上下文工程 · 18 · Agent 蒸馏与上下文蒸馏

2 阅读9分钟

系列第 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 设计者的可迁移规则

  1. 默认不蒸馏:MVP 阶段直接用最强模型
  2. 先优化 prompt 再考虑蒸馏:手工压缩通常能省 30%+
  3. 蒸馏要工具集稳定:经常变工具就别蒸馏
  4. 训练数据要含失败轨迹:不要只喂成功案例
  5. eval 要看分布而非均值:边缘任务质量是关键
  6. RAG 优于全塞:知识量大时检索比蒸馏更灵活
  7. 子 agent 是运行时蒸馏:不需要训练就有蒸馏效果
  8. 解释性敏感的任务不蒸馏:会丢推理理由
  9. 蒸馏切换是高风险:灰度 + 回滚
  10. 监控质量退化的长尾:mean 看不出问题

11. 一句话总结

蒸馏是规模化场景的优化手段,不是 prompt 工程的捷径。先把上下文工程做对、再考虑蒸馏 —— 把不该塞的从 prompt 里删掉,比把塞错的"蒸馏到模型权重里"省事得多。

下一篇:19 · 多语言与非英语任务适配