Agent 精读(九):装得下,但找不到了

这是《深入理解 AI Agent》精读专题的第九篇,第 2 章的收官:上下文压缩——什么时候压、怎么压、以及为什么「隔离优于压缩」。读的是李博杰的开源书第二章的最后部分。

压缩的三个理由,一个比一个深

  1. 成本与长度:窗口有限(比如 128K),工具结果动辄数万字符,几轮就撑满,任务被迫中断;token 越多,成本和延迟越高
  2. 思考质量:即使窗口够大,堆原始信息也不是最优——十几轮搜索结果散落各处,模型每次决策都要在数万 token 里反复检索,注意力被分散,关键信息被遗漏
  3. 上下文焦虑(Context Anxiety):最隐蔽的一个——当模型「觉得」窗口快耗尽时,会在任务没完成前提前收尾。在窗口远没接近耗尽时就主动压缩,模型反而能把任务做完

机制:把需要思考的,变成可以检索的

上一篇状态栏说过「上下文学习更像检索而非推理」。压缩是同一枚硬币的另一面:状态栏是把算好的结论「加」进上下文,压缩是把臃肿的原始记录「换」成算好的结论——都在给那台只有一半的检索引擎补上提炼层。区别只是:状态栏由代码确定性维护,压缩通常用一次 LLM 调用把大段原文蒸馏掉。

书里的例子一眼就懂:上下文里有 100 个笼子的巡查记录(90 只黑猫、10 只白猫),问「黑猫几只」——查找(笼子 37 是什么猫)是注意力的强项;统计归纳要遍历全部记录并维护计数,本质是思考。思维链当然能数对,但每问一次就要从头数一遍。而提前写入「当前统计:黑猫 90 只」,模型立刻检索到。

这就是压缩的第二个价值:把需要思考才能得到的结论,变成可以直接检索的知识。

两个病:溢出和腐化

  • 上下文溢出:装不下了,任务直接失败——这个好理解
  • 上下文腐化(Context Rot)装得下,但找不到了——窗口远没满,Agent 却找不到关键信息,或反复纠结一个早已解决的问题。更隐蔽:表面上还在正常工作,决策质量已经悄然下降

腐化的原因是注意力权重被更多 token 分薄、无关内容占了大头——像在巨大的图书馆里找一本书,无关的书越多,目标越难找。

与 KV Cache 共存:压缩的时机和位置

前面反复强调「前缀不能动」,压缩不就是要改上下文吗?关键在时机和位置:压缩发生在两次 API 调用之间,由框架预处理消息列表——

  • System Prompt 和工具定义永远不动(静态前缀持续缓存)
  • 压的对象是对话历史里的 tool results;替换点之后的缓存失效,之前的仍有效
  • 这是笔有意识的权衡:不压缩会溢出任务失败;压缩损失部分缓存换上下文可控。所以接近阈值时批量压,而不是每轮都压

四条设计原则

  1. 信息价值非均匀分布:决策关键点 > 支撑证据 > 噪声(导航栏、页脚广告)——压缩预算要按价值分配
  2. 语义完整性:「Sutskever 于 2024 年 5 月离开 OpenAI」不能压成「Sutskever 离开」——时间和主体是不可丢的关键信息
  3. 任务相关性:同一内容在不同任务下应产出不同的压缩——检索类任务保广度,分析类保深度,创作类保灵感触发点
  4. 压缩即理解:有效的压缩需要深层语义理解,压缩模块本身要接近主模型的能力(「模型调用模型」的递归架构);好处是压缩结果可审查、可跨会话复用

实验数字背书:上下文感知压缩(把查询意图纳入压缩决策)让 token 使用量减少 75% 以上;而无压缩基线里,几次搜索就耗尽了 128K 窗口(累计 36.7 万字符的原始结果)。

一个优雅的补充是带引用的压缩:内容语义压缩(有损),但每条事实附来源 URL(无损索引)——理论上随时可以回溯原始信息。再配一条工程纪律:决策关键信息要持久化到文档——压缩最容易丢的恰恰是早期的架构决策、约束背后的理由和失败的路径;就像公司的重要信息要文档化而不是留在聊天记录里,模型没有文档化习惯,就用 prompt 和 Skill 提醒它。

生产级:五层分层压缩

成熟系统不会只用一种策略,而是按信息的「保质期」分层(以 Claude Code 为参照):

  1. 工具结果预算控制:大输出落盘,模型只看摘要预览
  2. 噪声直接删:低价值内容直接移除,不做摘要——对噪声做摘要只是浪费 token
  3. API 层微压缩:用 API 的上下文编辑能力让服务端移除指定工具结果——零本地成本,但移除点后的缓存同样失效,适合即将溢出、反正要重建缓存时用
  4. 归档式摘要:逐轮结构化摘要,像 git log 那样保留每轮记录(而不是 squash 成一条),保住对话脉络
  5. 全量压缩:LLM 驱动的最后手段,且带熔断器——生产数据表明大量会话会困在「反复压缩失败」的循环里持续烧钱

隔离优于压缩

压缩是信息进来之后做减法,更釜底抽薪的思路是:让大体积的中间信息根本不进主上下文

主 Agent 把「在代码库中大范围搜索」这类会产生海量中间内容的任务,委派给独立的子 Agent:子 Agent 在自己的上下文里完成探索,只把几百 token 的结论回传。对比一下——主 Agent 亲自搜,数万 token 的原始代码进主上下文,找到目标后全沦为噪声还得靠压缩清理;委派出去,主上下文只增加两条消息(任务描述 + 结论),中间的数万 token 随子 Agent 的上下文一起被丢弃。

本质是用隔离代替压缩:压缩是有损的、需要额外 LLM 调用的事后补救;隔离让噪声从一开始就与主上下文绝缘,主 Agent 的 KV Cache 前缀完全不受影响。代价是子 Agent 看不到主 Agent 的完整上下文,任务描述必须自包含、目标明确——又回到全章的主题:上下文的质量决定能力上限,对子 Agent 同样成立。

第 2 章读完了

三条线索合成一句话:上下文的质量决定能力的上限——提示工程决定写什么,Skills 和状态栏决定怎么按需加载与提炼,压缩决定怎么给膨胀的上下文做减法,隔离决定什么根本不该进来。

下一步

  • 进入第 3 章:用户记忆与知识库——把上下文从单次会话延伸为跨会话的持久知识
  • 实验债清单:context-compressionagent-status-barprompt-engineering

参考来源