系列第 18 篇。主文档见 智能体上下文工程实现.md。
用 Opus 跑出来的高质量 agent 行为,能不能让 Haiku 也学会?复杂的 prompt + 工具集,能不能压缩成更简洁的形式?这一篇讲两类相关但不同的"蒸馏":模型蒸馏(让小模型模仿大模型)和上下文蒸馏(让短 prompt 复现长 prompt 的行为)。
0. 两种蒸馏
| 类型 | 输入 | 输出 | 目标 |
|---|---|---|---|
| 模型蒸馏 | 大模型的 (input, output) 对 | 小模型微调 | 小模型在该任务上表现接近大模型 |
| 上下文蒸馏 | 长 prompt + 行为示例 | 短 prompt | 短 prompt 复现同样行为 |
两者都是"压缩",但方向不同:模型蒸馏压模型容量,上下文蒸馏压prompt 长度。
agent 系统里两者都有用,但场景不同。
1. 模型蒸馏在 agent 上下文工程的位置
1.1 为什么要蒸馏
Opus 4.7 跑 agent 质量最高,但:
- 慢(参见 17 篇延迟曲线)
- 贵(每次推理几美分起)
- 容量大(不是所有任务都用得上)
如果 80% 的任务用 Haiku 也能搞定,蒸馏就有价值。
1.2 经典蒸馏 vs agent 蒸馏
经典 LLM 蒸馏(学术):
输入:1M 个 (prompt, gpt4_response) 对
训练:让小模型模仿
输出:小模型在该数据分布上表现接近大模型
agent 蒸馏(实战):
输入:1000 个 (用户请求, agent_轨迹) 对
其中 agent_轨迹 = [thinking, tool_use, tool_result, ...]
训练:让小模型生成同样的轨迹
输出:小模型能"模仿"大模型的工具调用决策、推理路径
差别:agent 蒸馏不只是"输出文本相似",而是整条轨迹相似 —— 包括用什么工具、什么顺序、什么参数。
1.3 数据收集策略
最常见的做法是用大模型"打工",生成训练数据:
# 用 Opus 跑 1000 个真实任务
for task in real_tasks:
trajectory = run_with_opus(task)
save(task, trajectory)
# 然后用这些 trajectory 微调 Haiku 或定制小模型
fine_tune_data = [(t.input, t.full_trajectory) for t in trajectories]
但要注意:
- 大模型也会犯错。需要人工或自动评估筛掉错误轨迹
- 不同任务难度不同,要分布合理
- 工具集要稳定(蒸馏期间不能改工具)
2. 蒸馏对上下文工程的影响
2.1 蒸馏让 prompt 变短成为可能
如果你的 agent 严重依赖一个 30k token 的 System Prompt 教模型"怎么做",蒸馏后小模型的权重里"内化"了这些规则,prompt 可以缩到 5k。
差别:
- 蒸馏前:每次请求带 30k System Prompt(cache 帮助但仍贵)
- 蒸馏后:每次请求带 5k,模型权重里有剩下的"知识"
这是 prompt 工程的极限优化路径之一。但代价大(蒸馏成本本身高)。
2.2 工具描述也能蒸馏
08 篇讲过工具描述占 prompt 60%。蒸馏后小模型可以:
- 工具描述压缩到 1/3(核心契约保留,nice-to-have 删掉)
- 工具命名约定通过训练而非描述传达
- 失败模式通过训练数据"被教会"
2.3 但蒸馏也丢东西
蒸馏出来的模型:
- 在训练分布上接近大模型
- 在分布外表现可能很差
- 失去通用性
如果 agent 要处理的任务多样,蒸馏后的模型可能在常见任务上接近 Opus,但遇到边缘任务直接崩。
3. 上下文蒸馏:不动模型,压 prompt
更轻量的方法:不微调模型,只压 prompt。
3.1 工作流
原始:长 System Prompt(30k)+ 工具描述(12k)+ ...
↓
用大模型对一组任务生成(task, behavior)对
↓
让大模型自己分析:哪些 prompt 内容真的影响了 behavior?
↓
迭代删除"低影响"段落,保持 behavior 一致
↓
得到压缩 prompt(10k),同样模型用它跑相同任务
这是用 LLM 做 prompt 优化(meta-prompting)的一种形式。
3.2 自动 prompt 压缩工具
学术界有 LongLLMLingua 等工具:
compressed_prompt = compress(
original_prompt=long_prompt,
target_ratio=0.3,
preserve=["IMPORTANT", "NEVER", "ALWAYS"],
)
它通过 token 级别的"重要性打分"删除冗余。但对 agent 场景:
- 风险高:删错一句关键纪律 agent 行为就跑偏
- 上限低:通常能压 30-50%,再压质量崩
- 不可解释:哪些被删了不一定能事后追溯
实操中我倾向人工 + LLM 辅助而不是全自动。
3.3 渐进式压缩
更稳妥的方法:
1. 先评估 baseline:原 prompt 在 100 个 eval 任务上的得分
2. 删一段(比如某个示例)
3. 重测 eval 得分
4. 如果跌幅 < 阈值,保留删除;否则恢复
5. 迭代
这种方法慢但安全。每次只删一段,确保得分不退化。最终得到"经过验证的最短 prompt"。
4. 上下文蒸馏的"few-shot 折叠"
一种特殊的上下文蒸馏:把"长篇 few-shot 示例"折叠成"简短规则"。
4.1 折叠前
System Prompt: "Here are 10 examples of how to handle ambiguous user requests:
Example 1: User says 'fix the bug'. Agent responds: 'Which bug? I see these 3...'
Example 2: User says 'make it faster'. Agent responds: 'Profile first to find...'
... (8 more)"
10 个示例 = 5k token。
4.2 折叠后
System Prompt: "When user request is ambiguous (e.g., 'fix the bug', 'make it faster'),
ask a clarifying question that lists 2-3 concrete options based on what you observed.
Don't ask abstract questions like 'what do you mean?'."
300 字 = 60 token。
折叠的关键:抽取规则而不是展示样本。当然规则化后失去了一些细节(具体语气、措辞),但对常见情况覆盖足够。
4.3 何时该展开示例
不能完全规则化的情况:
- 输出格式很特殊(用示例展示比文字描述清楚)
- 边界情况多到难以总结成规则
- 微妙的语气 / 风格
08 篇的"示例对话"模式就是这种"无法折叠"的例子。
5. 知识蒸馏到 RAG
另一种相关思路:把"知识"从 prompt 移到外部检索系统。
5.1 prompt 里塞知识 vs 检索知识
prompt 里塞:
- "本项目用 Postgres 14,迁移用 sqlx,连接池用 deadpool..."
- 30k token 的项目文档
检索:
- prompt 短:只说"用工具查项目文档"
- 真要用时:调用 RAG 工具检索相关段落
后者把"全量知识塞 prompt"变成"按需检索"。这是 agent 上下文工程里最实用的"蒸馏"形式。
5.2 何时该 RAG 化
- 知识量大(>10k token)
- 大部分任务只用一小部分
- 知识更新频繁(不想每次更新都改 prompt)
6. 子 agent 作为"运行时蒸馏"
从某种意义上,子 agent(03 篇)也是一种蒸馏:
父 agent: 用一段精简的 brief 调用子 agent
子 agent: 在自己的上下文里用全套工具探索
父 agent: 收到摘要(蒸馏后的结果)
把"完整探索"压缩成"摘要",这是运行时蒸馏而不是训练时蒸馏。
优点:
- 不需要训练
- 灵活(每次任务可以不同)
- 不损失通用性
缺点:
- 每次都要重新做(不是一次蒸馏永远受益)
- 子 agent 调用本身有成本
实操中这种"运行时蒸馏"用得最多。模型微调蒸馏只有规模化场景才划算。
7. 蒸馏的失败模式
7.1 训练分布偏差
蒸馏数据全是"成功轨迹",没有失败和恢复。结果蒸馏出的小模型遇到错误就懵。
防御:训练数据要包含错误恢复轨迹(参见 10 篇)。
7.2 工具集漂移
蒸馏时用工具集 A,部署时用工具集 B(多了或少了几个工具)。小模型的"工具决策"基于 A 训练,对 B 不熟。
防御:工具集稳定后再蒸馏。变化时要重新蒸馏。
7.3 长尾任务崩溃
常见任务表现接近 Opus,但 5% 边缘任务质量暴跌。如果不监控,平均指标看起来好,实际用户在边缘任务上极差体验。
防御:分布式 eval(不只是 mean,看 p50/p95/p99)。
7.4 prompt 压缩过激
把"重要纪律"删了,agent 行为彻底变形。
防御:渐进压缩 + eval 把关。
7.5 蒸馏后失去解释性
原 prompt 里写"do X because of Y",模型权重里没法保留 Y。当用户问"为什么这么做",蒸馏后的模型答不上。
防御:解释性需求高的任务不蒸馏,或保留解释性 prompt 段。
8. 实战:什么时候考虑蒸馏
| 场景 | 推荐路径 |
|---|---|
| 单次复杂任务,质量第一 | 直接用 Opus,不蒸馏 |
| 高频简单任务,成本敏感 | Haiku + 上下文蒸馏 prompt |
| 中频中等任务 | Sonnet + 标准 prompt |
| 极高频,工具集稳定 | 训练时蒸馏(自定义小模型) |
| 任务多样,难规模化 | 子 agent 运行时蒸馏 |
| 知识密集型 | RAG + 短 prompt |
默认不蒸馏。蒸馏是规模化产品的优化路径,不是 MVP 阶段的工作。
9. 蒸馏与 cache 的关系
蒸馏改变 prompt 长度和工具集,直接破坏 cache。
工程时序:
阶段 1:用 Opus + 长 prompt 跑业务(建立 cache)
阶段 2:收集数据训练蒸馏模型
阶段 3:切换到蒸馏模型 + 短 prompt → cache 全部失效,重新建立
阶段 4:稳态运行
阶段 3 的"切换"是高风险操作。需要:
- 灰度(小流量先切)
- 监控(cache hit rate、质量指标双盯)
- 回滚预案
10. 给 Agent 设计者的可迁移规则
- 默认不蒸馏:MVP 阶段直接用最强模型
- 先优化 prompt 再考虑蒸馏:手工压缩通常能省 30%+
- 蒸馏要工具集稳定:经常变工具就别蒸馏
- 训练数据要含失败轨迹:不要只喂成功案例
- eval 要看分布而非均值:边缘任务质量是关键
- RAG 优于全塞:知识量大时检索比蒸馏更灵活
- 子 agent 是运行时蒸馏:不需要训练就有蒸馏效果
- 解释性敏感的任务不蒸馏:会丢推理理由
- 蒸馏切换是高风险:灰度 + 回滚
- 监控质量退化的长尾:mean 看不出问题
11. 一句话总结
蒸馏是规模化场景的优化手段,不是 prompt 工程的捷径。先把上下文工程做对、再考虑蒸馏 —— 把不该塞的从 prompt 里删掉,比把塞错的"蒸馏到模型权重里"省事得多。
下一篇:19 · 多语言与非英语任务适配