🤖 吴恩达亲授:如何用Prompt工程让大模型“靠谱”地为你工作?
告别“随机输出”,像写代码一样精确控制LLM
在AI应用开发的浪潮中,大语言模型(LLM)展现了惊人的理解与生成能力。但很多开发者都遇到过这样的困扰:同样的Prompt,有时输出完美,有时却答非所问;有时返回优美的JSON,有时却夹杂着废话;甚至还会一本正经地编造事实……
吴恩达(Andrew Ng)在多次演讲和课程中反复强调:要让LLM成为“靠谱”的工程师伙伴,而不是一个随性的诗人。这就需要我们掌握一套系统化的Prompt工程原则——它不仅是写几句话,而是像编程一样,通过清晰性、结构化、约束和示例来减少随机性。
本文将基于吴恩达的核心思想,深入讲解如何设计高质量Prompt、封装API调用函数、以及实战中应对“幻觉”等棘手问题。无论你是新手还是进阶玩家,都能从中获得可落地的技巧。
📌 目录
- Prompt工程的三个核心原则
get_response:封装LLM API的艺术- 四大实战规则:让输出更确定
- 3.1 清晰且具体的表达
- 3.2 强制输出JSON并丰富语义
- 3.3 分布式提示(分解复杂任务)
- 3.4 Few-shot:给模型“抄作业”的机会
- 直面幻觉:原因与缓解策略
- 完整案例:从模糊到可靠的Prompt进化
- 总结与推荐资源
1. Prompt工程的三个核心原则
吴恩达将Prompt设计总结为三个层次:
| 原则 | 说明 |
|---|---|
| 清晰且详细的指令 | 不要只告诉模型“做什么”,还要说明“怎么做”和“不要做” |
| 约束返回结构 | 要求模型输出JSON/XML等结构化数据,便于程序解析 |
| 五个构建块 | 指令 + 上下文 + 输入数据 + 输出格式 + 示例 |
💡 记住:LLM不是读心者。你越是含糊,它就越可能“自由发挥”。
2. get_response:封装LLM API的艺术
在实际开发中,我们通常不会每次都裸调API,而是封装一个get_response函数。这样做的好处:
- 复用默认参数:比如
temperature=0.2、max_tokens=1000 - 统一异常处理:处理限流、超时等
- 支持不同接口:
completions(老式补全)和chat.completions(推荐)
2.1 简单封装示例(伪代码)
def get_response(prompt, system_msg="你是一个有用的AI助手", temperature=0.3):
response = openai.ChatCompletion.create(
model="gpt-4",
messages=[
{"role": "system", "content": system_msg},
{"role": "user", "content": prompt}
],
temperature=temperature,
max_tokens=800
)
return response.choices[0].message.content
2.2 两种API的区别
| 接口 | 特点 | 何时使用 |
|---|---|---|
completions | 输入单个prompt字符串,返回续写 | 简单生成任务(如写诗、翻译单句) |
chat.completions | 输入messages数组,支持多角色对话 | 99%的现代应用(尤其是需要系统指令的) |
messages结构示例:
[
{"role": "system", "content": "你是一个严格的数据分析师,只回答数值型事实,不编造数据。"},
{"role": "user", "content": "2024年全球AI融资总额是多少?"},
{"role": "assistant", "content": "根据Crunchbase数据,约为500亿美元。"}
]
🔔 小技巧:
system消息是最强大的控制开关。你可以在这里设置角色、语气、安全边界,甚至禁止模型说“我不知道”。
3. 四大实战规则:让输出更确定
吴恩达提出了四条黄金规则,下面一一拆解。
3.1 清晰且具体的表达
错误示例:
“总结这篇文章。”
(模型不知道长度、风格、侧重点)
正确示例:
请用三句话总结下面的文本,每句话不超过20个字,聚焦于技术难点,忽略背景介绍。
文本:{文章内容}
关键技巧:使用分隔符
用三个反引号```、"""或<tag>将原始数据与指令隔开,可以显著降低模型混淆。这是经过了数百次实验验证的有效手段。
请将以下客户评价的情感分类为【正面/负面/中性】,并输出JSON。
---
评价:```这个产品很好,但物流太慢了。```
3.2 强制输出JSON并丰富语义
结构化输出是LLM接入工程系统的前提。我们不仅要要求JSON,还可以通过在字段后添加注释(自然语言描述) 来进一步约束模型。
基础要求:
{"summary": "...", "score": 0.8}
进阶要求(带语义约束):
{
"summary": "// 20字以内,一句话总结",
"confidence": "// 0~1之间的浮点数,表示模型对自己的回答有多确信",
"keywords": "// 数组,最多3个关键词"
}
⚠️ 注意:某些模型会忽略注释,所以最好在指令中明确:“字段后的
//内容仅为说明,不要输出//符号”。
3.3 分布式提示:拆解复杂任务
不要让LLM一次完成太多事。例如“分析合同 → 提取条款 → 判断合规性 → 生成报告”四个步骤,最好分成四次调用。
优点:
- 每个子任务错误率更低
- 中间结果可缓存、可调试
- 可替换或升级单个环节的模型
案例:分析用户反馈
- 步骤1:提取关键实体(产品名、问题类型、情绪词)
- 步骤2:判断情绪强度(1-5分)
- 步骤3:生成改进建议
- 最终:合并为结构化报告
# 伪代码
entities = extract_entities(feedback) # 子Prompt 1
sentiment = score_sentiment(feedback) # 子Prompt 2
suggestions = generate_actions(entities, sentiment) # 子Prompt 3
report = merge(entities, sentiment, suggestions)
3.4 Few-shot:给模型“抄作业”的机会
Few-shot是指在Prompt中提供少量(通常是2~5个)输入-输出示例,让模型通过类比学习任务格式。它比零样本(zero-shot)要稳定得多,又比微调(fine-tuning)轻量得多。
零样本(效果一般):
将英文翻译成法文:
Hello
Few-shot(效果更好):
示例1:
英文:Good morning → 法文:Bonjour
示例2:
英文:Thank you → 法文:Merci
示例3:
英文:How are you? → 法文:Comment allez-vous?
现在请翻译:
英文:Nice to meet you → 法文:
🧠 原理:LLM在预训练时已经见过类似模式,Few-shot只是激活了正确的“工作记忆”。
4. 直面幻觉:原因与缓解策略
幻觉:模型生成了表面上流畅但事实上错误或杜撰的内容。例如问“谁是火星上第一个人类定居者”,模型可能回答“埃隆·马斯克于2029年建立了基地”——这完全是编造。
4.1 为什么会产生幻觉?
- 模型本质是概率生成器,没有真假判断的神经元
- 训练数据不完整或存在虚假信息
- 用户要求超出了模型知识截止日期
- 模型为了“取悦用户”强行给出答案
4.2 缓解幻觉的实战方法
| 策略 | 说明 | 示例指令 |
|---|---|---|
| 要求引用原文 | 让模型必须基于提供的上下文回答 | “仅根据以下文档回答,不要添加任何外部知识。如果答案不在文档中,输出‘不知道’。” |
| 启用低温度 | temperature=0 使输出确定性最高 | API参数设置 |
| 加入置信度评分 | 让模型输出对自己的答案有多确定 | “在JSON中添加confidence字段,取值0-1,1表示非常确信。” |
| 事后验证 | 用知识图谱或规则检查关键事实 | 写一段代码,检查模型输出的日期、名称是否存在 |
| 系统指令限制 | 明确禁止捏造 | system: “你是一个AI助手,严禁编造事实。如果不知道答案,直接说‘我无法确定’。” |
5. 完整案例:从模糊到可靠的Prompt进化
假设我们需要一个函数,输入任意产品的用户评论,输出情感分析和改进建议,且必须以JSON返回。
❌ 模糊版本(低质量)
分析:
{review}输出建议。
问题:格式随意,情感标签不统一,建议质量飘忽。
✅ 可靠版本(运用所有原则)
system_prompt = """
你是一个专业的产品分析AI。你的任务:
1. 必须严格输出以下JSON结构,不要输出任何其他文字。
2. 字段说明:
- sentiment: 只能是"positive", "neutral", "negative"之一
- confidence: 0~1之间的浮点数
- suggestions: 字符串数组,最多3条具体可操作的改进建议
- quoted_phrases: 从原文中摘录的关键短句数组(证明依据)
3. 如果用户评论少于5个词,设置sentiment为"neutral",confidence为0.2。
4. 绝不可以捏造建议,如果评论中没有明显问题,建议数组可以留空。
"""
user_prompt = """
请分析以下产品评论:
---
{review}
---
输出JSON:
"""
def analyze_review(review_text):
return get_response(
prompt=user_prompt.format(review=review_text),
system_msg=system_prompt,
temperature=0.1
)
示例输出:
{
"sentiment": "negative",
"confidence": 0.95,
"suggestions": ["加快物流速度", "增加包裹追踪通知"],
"quoted_phrases": ["物流太慢了", "等了一周"]
}
这个案例综合了分隔符、JSON约束、系统指令、低温度、Few-shot思路(虽然没有显式给示例,但通过字段描述模拟了示例效果)。
6. 总结与推荐资源
核心要点回顾
| 问题 | 解决方案 |
|---|---|
| 输出格式混乱 | 强制JSON + 字段注释 |
| 忽略上下文 | 用```分隔符包裹原始文本 |
| 复杂任务出错率高 | 分布式提示(拆分成子任务) |
| 模型不知道想要什么 | 提供2~5个Few-shot示例 |
| 幻觉编造事实 | 要求引用原文 + 低温度 + 事后验证 |
延伸学习
- 吴恩达《ChatGPT Prompt Engineering for Developers》(DeepLearning.ai免费课程)
- OpenAI官方Prompt指南(包括6大策略)
- LangChain:帮你结构化编排多步Prompt调用
最后,记住这句话:Prompt工程不是“与AI聊天”,而是一种面向任务的编程范式。当你把LLM看作一个可控的函数调用,而不是一个神秘的魔盒时,你就真正掌握了它。
如果你在实践中发现了更有趣的技巧,欢迎在评论区分享~ 🚀