上下文压缩动机与机制
上下文压缩有哪三个动机?
- 动机一(长度与成本约束): 上下文窗口有限(如 128K token),工具调用结果动辄数万字符,几轮交互就可能撑满;token 越多 API 成本越高、推理延迟急剧上升;
- 动机二(提升思考质量): 即使窗口足够大,把原始信息全堆进去也不是最优——与决策无关的内容散落各处,注意力被分散,关键信息容易被遗漏;
- 动机二的替代: 用一次 LLM 调用把已有信息结构化总结成“目前已知 A 是……、B 是……、还缺 C”,后续思考直接使用这份精炼表示;
- 动机三(缓解上下文焦虑 Context Anxiety): 模型认为窗口即将耗尽时,可能在任务尚未完成前提前收尾;
- 动机三的推论: 在窗口尚未接近耗尽时就提前压缩,可能提升模型决策质量;
为什么“总结后的知识”比原始形式更好用?
- 底层机制: 注意力机制擅长在已有内容里“查找”,却不擅长在一次前向传播里主动“归纳统计”;
- 宠物店例子: 上下文中列出 100 个笼子(90 只黑猫、10 只白猫),问“各有多少只”时,不启用思维链很难直接答对;
- 原因: 查找(“笼子 37 里是什么猫?”)是注意力强项;统计归纳(“总共有多少只黑猫?”)要遍历全部记录并维护计数状态,本质是思考而非检索;
- 成本对比: 启用思维链能数对,但每问一次就要从头数一遍,在 Agent 场景中这类统计常被反复使用,累积成本很高;
- 压缩解法: 提前做一次总结,在上下文中直接写入“当前统计:黑猫 90 只,白猫 10 只”,模型立刻能检索到;
- 核心价值: 把需要思考才能得到的结论,变成可以直接检索的知识;
- 与状态栏的关系: 状态栏是把算好的结论加进上下文,压缩是把臃肿的原始记录换成算好的结论——两者是同一枚硬币的两面;
- 分工差异: 状态栏往往由代码每一步确定性地维护,压缩则更多是用一次 LLM 调用把大段原文蒸馏掉;
上下文腐化与上下文溢出有何区别?
- 上下文溢出: 窗口“装不下了”,会触发长度限制与任务中断;
- 上下文腐化(Context Rot): 窗口远没有满,但 Agent 突然找不到关键信息,或反复纠结于一个早已解决的问题;
- 区别一句话: 溢出是“装不下了”,腐化是“装得下但找不到了”;
- 隐蔽性: 腐化更危险——Agent 表面上还在正常工作,只是决策质量悄然下降;
- 机制: 上下文越长,注意力权重被分散到越多 token 上,每个 token 获得的权重变小;
- 放大因素: 无关内容一旦占到上下文的大头,决策质量就会明显下滑;
- 典型场景: 偶尔才用到的知识每次都加载、稳定规则和动态状态混在一起;
- 比喻: 在巨大图书馆里找某本书,书架上无关书籍越多,找到目标越难;
压缩为什么与 KV Cache 不矛盾?
-
表面矛盾: KV Cache 要求前缀不变,压缩却要修改上下文中间的内容;
-
关键一(时机): 压缩不在单次 API 调用内进行,而是在两次 API 调用之间由框架预处理消息列表;
-
关键二(对象): 压缩的对象是对话历史中的 tool results,静态前缀(System Prompt 与 Tool Definitions)永远不动;
-
缓存影响: 替换位置之后的缓存失效,之前的缓存仍然有效;
-
权衡: 不压缩则上下文膨胀超出窗口,任务直接失败;压缩虽损失部分缓存,但长度可控、信息密度更高;
-
频次建议: 频繁压缩会频繁破坏缓存,最好在上下文接近阈值时批量压缩,而不是每轮都压;
-
定位: Agent 状态栏是压缩的一种形态;压缩的设计原则与策略选择见 压缩策略与分层机制;