Prompt Engineering 的本质:你不是在写咒语,你是在压缩上下文
AI 系列第 12 篇。我们终于到了"怎么用 LLM"这一段。第一站:prompt engineering。 这一篇会颠覆几个常见误解。
0. 一个让我尴尬的事
我刚开始用 GPT-3 时,写过这种 prompt:
"你是一个聪明、专业、详细、清晰、负责任、有耐心、富有同理心、
经验丰富、知识渊博、敏锐、谦虚、严谨、可靠的助手。请..."
我以为给模型加这么多形容词能让它表现更好。
后来我发现一个事实——这些形容词几乎对输出没影响。模型不会因为你说"专业"就突然变得更专业。它只是把你的 prompt 当作上下文,然后预测下一个 token。
prompt engineering 不是给模型"打鸡血"。它是别的东西。这篇我们讲清楚是什么。
1. 一句话定义:prompt 是给模型的"上下文压缩包"
LLM 没有记忆(这里指无状态调用)。每次推理它只能看到你给的 prompt。所以:
prompt 的核心任务,是在有限的 token 预算内,给模型足够多的上下文来完成任务。
这就是为什么我说 prompt engineering 是"上下文压缩"。它不是修辞,不是 magic words,不是 incantation。它是:
- 什么信息必须在 context 里?
- 怎么排列让模型最容易抓取?
- 怎么省 token?
2. Prompt 不是什么(破除幻觉)
误解 1:加形容词让模型变强
❌ "请认真、详细、专业地回答。"
✅ "回答的每一步都要给出依据。"
形容词没用。给具体规则才有用。
误解 2:威胁/利诱有效
❌ "如果你回答不准确,我会很生气。"
❌ "回答好我给你 200 美元小费。"
研究显示:早期模型对这类语言确实有反应。但现代对齐过的模型基本无视。别学网上那些 viral tweets。
误解 3:长 prompt = 好 prompt
❌ 写一个 2000 字的 system prompt,啥都说。
长 prompt 有三个问题:
- 模型注意力分散(参考第 10 篇的 lost in the middle)
- token 成本高
- 信息互相打架的概率上升
简洁、聚焦、有结构的 200 字 prompt 通常胜过 2000 字。
误解 4:每个模型用法一样
GPT-4o、Claude、Gemini、Llama 各家的 prompt 风格略有不同。例如:
- Claude 喜欢 XML 标签(
<example>...</example>) - GPT 喜欢 markdown 标题(
## 任务) - 中文模型对中文 prompt 反应更好
换模型时不要直接搬 prompt,要做轻量重写。
3. Prompt 真正在做什么:信息论的视角
一个 prompt 让模型完成任务的关键,是减少模型的不确定性。
模型先验: "用户问的可能是 100 种任务中的任意一种。"
看 prompt: "哦,是要写代码。具体是 Python,要求处理 CSV,
还要符合 PEP 8,错误处理用 try-except。"
每个具体描述都减少了一些不确定性。当不确定性降到足够低,模型就能"对症下药"。
三类有效信息
信息 1:任务定义
"把以下英文翻译成中文。"
"分析这段代码的复杂度。"
"判断这是垃圾邮件吗?"
任务越具体,模型越省力。"翻译" 模糊;"逐句翻译,保留原文标点" 具体。
信息 2:上下文 / 角色
"你是一个 Python 后端工程师,了解 FastAPI 和 SQLAlchemy。"
这不是"打鸡血",是激活相关知识。模型训练数据里有大量"Python 工程师写的代码",这个角色描述让它的输出风格偏向那些数据。
信息 3:示例(few-shot)
"按这个格式:
输入: '我今天很开心'
输出: { sentiment: 'positive', confidence: 0.9 }
输入: '今天真倒霉'
输出: { sentiment: 'negative', confidence: 0.85 }
输入: '今天天气不错' →"
few-shot 是 prompt engineering 最强的武器之一。它让模型直接从例子里学格式 + 风格 + 边界情况。
信息论的 takeaway
写好 prompt = 在最少 token 内传递最多任务相关信息。
4. 几个真正有效的模板
模板 1:分块式 prompt
# 任务
[一句话描述任务]
# 上下文
[必要的背景信息]
# 输入
[实际的输入数据]
# 输出格式
[期望的输出结构,最好带例子]
# 约束
[必须满足的规则]
这个模板的精髓是 结构化。模型对 markdown / XML 标签敏感,明确的分块比一团 prose 好。
模板 2:role + task + format
你是 [角色]。
你的任务是 [任务]。
请用 [格式] 输出。
[输入]
适合简单任务。够用。
模板 3:CoT 引导
[问题]
请先:
1. 列出涉及的概念
2. 分析每个概念之间的关系
3. 推导出结论
4. 给出最终答案
最终答案放在 <answer></answer> 标签里。
适合复杂推理。把"思考步骤"显式写出来。
模板 4:few-shot + 思维链
Q: [简单例子的问题]
A: [示范推理]
最终答案: [示范答案]
Q: [简单例子 2]
A: [示范推理 2]
最终答案: [示范答案 2]
Q: [真实问题]
A:
模型会模仿例子的推理风格。比单纯 zero-shot CoT 强很多。
5. 一些"被低估"的小技巧
技巧 1:指定"如果不知道"
"如果你不确定,请回答 '不知道' 而不是猜测。"
显著降低幻觉率。
技巧 2:要求"先想再说"
"请先用 <thinking>...</thinking> 标签思考,再给最终答案。"
不是 reasoning model 也能用,效果接近 CoT。
技巧 3:让模型自我审查
"先生成答案,然后检查这个答案是否:
1. 符合要求
2. 内部自洽
3. 有支撑证据
如有问题,请修正。"
适合关键任务。两轮自洽明显比单轮稳。
技巧 4:负面示例
"不要这样写: ❌ 模糊的描述 / 无具体步骤 / 没有代码"
"要这样写: ✅ 明确步骤 + 可运行代码"
明确说"不要"比只说"要"更有效。
技巧 5:把约束放在最后
[长长的任务描述]
...
重要:必须用 JSON 输出,不要加任何 markdown 标记。
研究显示模型对 最后看到的指令 更敏感(recency bias)。关键约束放末尾。
6. 反模式(看到就要警觉)
反模式 1:互相矛盾的指令
"请详细回答" + "回答要简短" → 模型懵逼
反模式 2:模糊代词
"分析它的性能" ← "它"指什么?
"修复这个 bug" ← 哪个 bug?
反模式 3:太多 system prompt
system: 2000 字的角色 + 规则 + 例子
user: "你好"
system prompt 过载后模型容易忘 user 问的是啥。
反模式 4:示例和任务不一致
few-shot 都是分类任务,最后突然问个生成任务 → 模型混乱
反模式 5:用 prompt 强行做 LLM 不擅长的事
"请精确计算 1234567 × 7654321 的结果。"
LLM 算术天生不准。这种任务应该让它调用计算器工具(下一篇 RAG,下下篇 tool use 会讲)。
7. 你写 prompt 的实际流程应该是什么样
1. 一句话描述任务,跑一次。
2. 观察输出,记下错误模式(格式错?事实错?风格不对?)
3. 针对错误模式加一句具体指令。
4. 再跑。
5. 重复 2-4 直到稳定。
不要一上来就写 2000 字。从 50 字开始,按需加。
Anthropic 内部有句话:
"Prompt engineering 是迭代过程,不是设计过程。"
8. 给你的小作业
- 挑一个你日常用 LLM 做的任务,把当前 prompt 写下来。然后用今天的模板重写。对比两版输出。
- 写一个 prompt 让 GPT 把任意自然语言描述转成 SQL。试试 zero-shot vs few-shot 哪个更好。
- 如果一个 prompt 在 GPT-4 上 work,在 Claude 上不 work,你会怎么排查?给三个步骤。
下一篇钩子:prompt engineering 的本质是 "压缩上下文"。 但有些上下文太大,没法压缩——例如你公司 10 万份文档。 这时你需要给模型外挂一个"知识硬盘"——这就是 RAG。 下一篇我们讲 RAG 的完整流水线,并打破"向量搜索一招吃天下"这个常见错觉。