Skip to content

从 Cursor 的 Self-Compaction 看 Agent 上下文压缩

MasakiMu319 ·

2026 年 3 月 17 日,Cursor 发布了一篇博客 Training Composer for longer horizons,介绍他们如何通过强化学习训练 Composer 模型学会”自我压缩”(self-summarization),从而处理远超上下文窗口的长周期编程任务。

文章本身讲得很清楚:Agent 轨迹增长速度远超模型上下文长度,传统的外部压缩会引入延迟、信息损失和额外成本。Cursor 的做法是让模型自己在训练中学会何时压缩、保留什么。

但读完之后有一个问题没有被解释清楚:self-compaction 作为模型自身的行为,在复用 KV cache 时究竟是怎么做到的?

这篇文章试图回答这个问题,然后把它和我们逆向工程研究过的 Claude Code、Codex CLI 的上下文压缩机制放在一起比较。


传统压缩的 KV Cache 问题

先回顾一下传统方案的流程:

  1. Agent 运行到 context 接近上限(比如 80k token)
  2. 调用外部模型(或用不同 prompt)对历史进行压缩
  3. 拿到摘要后,拼成新 prompt
  4. 整个 prompt 重新 prefill

问题在第 4 步:新 prompt 的 token 序列和旧的完全不同,KV cache 全部作废。即使摘要只有 1k token,你也需要重新 prefill system prompt + 摘要 + 最近的消息,延迟开销和 GPU 占用都不低。

Cursor 的 Self-Compaction:KV Cache 复用机制

Cursor 的方案巧妙地避开了这个问题。关键在于:压缩后的表示不是由外部模型生成的,而是当前模型在已有 KV cache 基础上直接 decode 出来的。

具体流程:

[System Prompt] [Tool calls & results...] [80k tokens of context]

                                          触发 compaction

                              插入合成 query:"请总结以上关键信息"

                        模型基于已有 80k 的 KV cache 直接 decode

                            生成 ~1k token 的 summary(无需 prefill)

                    截断 KV cache,只保留 prefix + summary 的 KV

                              从新的压缩状态继续 decode

这里的”KV cache 友好”不是指 system prompt 前缀可以复用(这是 prefix caching 的基本能力,所有方案都有),而是指生成压缩摘要这一步本身零 prefill 开销

模型已经在 80k context 的 decode 流中了,KV cache 完好无损。插入合成 query 后,模型直接基于这个 cache 生成 summary——这是一次普通的 decode,不是 prefill。80k token 的信息已经编码在 KV cache 的 attention 表示中,模型只是把它”蒸馏”成了 1k token 的输出。

生成完成后,丢掉前面 80k 的 KV cache,只保留 summary 这 1k token 的 KV 作为新起点。

对比传统方案:

省掉的是两次大规模 prefill,这才是”KV cache 友好”真正的含义。


应用层的 Auto-Compaction:Claude Code 与 Codex CLI

Cursor 的方案在推理层操作 KV cache,大多数 Agent 框架没有这个条件。但应用层的 auto-compaction 早已是标配——只是工程实现不同。通过对 Claude Code v2.0.37 和 Codex CLI 的逆向工程(本地安装字符串提取 + 代码分析),我们拆解了两者的具体机制。

Claude Code — 9 段式结构化 Compact

触发条件:系统级自动触发。当 token 用量接近窗口上限时(200K 窗口下约 155K),系统直接调压缩 API,不需要模型决定。也支持手动 /compact

