上下文压缩策略
一、为什么需要压缩不只是长度问题压缩上下文有两个截然不同的动机解决长度与成本约束上下文窗口有限如 128K token工具调用结果动辄数万字符几轮交互就可能撑满窗口token 越多API 成本越高、推理延迟越大。提升思考质量总结后的知识比原始形式更利于模型使用。即使窗口足够大把原始信息散落堆放也会分散注意力、遗漏关键信息先用一次 LLM 调用做结构化总结“已知 A、B还缺 C”后续思考可直接使用精炼结论。二、内部机制上下文学习是检索而非推理注意力擅长在已有内容里查找不擅长在单次前向传播里归纳统计。经典例子100 个笼子的巡查记录问黑猫白猫各多少只——不开思维链很难答对开思维链每次都要重数一遍成本高。若提前写入黑猫 90 只白猫 10 只模型可直接检索。压缩的核心价值把需要思考才能得到的结论变成可以直接检索的知识。状态栏是往上下文加算好的结论压缩是把臃肿原始记录换成算好的结论——同一枚硬币的两面。上下文腐化Context Rot与溢出不同腐化是装得下但找不到了——窗口远未满检索精度却下降决策质量悄然下滑。最常见失效模式不是窗口不够长而是信息密度不对。Karpathy 的洞察模型记忆差某种程度上是特性而非缺陷——迫使从细节中抽象出一般模式。设计原则主动、显式地做知识提炼而非让模型被动在海量信息中检索。三、压缩的工程形态在哪发生、由谁执行理解后面所有策略的三个前提事实3.1 上下文是结构化消息数组不是混沌长文本主模型每次调用看到的上下文只是框架从消息数组渲染出来的结果。每条消息自带 role、index、tool_call_id 等元数据框架对数组有完全控制权——切片、瘦身、替换都是确定性代码操作。messages [ {index: 0, role: system, content: ...}, {index: 1, role: user, content: 修复支付回调超时}, {index: 2, role: assistant, tool_calls: [Read(...)]}, {index: 3, role: tool, tool_call_id: abc, content: 文件内容 8000 tok}, {index: 4, role: assistant, tool_calls: [Edit(...)]}, {index: 5, role: tool, tool_call_id: def, content: edit ok}, {index: 6, role: assistant, content: 已修复测试通过}, # ← 无工具调用轮结束 {index: 7, role: user, content: 再看看 staging 环境}, # ← 新一轮开始 ... ]3.2 压缩发生在两次 API 调用之间与 KV Cache 的互补关系压缩不是在单次调用中改上下文而是框架对消息数组的预处理System Prompt 和 Tool Definitions 永远不动静态前缀缓存持续有效压缩对象是对话历史中的tool results替换点之后的缓存失效、之前仍有效有意识的权衡最好在上下文接近阈值时批量压缩而不是每轮都压避免频繁破坏缓存。3.3 压缩器是一次无状态 LLM 调用输入压缩提示词压缩策略数据格式 原始messages输出压缩后的messages通常用更便宜的小模型压缩任务对能力要求低于主任务四、实验六种压缩策略对比任务多步搜索追踪 OpenAI 联合创始人职业状态Kimi K3限制 128K 窗口。策略核心做法Token 用量压缩率迭代次数结果① 无压缩完整保留原始工具结果110K 溢出100%5✗ 失败② 个体摘要每个结果独立摘要123,2056.8%24✓信息碎片化、重复浪费③ 组合摘要所有结果合并统一摘要55,4622.1%21✓超长需截断可能丢尾部信息④ 上下文感知将查询意图 已积累信息纳入压缩决策25,1980.9%15✓最优⑤ 感知 引用智能压缩 保留来源 URL45,5441.4%17✓有损压缩 无损索引⑥ 自适应窗口80% 窗口不压超阈值批量压缩181,372—8✓初期最大保真关键结论上下文感知压缩在压缩 prompt 中注入 query 和 contexttoken 减少 77%成功率最高、迭代最少——多步骤任务不同阶段所需信息密度和类型不同动态调整压缩侧重点可最大化信息价值。需要注意实验策略的定位这里比较的是单次压缩的技法压缩单个工具结果时带不带背景、带什么背景而下一节的分层机制是系统的压缩制度压缩职责在各层怎么分工——两者不是互斥选项技法会被制度中的 LLM 层复用见 5.4。五、生产级分层压缩机制以 Claude Code 为参照成熟系统组合多种策略压缩策略应与信息的预期生命周期匹配。五层机制的分工本质是能用便宜代码规则解决的绝不动用 LLMLLM 只做规则搞不定的语义级工作。层机制驱动方式成本定位1工具结果预算控制代码规则低优先使用2噪声直接删除代码规则低优先使用3API 层微压缩服务端能力低即将溢出时用4归档式摘要LLM增量中日常维护脉络5全量压缩LLM全量高最后兜底5.1 第 1~3 层代码规则驱动的低成本层第 1 层 · 工具结果预算控制大体积输出存磁盘模型只看摘要预览替换决策一旦做出就被冻结保证缓存一致性。第 2 层 · 噪声直接删除低价值内容直接移除不做摘要——对噪声做摘要是浪费 token。低价值靠确定性代码规则鉴别而非 LLM若判断还要调 LLM成本就与做摘要相当本层低成本优先的定位便不成立。典型鉴别信号信号判断逻辑后续引用率工具结果产出后从未被后续轮次引用 → 低价值体积与轮次距离超大输出 距当前已隔 N 轮 → 可清理结构化噪声模式导航栏、页脚、广告等固定模式正则/DOM 规则过滤任务状态覆盖文件旧 Read 快照已被后续 Edit/新 Read 覆盖 → 失效失败的重试被成功重试覆盖的中间失败输出只留 pass/fail其中是否被引用的判断API 拿不到模型内部注意力权重只能在消息轨迹上做确定性匹配来近似方法从强到弱结构化引用追踪最可靠工具结果中的路径/URL/ID 出现在后续工具调用参数里搜索返回 10 个文件路径仅 2 个被后续 Read 命中 → 其余 8 条可删。实现上是一张以 tool_call_id 为键的引用计数表标识符提取 全轨迹匹配正则提取路径、hash、函数名等扫描后续 assistant 消息是否复述——标识符既是不可压缩的内容也是引用追踪的锚点文本重叠检测后续消息与工具输出间的长子串 / n-gram 重叠协议化引用工具结果带编号[ref:12]要求模型引用时标注来源 ID把文本匹配变成精确查表状态覆盖判断按(工具类型, 目标对象)键值去重成本最低。注意假阴性文本匹配捕捉不到隐式使用模型读了结果改变判断方向但未复述。保守策略不删结论只删原文替换成一行元信息、近期 1~2 轮的结果不删、拿不准的留给第 4/5 层做语义判断。第 3 层 · 模型服务层微压缩通过 模型服务API 的上下文编辑能力通过参数控制例如 Anthropic 的 context editing可以声明丢弃前 N 个之外的工具结果指示服务端从前缀移除指定工具结果零本地实现成本但移除点之后缓存同样失效适合在即将溢出、反正要付缓存重建代价时使用不宜频繁触发。5.2 第 4 层归档式摘要——增量式 LLM 压缩逐轮结构化摘要像 git log保留每轮独立记录而非 git squash合并成一条丢失脉络。轮的单位是逻辑闭环片段不是字面的一问一答一次用户请求→多轮工具调用→交付结果的完整 episode可能含 30 次工具调用归档成一条记录——对应 git log 里的一个 commit。轮边界由消息结构的确定性标记划出无需 LLM一条user消息开轮assistant(tool_calls)→tool(result)循环为轮身不带工具调用的 assistant 消息最终答复收轮也可用 token 增量阈值触发。提取即数组切片框架维护last_archived游标轮结束时切出messages[last_archived1 : current]送压缩器前先序列化 预瘦身超大工具输出先经第 1~2 层截断/删噪——压缩器不需要看 8000 token 的完整文件才能写出修改了 callbacks.py。增量追加而非独立压缩与实验中个体摘要策略的关键区别压缩第 N 轮的输入 已有摘要日志第 1~N-1 轮 第 N 轮原始消息瘦身后 输出 第 N 轮的一条新记录追加到日志末尾带前文日志的目的去重已记录的事实不重复写、保持因果链“本轮改用方案 B因为第 3 轮方案 A 失败”、只写增量。这本质上是复用了实验中上下文感知压缩的技法——把已有摘要日志当作{context}传入只是压缩对象从单个工具结果换成了一整轮消息。结构化条目格式字段对应第七节的保留优先级清单防止关键信息被蒸馏掉## 轮次 7 - 意图修复支付回调超时 bug - 动作修改 src/payment/callbacks.py重试间隔 3s→10s - 结果test_callback_timeout 通过 ✓ - 决策放弃异步队列方案依赖过重 - 未决staging 环境尚未验证归档后原地替换数组替换前: [system] [轮1原始消息×6] [轮2原始消息×9] [轮3进行中...] 替换后: [system] [摘要日志(轮1、轮2各一条)] [轮3进行中...]摘要日志只在末尾追加、旧条目不动当前活跃轮始终保持原文——旧记录永不改写缓存友好、只压新一轮单次成本小、保留时序因果脉络、单轮失败影响小这是它优于全量压缩的原因。5.3 第 5 层全量压缩——最后兜底唯一会拿到接近整个上下文的压缩层但也非字面全部System Prompt / Tool Definitions 永不参与最近 N 条消息保留原文保证近期工作连续性tool results 可能已被前几层预瘦身。压缩器自身也有窗口限制极端情况需分块摘要再合并map-reduce 式。压缩后重建消息列表[System Prompt] [结构化摘要作为一条消息注入] [最近 N 条原文]。分两阶段执行先尝试压缩会话记忆不行再全量压缩并配连续失败熔断器——生产数据表明大量会话会困在反复压缩失败的循环中熔断器避免持续烧钱。5.4 上下文感知压缩与归档式摘要技法与制度的组合两者不是同一个策略但共享同一个核心思想并在生产系统中串联使用维度上下文感知压缩实验策略④归档式摘要第 4 层定位单次压缩的技法系统常设的制度压缩对象单个工具结果空间维度的冗余一整轮对话时间维度的冗余触发时机大体积工具结果产出时一轮逻辑闭环结束时压缩时带的背景查询意图{query} 已积累信息{context}已有摘要日志输出去向替换原始工具结果留在对话流原位置追加到摘要日志末尾替换整轮消息共同思想压缩时带上背景而不是孤立地对着内容做摘要——这正是两者同时优于个体摘要孤立压缩、信息碎片化的原因。实践中的串联流水线工具结果产出 → 上下文感知压缩/预算控制瘦身空间维度即时 一轮结束 → 归档式摘要蒸馏成一条日志记录时间维度轮级 仍接近溢出 → 全量压缩兜底全局注意实时的压缩会牺牲效率和时间5.5 各层压缩器的输入范围对比压缩类型输入是否整个上下文上下文感知压缩实验策略④单个工具结果 查询意图 已积累信息简述❌归档式摘要第 4 层新一轮原始消息 已有摘要日志❌ 只有增量全量压缩第 5 层几乎全部对话历史✅最后兜底分层机制让整个上下文进压缩器成为最后才发生的事日常以小粒度、增量式进行只有前几层都不够时才触发昂贵的全量压缩。六、压缩策略的四条设计原则信息价值非均匀分布关键决策点 支撑性证据 冗余噪声语义完整性“Sutskever 于 2024 年 5 月离开 OpenAI不能压成Sutskever 离开”——时间和公司名不可丢任务相关性同样内容在不同任务下应产生不同压缩结果压缩即理解有效压缩需要深层语义理解且显式压缩结果可审查、可跨会话复用。七、对 Agent 架构设计的启示压缩即理解压缩模块需接近主模型的理解能力形成模型调用模型的递归架构压缩策略与任务类型耦合检索类保广度、分析类保深度、创作类保灵感触发点ROI 极高上下文感知压缩减少 75% token 使用量压缩最易丢失的不是细节而是早期架构决策、约束背后的理由、失败的路径。建议显式定义保留优先级架构决策和关键约束不得摘要已修改文件列表和关键变更记录完整保留验证状态pass/fail必须保留未解决的 TODO 和回滚笔记必须保留工具输出可删除仅保留 pass/fail 结论标识符UUID、hash、IP、端口、URL、文件名必须原样保留——改错一位后续工具调用直接失效。八、隔离优于压缩子 Agent 上下文隔离更釜底抽薪的思路让大体积中间信息根本不进入主上下文——主 Agent 把读大量文件大范围搜索等任务委派给独立子 Agent子 Agent 在自己的上下文中探索只回传几百 token 的结论性摘要。对比主 Agent 亲自搜索 → 数万 token 原始代码成为永久噪声委派子 Agent → 主上下文只增加一条任务描述 一条结论中间过程随子 Agent 上下文一起丢弃。本质是用隔离代替压缩压缩是有损的事后补救隔离让噪声从一开始与主上下文绝缘KV Cache 前缀完全不受影响。代价子 Agent 看不到主上下文任务描述必须自包含、目标明确。生产实现Claude Code 的 Task 工具、各类 Deep Research 系统的检索子 Agent。

相关新闻