一、引言

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 实用配置参考

场景TemperatureTop-PTop-K
通用起点0.20.9530
创意任务0.90.9940
精确任务0.10.920
数学/唯一答案0N/AN/A

过高的自由度(高 temperature、Top-K、Top-P)可能导致"重复循环错误"——模型陷入循环,重复生成相同的词或短语。


三、基础提示技术

3.1 零样本提示

直接提供任务描述,让模型处理:

文本:我今天很开心。
情感分类:

零样本提示适合简单任务,对复杂任务往往不够。

3.2 少样本提示

通过提供示例帮助模型理解任务要求和期望的输出格式:

文本:这个电影太无聊了。
情感:负面

文本:演员表演很出色!
情感:正面

文本:一般般吧。
情感:

模型先看到高质量示例,能更好地理解人类意图和答案标准。

经验法则:n ≥ 5。不要害怕使用几十个示例,但要注意上下文长度限制。

3.3 示例选择与排序

少样本学习存在多种偏置(Zhao et al., 2021):

  1. 多数标签偏置:示例中某类标签过多时,模型倾向于重复该标签
  2. 近期偏置:模型可能重复末尾示例的标签
  3. 常见 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 最佳实践

  1. 温度设为 0:CoT 基于贪婪解码推理,只有一个正确答案
  2. 使用换行符分隔推理步骤:比序号或分号更有效
  3. 在推理之后放置答案
  4. 复杂推理示例对复杂问题有效,对简单问题可能适得其反

5.4 自洽性(Self-Consistency)

多次采样配合多数投票,提高推理准确性:

  1. 使用 temperature > 0 生成多个不同推理路径
  2. 从每个响应中提取最终答案
  3. 选择出现最频繁的答案

在 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 通过"思考-行动-观察"循环工作:

  1. 推理:理解问题,制定计划
  2. 行动:执行搜索或其他工具调用
  3. 观察:获取结果,更新推理
  4. 重复:直到找到解决方案

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 自动生成和优化提示:

  1. 生成候选:让 LLM 基于示例生成多个提示变体
  2. 评估:根据指定指标(如准确率、BLEU)评估
  3. 选择:选择得分最高的候选提示
  4. 迭代:可进一步优化选中的提示

7.2 自动 CoT

augment-prune-select 三步法:

  1. Augment:使用少样本或零样本 CoT 生成多个推理链
  2. Prune:剪枝,保留答案正确的推理链
  3. Select:使用策略梯度选择最佳示例

八,生产环境最佳实践

8.1 小而专注的提示

避免"God Object"提示——一个提示做所有事情。复杂任务应分解为多个简单提示。GoDaddy 将其列为使用 LLM 的第一大教训。

反例(单一复杂提示):
"总结这个会议纪要,包括关键决策、行动项、负责人,并检查一致性..."

正例(分解为多个提示):
提示1:提取关键决策、行动项和负责人 → 结构化输出
提示2:检查提取内容与原文的一致性 → 是/否 + 说明
提示3:基于结构化内容生成简洁摘要

每个提示简单、专注、易于测试和迭代。

8.2 精心设计上下文

上下文如同雕塑——不要堆积材料,而要像米开朗基罗一样雕刻:

  1. 削减冗余:移除无关信息
  2. 结构化:用有意义的组织方式呈现上下文
  3. 一致性:确保上下文内部不自相矛盾
  4. 格式清晰:便于模型提取关键信息

8.3 多步工作流

分解任务为多步流程可获得显著提升。AlphaCodium 从单提示 19% 准确率提升到多步工作流 44%(GPT-4):

  1. 反思问题
  2. 在公开测试上推理
  3. 生成可能解
  4. 排名可能解
  5. 生成合成测试
  6. 在测试上迭代

8.4 优先确定性工作流

AI Agent 可以动态响应,但非确定性使其难以部署。每增加一步,失败概率指数增长。

建议使用确定性计划执行,而非动态 Agent 响应:

  1. Agent 生成计划
  2. 按结构化、可重现方式执行计划
  3. 每步可预测、可测试

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、结构化输入/输出

生产实践:小而专注的提示、多步工作流、确定性优先、选择合适模型

关键原则:提供多样化高质量示例、使用具体指令而非约束、记录所有提示尝试、不断实验和迭代、适应模型更新


参考资料