执行流程

  1. 检测 token 超过 autocompact 阈值
  2. 运行 PreCompact hooks(允许用户注入自定义指令或阻止压缩)
  3. 调用当前主模型(不是小模型)做压缩,thinking 关闭,maxOutputTokens = 20000
  4. 压缩 prompt 要求生成 9 段式结构化摘要
    • Primary Request and Intent — 用户的所有显式请求
    • Key Technical Concepts — 技术概念、框架、工具
    • Files and Code Sections — 文件名 + 完整代码片段 + 变更原因
    • Errors and Fixes — 所有错误 + 修复方式 + 用户反馈
    • Problem Solving — 已解决和进行中的问题
    • All User Messages — 所有非工具调用的用户消息(完整保留,非摘要
    • Pending Tasks — 待完成任务
    • Current Work — 压缩前正在做的工作(含代码片段)
    • Optional Next Step — 下一步(须与用户最近请求直接相关)
  5. 恢复最近读过的 5 个文件(每个上限 5000 tokens,总上限 50000 tokens)
  6. 插入 compact_boundary 标记 + 摘要消息
  7. 整个 prompt 重新 prefill

此外,Claude Code 还有独立的工具输出预压缩:bash 输出超过 5000 字符时,单独调模型判断是否需要压缩,原始输出保存到磁盘文件供回查。

Codex CLI — 简洁版 Auto-Compact

Codex CLI 的方案更简单:

两者的共同特点:都是系统级自动触发,不依赖模型自行判断”该不该压缩了”。压缩后非终止——agent 在同一会话中继续工作,不中断循环。

两者的 KV cache 特性:通过逆向工程确认,Claude Code 的 compact 是一次独立的 API 调用——使用全新的 system prompt("You are a helpful AI assistant tasked with summarizing conversations.")和全新的 user message(将完整对话历史作为待压缩内容传入)。Codex CLI 同理。这意味着 compact 调用本身不复用原有对话的 KV cache,需要对整段对话做完整 prefill。

但这并不意味着应用层方案就完全不友好。压缩完成后,后续的正常对话请求可以享受 API 提供商的 prompt caching(Anthropic、OpenAI 都有)——压缩后的 prompt 保留了相同的 system prompt 前缀,这部分 cache 命中。所以代价主要集中在 compact 调用本身那一次 prefill。

这与 Cursor 的方案有本质差异:Cursor 在原有对话的 KV cache 上直接 decode 出摘要,连 compact 本身那一次 prefill 都省掉了。应用层方案无论怎么优化,compact 调用都需要一次完整的对话级 prefill。


对比

维度Cursor Self-CompactionClaude CodeCodex CLI
触发方式RL trained behavior系统自动(token 阈值)系统自动(可配置)
压缩执行层推理层(KV cache 操作)应用层(独立 API 调用)应用层(独立 API 调用)
是否阻塞
摘要结构模型自学(RL)9 段式结构化文本可定制 prompt
训练信号RL 奖励(端到端)
长期知识N/A文件恢复(最近 5 个)

这个 pattern 的本质

剥掉工程差异,所有方案共享同一个核心洞察:

最好的压缩器就是需要使用被压缩信息的那个模型自己。

外部摘要模型不知道下游任务需要什么信息,它只能做通用的”重要性”判断。而执行任务的模型自己做压缩时,它的 attention 分布天然反映了”对当前任务而言什么是重要的”。

这也解释了为什么 Cursor 的实验中,self-compaction 的 token 效率远高于外部压缩——不是因为它生成了更好的自然语言摘要,而是因为 KV cache 中的 attention 表示本身就是一种比自然语言更高效的信息压缩形式。模型不需要把所有上下文”翻译”成人类可读的文字再”翻译”回来,它只需要在 KV 空间中保留对后续 decode 有用的表示。

应用层方案虽然必须经过”自然语言中转”,但也在逼近这个本质:比如 Claude Code 要求保留完整代码片段和所有用户消息(减少压缩带来的信息损失)。

最根本的差距:训练信号

四种方案中,Cursor 是唯一有闭环优化信号的。RL 奖励直接告诉模型”这次压缩丢了关键信息导致后续任务失败了”,模型下次学会保留更多关键细节。

其他方案的压缩质量完全依赖 prompt 设计。你可以写”保留关键事实和代码片段”,但模型不会收到”这次压缩导致后续出错了”的反馈。应用层能做的近似是事后审计:检测因压缩丢失信息导致的错误,记录 pattern 并反馈到压缩 prompt 中——但这是人工闭环,不是梯度闭环。

对于应用层框架来说,一个可以逼近的方向是知识外置:把长期知识外置到向量数据库 / 知识图谱中,compaction 只负责短期工作状态的压缩。摘要的负担更轻——它不需要记住所有历史事实,只需要记住”当前在做什么、下一步做什么”。这是推理层方案做不到的事:用架构补偿训练信号的缺失


写在最后

Cursor 这篇文章的核心贡献不是发明了 self-compaction 这个 pattern——任何做过 Agent 上下文管理的工程师都在用某种形式的 compaction。它的贡献是把这个行为从 harness-level hack 提升为 trained behavior,用 RL 让模型自己学会什么时候压缩、保留什么,并且在推理层利用 KV cache 实现了近乎零开销的执行。

从 Claude Code 的 9 段式结构化摘要,到 Codex CLI 的可配置 compact,应用层框架在用不同的工程手段逼近同一个目标。方法论不同,但解决的都是同一个问题——让 Agent 在有限的注意力窗口中,做出需要无限记忆才能做好的事情。

上下文压缩不应该是框架的补丁,而应该是系统的一等公民。


Previous 被困在同一条河里的 Agent Next Bub Tape 架构深度解读:从可追踪记忆到可控上下文窗口