一、引言
Prompt 工程(Prompt Engineering),又称上下文提示工程(In-Context Prompting),指的是在不更新模型权重的前提下,通过设计高质量提示词来引导大语言模型(LLM)生成期望输出的方法。它是一门实验性科学,同样的提示技巧在不同模型上的效果可能差异很大,需要大量的测试和调优。
核心目标有两个:对齐(Alignment) 和 可控性(Steerability)。对齐是指让模型的输出符合人类意图;可控性是指让模型按照指定的方向和方式生成内容。
"LLM 是一个预测引擎——它根据训练数据预测下一个 token 应该是什麼。Prompt 工程就是设计高质量提示来指导这个预测过程。" —— Google Prompt Engineering Guide
二、LLM 输出配置
2.1 Temperature
Temperature 控制 token 选择中的随机程度:
- 低 temperature(接近 0):适合分类、提取、翻译等需要确定性响应的任务,始终选择概率最高的 token
- 高 temperature:适合写作、头脑风暴等需要创意输出的任务,增加输出的多样性
temperature 设为 0 时,模型使用贪婪解码,是确定性的。如果两个 token 具有相同的最高概率,实际选择可能因实现方式而异。
2.2 Top-K 和 Top-P
Top-K 和 Top-P(nucleus sampling)是两种采样设置,用于限制候选 token 的范围:
- Top-K:从模型的预测分布中选择前 K 个最可能的 token。K 值越低,输出越保守;K=1 等同于贪婪解码
- Top-P:选择累积概率不超过 P 的 top token。P 范围从 0(贪婪解码)到 1(所有 token)
2.3 实用配置参考
| 场景 | Temperature | Top-P | Top-K |
|---|---|---|---|
| 通用起点 | 0.2 | 0.95 | 30 |
| 创意任务 | 0.9 | 0.99 | 40 |
| 精确任务 | 0.1 | 0.9 | 20 |
| 数学/唯一答案 | 0 | N/A | N/A |
过高的自由度(高 temperature、Top-K、Top-P)可能导致"重复循环错误"——模型陷入循环,重复生成相同的词或短语。
三、基础提示技术
3.1 零样本提示
直接提供任务描述,让模型处理:
文本:我今天很开心。
情感分类:
零样本提示适合简单任务,对复杂任务往往不够。
3.2 少样本提示
通过提供示例帮助模型理解任务要求和期望的输出格式:
文本:这个电影太无聊了。
情感:负面
文本:演员表演很出色!
情感:正面
文本:一般般吧。
情感:
模型先看到高质量示例,能更好地理解人类意图和答案标准。
经验法则:n ≥ 5。不要害怕使用几十个示例,但要注意上下文长度限制。
3.3 示例选择与排序
少样本学习存在多种偏置(Zhao et al., 2021):
- 多数标签偏置:示例中某类标签过多时,模型倾向于重复该标签
- 近期偏置:模型可能重复末尾示例的标签
- 常见 token 偏置:模型更频繁地生成常见 token
选择原则:示例应与测试样本语义相似(使用 k-NN 聚类选择),选择多样化且有代表性的示例,包含边缘情况以提高鲁棒性。
排序原则:保持多样化、随机顺序,避免按标签分组,不同模型可能偏好不同的排序。
3.4 指令提示
直接描述任务要求,避免依赖示例:
请将这段文本分类。分类标签应为"正面"或"负面"。
文本:我今天很开心。
情感:
具体明确地描述要做什么,而不是描述不要做什么。描述目标受众(如"用6岁孩子能理解的语言解释")和指定输出格式(如"仅返回标签,全大写")都能提升效果。
四、结构化提示技巧
4.1 系统提示、上下文提示与角色提示
三种不同维度的提示技术,可以组合使用:
| 类型 | 作用 | 特点 |
|---|---|---|
| 系统提示 | 设置整体上下文和目标 | 定义模型的基本能力 |
| 上下文提示 | 提供当前任务的具体信息 | 动态、特定于当前输入 |
| 角色提示 | 分配角色或身份 | 构建输出风格和声音 |
示例:
系统提示:
你是一个专业的代码审查员。你的职责是发现代码中的潜在 bug、安全漏洞和性能问题。
角色提示:
请用旅行指南的风格,为我推荐阿姆斯特丹值得游览的博物馆。
上下文提示:
上下文:你正在为一个关于80年代复古街机游戏的博客撰写文章。
请推荐3个可以写成文章的主题。
4.2 退后提示(Take a Step Back)
先让模型考虑更一般性的问题,激活相关背景知识,再回到具体任务:
传统提示:
写一个第一人称射击游戏关卡的故事情节。
退后提示(第一步):
基于流行射击游戏,列出5个让关卡故事情节引人入胜的关键设定。
退后提示(第二步):
基于以上设定,选择一个,写一段引人入胜的关卡故事情节。
4.3 结构化输入与输出
不同模型家族偏好不同的格式:Claude 偏好 XML,GPT 偏好 Markdown 和 JSON。
结构化输出的优势:
{
"sentiment": "POSITIVE",
"confidence": 0.95,
"keywords": ["开心", "精彩", "推荐"]
}
- 强制模型创建结构,减少幻觉
- 便于解析和下游处理
- 保持输出格式一致
- 提供数据类型信息
JSON Schema 可用于定义输入格式,帮助模型理解数据结构。
五、链式思考(Chain of Thought, CoT)
通过生成中间推理步骤来提高 LLM 推理能力的技术。
普通提示在复杂推理任务上表现不佳:
提示:我3岁时,我的伴侣年龄是我的3倍。现在我20岁了。伴侣几岁?
普通输出:63岁 ❌(错误)
5.1 零样本 CoT
添加"让我们一步步思考":
提示:我3岁时,我的伴侣年龄是我的3倍。现在我20岁了。伴侣几岁?让我们一步步思考。
CoT输出:
1. 当我3岁时,伴侣是3×3=9岁
2. 年龄差是9-3=6岁
3. 现在我20岁,伴侣是20+6=26岁
答案:26岁 ✅(正确)
5.2 少样本 CoT
提供完整推理链示例:
问题:小明5岁时,他哥哥的年龄是他的2倍。现在小明15岁了,他哥哥几岁?
答案:
当小明5岁时,他哥哥是5×2=10岁。
年龄差是10-5=5岁。
现在小明15岁,他哥哥是15+5=20岁。
答案是20岁。
问题:我3岁时,伴侣年龄是我的3倍。现在我20岁了。伴侣几岁?
答案:
5.3 CoT 最佳实践
- 温度设为 0:CoT 基于贪婪解码推理,只有一个正确答案
- 使用换行符分隔推理步骤:比序号或分号更有效
- 在推理之后放置答案
- 复杂推理示例对复杂问题有效,对简单问题可能适得其反
5.4 自洽性(Self-Consistency)
多次采样配合多数投票,提高推理准确性:
- 使用 temperature > 0 生成多个不同推理路径
- 从每个响应中提取最终答案
- 选择出现最频繁的答案
在 GSM8K 数学基准上,自洽性将准确率从 34% 提升到 47%。
六、进阶提示技术
6.1 思维树(Tree of Thoughts, ToT)
在每个步骤探索多个推理可能,形成树结构:
问题:如何优化电商网站的转化率?
思维分支1(定价策略)
→ 分支1.1:动态定价
→ 分支1.2:会员折扣
思维分支2(用户体验)
→ 分支2.1:简化结账流程
→ 分支2.2:个性化推荐
思维分支3(营销策略)
→ 分支3.1:社交媒体广告
→ 分支3.2:邮件营销
适合需要探索和规划复杂任务。搜索可以使用 BFS 或 DFS,每个状态通过多数投票或分类器评估。
6.2 ReAct(推理 + 行动)
让 LLM 结合外部工具(搜索、代码执行)来解决问题:
from langchain.agents import load_tools, initialize_agent, AgentType
from langchain.llms import VertexAI
llm = VertexAI(temperature=0.1)
tools = load_tools(["serpapi"], llm=llm)
agent = initialize_agent(
tools, llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION
)
agent.run("Metallica乐队成员一共有多少个孩子?")
ReAct 通过"思考-行动-观察"循环工作:
- 推理:理解问题,制定计划
- 行动:执行搜索或其他工具调用
- 观察:获取结果,更新推理
- 重复:直到找到解决方案
6.3 Program-Aided Language Models (PAL/PoT)
让 LLM 生成程序代码来执行推理,而不是依赖模型自身的计算:
问题:计算 (3 + 5) × 2 - 4
代码:result = (3 + 5) * 2 - 4
执行:result = 16 - 4 = 12
答案:12
适合需要精确数学计算的任务。
七、提示自动化
7.1 APE(自动提示工程)
让 LLM 自动生成和优化提示:
- 生成候选:让 LLM 基于示例生成多个提示变体
- 评估:根据指定指标(如准确率、BLEU)评估
- 选择:选择得分最高的候选提示
- 迭代:可进一步优化选中的提示
7.2 自动 CoT
augment-prune-select 三步法:
- Augment:使用少样本或零样本 CoT 生成多个推理链
- Prune:剪枝,保留答案正确的推理链
- Select:使用策略梯度选择最佳示例
八,生产环境最佳实践
8.1 小而专注的提示
避免"God Object"提示——一个提示做所有事情。复杂任务应分解为多个简单提示。GoDaddy 将其列为使用 LLM 的第一大教训。
反例(单一复杂提示):
"总结这个会议纪要,包括关键决策、行动项、负责人,并检查一致性..."
正例(分解为多个提示):
提示1:提取关键决策、行动项和负责人 → 结构化输出
提示2:检查提取内容与原文的一致性 → 是/否 + 说明
提示3:基于结构化内容生成简洁摘要
每个提示简单、专注、易于测试和迭代。
8.2 精心设计上下文
上下文如同雕塑——不要堆积材料,而要像米开朗基罗一样雕刻:
- 削减冗余:移除无关信息
- 结构化:用有意义的组织方式呈现上下文
- 一致性:确保上下文内部不自相矛盾
- 格式清晰:便于模型提取关键信息
8.3 多步工作流
分解任务为多步流程可获得显著提升。AlphaCodium 从单提示 19% 准确率提升到多步工作流 44%(GPT-4):
- 反思问题
- 在公开测试上推理
- 生成可能解
- 排名可能解
- 生成合成测试
- 在测试上迭代
8.4 优先确定性工作流
AI Agent 可以动态响应,但非确定性使其难以部署。每增加一步,失败概率指数增长。
建议使用确定性计划执行,而非动态 Agent 响应:
- Agent 生成计划
- 按结构化、可重现方式执行计划
- 每步可预测、可测试
8.5 模型选择
不要忽视小模型。Haiku + 10-shot 可能匹敌 Opus 零样本,DistilBERT(67M 参数)在分类任务上是强 baseline。小模型配合技巧可以匹敌甚至超越大模型。选择能完成任务的最小模型,降低延迟和成本。
九、评估与监控
9.1 基于断言的单元测试
从生产输入/输出样本创建断言测试:
def test_summarization():
assert len(summary) < 200 # 长度检查
assert "关键决策" in summary # 关键词检查
assert summary.flesch_reading_ease > 60 # 可读性检查
触发条件:任何管道修改(提示编辑、上下文变化等)
9.2 LLM-as-Judge
用强模型评估其他模型输出:
- 使用成对比较而非单独评分
- 控制位置偏置(交换顺序两次评估)
- 允许平局
- 使用 CoT 让评估更可靠
- 控制响应长度以减少偏置
9.3 "实习生测试"
自问:如果把这个任务给相关专业的普通大学生,他能完成吗?
- 不能(缺乏知识)→ 丰富上下文
- 不能(任务太难)→ 分解任务或templatize
- 能,很快 → 检查数据,分析模型错误模式
9.4 幻觉问题
幻觉基线率约 5-10%,很难降到 2% 以下。
应对策略:
- 上游:CoT 提示让模型解释推理过程
- 下游:事实不一致检测 guardrails
- RAG:如果输出引用了检索文档,应能溯源到输入上下文
十、总结
基础技巧:零样本和少样本提示、指令提示、系统/上下文/角色提示
进阶技巧:链式思考(CoT)和自洽性、思维树(ToT)和 ReAct、结构化输入/输出
生产实践:小而专注的提示、多步工作流、确定性优先、选择合适模型
关键原则:提供多样化高质量示例、使用具体指令而非约束、记录所有提示尝试、不断实验和迭代、适应模型更新