第 5 章 Prompt Engineering——与大模型高效沟通
"同样的模型,不同的 Prompt,效果可能天差地别。"
上一章我们学会了如何调用大模型 API。但调用只是开始,怎么写 Prompt 才能得到好结果,这才是关键技能。
Prompt Engineering(提示工程)不是玄学,而是一套可学习、可复用的方法论。本章我们将系统学习:
- 基础技巧:Zero-shot、Few-shot、角色设定
- 进阶技巧:思维链(CoT)、ReAct、自我反思
- 结构化输出:让模型按你的格式返回
- 工程化实践:Prompt 版本管理、A/B 测试
5.1 Prompt 是什么?为什么写法不同效果差异这么大?
5.1.1 Prompt 的本质
Prompt 是你发给大模型的指令和上下文。模型根据 Prompt 来理解你的意图,并生成相应的回复。
同样的任务,不同的 Prompt,结果可能完全不同:
不好的 Prompt:
分析这段代码
好的 Prompt:
你是一位资深的 Java 架构师,拥有 10 年代码审查经验。
请分析下面的代码,重点关注:
1. 潜在的性能问题
2. 线程安全隐患
3. 资源泄漏风险
对于每个发现的问题,请说明:
- 问题所在行号
- 具体问题描述
- 修复建议代码
代码:
[代码贴在这里]
后者给出的结果会详细得多、有用得多。
5.1.2 为什么 Prompt 这么重要
大模型没有真正的"理解"能力,它只是在根据概率预测最可能的下一个词。Prompt 的作用是给模型提供足够的上下文和约束,引导它生成你想要的内容。
对后端开发者的类比:
Prompt 就像SQL 查询语句——
- 写得好:精准命中索引,毫秒级返回结果
- 写得差:全表扫描,几秒都出不来结果
- 同样的数据库(模型),不同的查询(Prompt),性能天差地别
5.2 基础技巧:Zero-shot、Few-shot、角色扮演
5.2.1 Zero-shot(零样本)
直接描述任务,不给示例。适合简单、明确的任务。
将以下中文翻译成英文:
你好,世界
优点:简单直接,无需准备示例 缺点:复杂任务可能效果不佳
5.2.2 Few-shot(少样本)
给 1-5 个示例,让模型"照猫画虎"。
请将情感分类为正面、负面或中性。
示例 1:
文本:这家餐厅的食物太棒了!
情感:正面
示例 2:
文本:等了一个小时,服务态度很差
情感:负面
示例 3:
文本:今天天气晴朗
情感:中性
待分类:
文本:物流很快,但包装有点破损
情感:
模型会输出:负面(或 混合,取决于你的示例设计)
Few-shot 的关键:
- 示例要覆盖各种情况
- 示例格式要统一
- 示例质量要高(错误的示例会教坏模型)
5.2.3 角色扮演(Role-playing)
给模型设定一个角色,让它以该角色的视角和能力来回答。
你是一位经验丰富的 MySQL DBA,擅长数据库性能优化。
用户问:我的查询很慢,怎么优化?
请先询问必要的上下文信息(表结构、数据量、查询语句),
然后再给出优化建议。
角色设定的作用:
- 激活模型在特定领域的知识
- 约束回答的风格和深度
- 提高回答的专业性和一致性
📌 插图 5-1:基础 Prompt 技巧对比
Zero-shot(零样本): 用户 ──► "翻译:你好" ──► 模型 ──► "Hello" Few-shot(少样本): 用户 ──► "示例1...示例2...示例3...待分类:..." ──► 模型 ──► 结果 ↑ 提供示例,让模型学习模式 角色扮演: 用户 ──► "你是一位专家...用户问题:..." ──► 模型 ──► 专业回答 ↑ 设定角色,激活领域知识
5.3 进阶技巧:思维链(CoT)、ReAct、自我反思
5.3.1 思维链(Chain-of-Thought, CoT)
对于需要推理的任务,让模型一步步思考,而不是直接给答案。
不用 CoT:
问题:一个农场有鸡和兔,头共 35 个,脚共 94 只。鸡兔各几只?
答案:
模型可能直接猜一个答案,容易错。
使用 CoT:
问题:一个农场有鸡和兔,头共 35 个,脚共 94 只。鸡兔各几只?
请一步步思考:
1. 设鸡有 x 只,兔有 y 只
2. 根据头的数量:x + y = 35
3. 根据脚的数量:2x + 4y = 94
4. ...
答案:
模型会展示推理过程,最终答案更准确。
自动 CoT:在 Prompt 末尾加一句"Let's think step by step",就能触发模型的推理模式。
5.3.2 ReAct(Reasoning + Acting)
ReAct 是 CoT 的扩展,把推理和行动结合起来。模型不仅思考,还可以决定调用工具。
你是一位智能助手,可以使用以下工具:
- search(query): 搜索信息
- calculator(expression): 计算表达式
请按以下格式回答:
Thought: 你的思考过程
Action: 工具名称(参数)
Observation: 工具返回的结果
...(重复 Thought-Action-Observation 直到得出结论)
Thought: 最终结论
Answer: 最终答案
用户问题:2024年诺贝尔奖物理学奖得主是谁?他/她出生在哪个国家?
模型可能的执行过程:
Thought: 我需要搜索 2024 年诺贝尔物理学奖得主的信息
Action: search("2024 Nobel Prize Physics winner")
Observation: 2024年诺贝尔物理学奖授予约翰·霍普菲尔德和杰弗里·辛顿...
Thought: 现在我需要查询杰弗里·辛顿的出生地
Action: search("Geoffrey Hinton birthplace")
Observation: 杰弗里·辛顿出生于英国伦敦...
Thought: 我已经获得了所有需要的信息
Answer: 2024年诺贝尔物理学奖得主之一是杰弗里·辛顿,他出生于英国。
5.3.3 自我反思(Self-Reflection)
让模型检查自己的回答,发现并修正错误。
请回答以下问题,然后检查你的答案:
问题:Python 中列表和元组有什么区别?
回答:[模型生成初始回答]
检查:
1. 我的回答是否准确?
2. 是否有遗漏的重要区别?
3. 举例是否恰当?
修正后的回答:
自我反思能显著提高回答质量,特别适合事实性问题和代码审查。
5.4 System Prompt 的作用:给模型定角色、规则和输出格式
5.4.1 System Prompt 的最佳实践
System Prompt 是对话的全局设定,应该包含:
- 角色定义:你是谁,有什么专业背景
- 任务描述:你的主要职责是什么
- 约束条件:什么能做,什么不能做
- 输出格式:回复应该遵循什么格式
system_prompt = """你是一位专业的技术文档撰写助手。
【角色】
- 你拥有 10 年技术写作经验
- 擅长将复杂技术概念转化为易懂的中文文档
【任务】
- 根据提供的技术信息,撰写清晰的用户文档
- 确保文档结构完整,包含:概述、步骤、示例、注意事项
【约束】
- 使用中文撰写
- 避免使用过于专业的术语,必要时提供解释
- 不要编造信息,不确定的内容标注"[待确认]"
【输出格式】
## 概述
...
## 操作步骤
1. ...
2. ...
## 示例
...
## 注意事项
- ...
"""
5.4.2 System Prompt vs User Prompt 的分工
| 内容 | 放在哪里 | 原因 |
|---|---|---|
| 全局角色设定 | System | 影响整个对话 |
| 固定的格式要求 | System | 每次回复都要遵循 |
| 具体任务描述 | User | 每次任务不同 |
| 需要处理的数据 | User | 动态变化 |
5.5 结构化输出:让模型返回 JSON / Markdown / 固定模板
5.5.1 为什么要结构化输出
非结构化文本难以解析,结构化输出可以直接用于程序处理。
5.5.2 JSON 输出
system_prompt = """你是一个信息提取助手。
请从用户输入中提取以下信息,并以 JSON 格式返回:
{
"name": "姓名",
"date": "日期(YYYY-MM-DD格式)",
"amount": "金额(数字)",
"items": ["物品1", "物品2"]
}
只返回 JSON,不要其他内容。"""
user_prompt = "张三在 2024 年 3 月 15 日购买了笔记本电脑和鼠标,共花费 5999 元。"
5.5.3 Markdown 表格输出
请对比以下三种数据库,并以 Markdown 表格形式输出:
对比维度:性能、一致性、扩展性、适用场景
数据库:MySQL、PostgreSQL、MongoDB
5.5.4 固定模板输出
请按以下模板生成代码审查报告:
## 审查概览
- 审查文件:{文件名}
- 问题总数:{数量}
- 风险等级:{高/中/低}
## 详细问题
### 问题 1:[类型] - [严重程度]
- 位置:{行号}
- 描述:{问题描述}
- 建议:{修复建议}
## 总结建议
{总结}
5.6 Prompt 的版本管理与工程化实践
5.6.1 为什么需要版本管理
Prompt 也是代码,需要:
- 版本控制(Git)
- 变更记录
- A/B 测试
- 回滚机制
5.6.2 Prompt 管理方案
方案 1:代码中的常量
# prompts.py
class Prompts:
CODE_REVIEW = """你是一位代码审查专家..."""
TRANSLATION = """你是一位专业翻译..."""
方案 2:配置文件
# prompts.yaml
code_review:
version: "1.2.0"
system: "你是一位代码审查专家..."
temperature: 0.2
translation:
version: "2.0.0"
system: "你是一位专业翻译..."
temperature: 0.5
方案 3:数据库 + 管理后台
适合大型团队,支持:
- 在线编辑 Prompt
- 版本历史
- 灰度发布
- 效果监控
5.6.3 Prompt A/B 测试
import random
def get_prompt_version(experiment_id: str) -> str:
"""根据实验 ID 决定使用哪个版本的 Prompt"""
if experiment_id in experiment_group_a:
return "v1" # 对照组
else:
return "v2" # 实验组
# 记录结果用于分析
log_experiment_result(experiment_id, prompt_version, user_satisfaction_score)
5.7 常见 Prompt 反模式与避坑指南
5.7.1 常见错误
| 反模式 | 示例 | 问题 | 修正 |
|---|---|---|---|
| 过于模糊 | "分析一下" | 模型不知道分析什么 | 明确分析维度和输出格式 |
| 要求矛盾 | "详细但简洁" | 模型无所适从 | 明确优先级或分步骤 |
| 示例错误 | 给错误的 Few-shot 示例 | 模型学到错误模式 | 确保示例质量 |
| 过度约束 | 限制太多导致无法回答 | 模型放弃或胡编 | 平衡约束和灵活性 |
| 忽略边界 | 没处理"我不知道"的情况 | 模型可能幻觉 | 明确允许拒绝回答 |
5.7.2 Prompt 优化检查清单
- 角色是否明确?
- 任务描述是否清晰?
- 输出格式是否定义?
- 约束条件是否合理?
- 是否提供了足够的上下文?
- 是否处理了边界情况?
- 示例是否覆盖各种场景?
本章小结
Prompt Engineering 是与大模型高效沟通的核心技能:
-
基础技巧:Zero-shot 简单直接,Few-shot 提供示例,角色扮演激活领域知识
-
进阶技巧:CoT 让模型一步步推理,ReAct 结合推理和行动,自我反思提高准确性
-
System Prompt:定义全局角色、任务、约束、格式,是 Prompt 工程的基石
-
结构化输出:JSON/Markdown/模板,让模型输出可直接用于程序处理
-
工程化:Prompt 需要版本管理、A/B 测试、灰度发布,像管理代码一样管理 Prompt
-
避坑:避免模糊、矛盾、错误示例、过度约束,使用检查清单确保 Prompt 质量
思考题
-
你正在开发一个 SQL 生成助手,用户用自然语言描述查询需求。设计一个 Prompt,让模型生成正确、安全的 SQL。
-
假设你的客服机器人之前用简单的 Prompt,现在想升级到 Few-shot + CoT。如何设计实验来验证新 Prompt 的效果?
-
你的团队有 5 个不同的 Prompt,分别用于代码审查、文档生成、测试用例生成、Bug 分析、性能优化建议。设计一个 Prompt 管理方案,支持版本控制和 A/B 测试。
下一章预告:Prompt 写好了,但怎么管理对话历史?怎么处理长文本超出上下文窗口?第 6 章,上下文工程——让你的大模型应用能处理复杂的多轮对话和长文档。