做 Agent 项目时,对话持续进行,token 会不断累积,迟早超出模型的 context window。这篇文章整理一套五层上下文压缩机制,从轻到重依次触发,核心思路是”能少压就少压,实在不行再大压”。
整体逻辑
1 | 对话持续进行 → Token 接近上限 → 触发压缩 → 压缩成功继续 → 压缩失败升级到下一层 |
五层从左到右,压缩力度递增,成本也递增:
1 | Tool Result Replace → Snip Compact → Micro Compact → Context Collapse → Auto Compact |
第一层:Tool Result Replace
做什么: 把工具调用的返回结果替换掉,只保留占位符。
1 | # 原来 |
工具返回了大量原始数据(日志、代码、搜索结果),但后续对话其实不需要完整内容,只需要知道”调用过这个工具、拿到了结果”。
成本: 极低,只是字符串替换,不需要调用 LLM。
第二层:Snip Compact
做什么: 精准裁剪,找到对话里最占空间的片段,把它们缩短,但保留上下文结构。
比如一个很长的 tool_result 块,只保留前几行 + 末尾摘要,中间截断:
1 | [原始内容前100行] |
适用场景: 有几个特别大的消息拖累了整体 token 数,其他消息都正常。
成本: 低,基于规则裁剪,不需要 LLM。
第三层:Micro Compact
做什么: 清理掉已经没用的工具调用记录。
比如 cache_read、cache_write 这类中间过程的工具调用,任务完成后这些记录对后续对话没有价值,直接标记为 [tool cleared] 删掉。
1 | # 删除前 |
适用场景: 对话里有大量中间步骤的工具调用,但最终结果已经体现在后续消息里了。
成本: 低,规则删除,不需要 LLM。
第四层:Context Collapse
做什么: 不再保留原始消息,把整段历史对话喂给 LLM,让它生成一个 summary,用 summary 替代原始历史。
1 | def context_collapse(history): |
1 | 原来:[20轮完整对话,8000 token] |
适用场景: 前三层都压不下去,token 还是超限。
成本: 高,需要调用一次 LLM 生成摘要,有延迟和费用。
注意: 这一层只压 Model-Facing 部分(发给模型的消息),不压 Raw Messages(原始记录),保留审计能力。
第五层:Auto Compact
做什么: 完全重建上下文。生成一个新的 compact prompt 作为全新对话的起点,原始历史全部丢弃。
新的起点包含三部分:
1 | compact_prompt = { |
内部还分两档:
- Session Memory Compact(轻量): 用已有的 session memory 替代,成本低,但信息可能不完整,适合对话内容不太重要的场景
- Full Compact(兜底): 完整重建,成本最高,但保证能继续运行,是最后的兜底手段
适用场景: 对话极长,前四层都无法把 token 压到窗口以内。
机制设计要点
容量精准计算
不用固定阈值,而是动态计算可用窗口:
1 | def get_effective_context_window(): |
缓存优先策略
压缩时优先保留 cache_read/cache_write 相关内容,避免缓存失效导致重复计算费用。
结构完整性保障
压缩后保证 thinking/tool_use 配对完整,不出现孤立的工具调用(没有对应 tool_result 的 tool_use 会导致 API 报错)。
失败兜底
每层失败都有明确的升级路径:
1 | 第1层失败 → 升级到第2层 |
五层对比
| 层级 | 方式 | 成本 | 信息损失 | 触发条件 |
|---|---|---|---|---|
| Tool Result Replace | 替换工具结果为占位符 | 极低 | 低 | 工具结果过大 |
| Snip Compact | 裁剪大消息中间部分 | 低 | 低 | 单条消息过大 |
| Micro Compact | 删除无用工具调用记录 | 低 | 极低 | 中间步骤堆积 |
| Context Collapse | LLM 生成历史摘要 | 高 | 中 | 前三层不够用 |
| Auto Compact | 完全重建上下文 | 最高 | 高 | 最后兜底 |
实际项目怎么选
大多数 Agent 项目不需要实现全部五层,按场景选:
短会话 Agent(每次对话独立,如运维告警): 滑动窗口就够,不需要压缩机制。
中等长度对话(如代码助手、问答): 实现第1层(Tool Result Replace)+ 第4层(Context Collapse)基本够用,覆盖了 80% 的场景。
超长会话(如长期任务执行、个人助手): 需要完整五层,或者引入向量库做长期记忆。
面试被问到”你的 Agent 怎么处理长对话”,不要只说”我用了摘要压缩”,说清楚在哪一层触发、为什么不需要更重的层,才能体现你对整个方案空间的理解。