☰
用户一思考,Agent 就失忆:ReCAP 把上下文压缩的延迟砍掉 95%
2026/10/3 11:47:25 网站建设 项目流程

TL;DR

Coding Agent 最大的隐形开销不是推理,而是「失忆重启」:你去泡杯咖啡回来,KV 缓存早过期了,Agent 要么重新摘要一遍历史、要么把几十万 token 重新 prefill 一遍。UCSB 与微软的 ReCAP 换了个思路——推理时反正算过注意力,用完就扔太浪费,不如存成一张轻量「持久上下文图」,下次请求来了直接翻图选块,全程零模型调用。结果:对比 Codex 默认的摘要式压缩,压缩加冷恢复的延迟降约95%,代码任务准确率反而比塞全量历史还高 19.8 分。

导语:那个「正在压缩对话」的转圈时刻

先问一个可能戳到你的问题:你有多久没见过 Coding Agent 的上下文条一直留在绿色了?

只要任务跑过半小时,你一定见过这个场面——Claude Code 弹出「Compacting conversation」,Codex 开始生成 handoff summary,转圈几十秒之后,Agent 对半小时前干过的事只剩一段摘要的记忆。想让它回看某个早前的改动?抱歉,细节已经被压缩掉了。

更隐蔽的是钱包在流血。一篇新论文引用的实测数据:在约 4,300 个 Claude Code 和 Codex 会话里,用户思考时间占了会话总时长的 92%。这意味着什么?意味着你每次隔了一小时回来发消息,服务端的 KV 缓存(可以理解为「模型对历史的记忆速查表」)几乎必然已经过期——Agent 要从冷状态重建对整个会话的记忆。

想自己动手试?

  • 📄 论文:arXiv 2609.40118
  • 💻 代码:GitHub · UCSB-NLP-Chang/ReCAP

来自 UC 圣塔芭芭拉和微软的这篇《Persistent Context Graphs for Efficient Memory Compaction in LLM Agents》给这套流程上了个狠活:他们把 Agent 推理时本来就在计算、用完就丢的注意力捡回来存成一张图,以后的每次「恢复记忆」都变成查表,一个模型调用都不加。听起来像玄学?数据说话:延迟砍 95%,效果不降反升。

三个反直觉的观察:注意力早就在替你「划重点」

这项工作的起点不是新模型,而是三个测量。团队拿真实的编码 Agent 会话做了实验,结论相当有意思。

观察一:注意力高度集中。在一个多轮编码会话里,每轮请求的注意力都牢牢锁在历史的一小部分上——按「每 token 注意力质量」排序,只保留 10% 的历史 token,就能锁住 65% 的注意力质量。换句话说,模型自己心里门儿清哪些历史重要。

观察二:上一轮的注意力能预测下一轮复用什么。跨 8 个会话的 64 次轮转换测量:用「上一轮注意力」给历史块排序,在 10% 预算下对下一轮实际使用的标识符(文件名、函数名)覆盖率中位数 0.68——而「开了天眼的未来使用神谕」也只有 0.71。差的那 0.03,恰好是新请求带来的变量。

观察三:新请求会重定向注意力。控制变量实验里,历史完全不动、只改请求:把目标文件从 A 换成 B,注意力重分配 10.1%;只是换个说法问同一件事,只重分配 5.3%。也就是说「哪些历史重要」这个问题有两半答案——重要性一半写在历史里,相关性一半写在新请求里。

这三个观察直接指出了现有方法的死穴:摘要式压缩在请求到来前就 irreversible 地做了取舍,赌的是「未来用得上什么」;query-aware 的 KV 驱逐倒是看请求了,但缓存过期后连打分的原料都没了。那怎么办?

ReCAP 的思路:记笔记,不问模型

ReCAP 的全称你可以理解成「Recall via Compacted Attention Persistence」——核心动作就两步:执行时记笔记,请求时翻笔记。

执行时:把注意力沉淀成一张图

ReCAP 把会话历史切成「原子块」:一条用户消息、一组工具调用连同它的返回结果、或一段普通回答。每个块是一个节点,身上挂着两个东西——

  • 重要性分:本轮生成过程对每个历史块的注意力,按块聚合后做指数滑动平均。经常被「翻牌」的块分数高,冷落许久的块分数自然衰减。
  • 依赖边:如果块 B 生成时大量注意力落在更早的块 A 上,就画一条 A→B 的边。以后选中 B 时,可以顺着边把支撑它的 A 也带回来——比如选了「诊断结论」,它依据的那条报错现场就能一并跟上。

整张图只有标量分数和指针,每会话约 19KB,躺在 CPU 内存里,跟 KV 缓存完全解耦——缓存死了它也活着。更妙的是,这些注意力本来就是推理的副产品,记录它几乎白嫖。

请求时:翻图选块,零模型调用

新请求到来时,ReCAP 给每个块算一个总分,成分很朴素:

  • 存量的重要性分(历史 usage 的先验);
  • 请求与块内容的标识符重叠,按 IDF 加权——你点名一个罕见文件名,含它的块分数陡增;
  • 从没被观测过的块拿一点探索奖励(防止「冷块永无出头日」),疑似被修订过的旧块吃惩罚(陈旧降权)。

然后按分数贪心装入约 10% 的历史预算。但有两道保险:用户消息和每个被改文件的最新编辑记录无条件保留(这是「保命块」);选中的块沿依赖边再做一跳扩展,把支撑上下文补齐。全程只有排序、字符串匹配和图遍历——实测开销0.02 秒,跑在 CPU 上。

和前缀缓存不是对手,是搭档

有人会问:前缀缓存(prefix caching)不是已经把热会话的重复编码解决了吗?没错,ReCAP 的定位很清楚:缓存还热就完全不介入,新请求直接追加在驻留上下文后面,99.9% 的 token 走缓存;缓存过期才出手,用图选块重建一个紧凑前缀。两者一个管热、一个管冷,互不拆台。

效果到底怎么样?

实验用两个开源模型(Qwen3-Coder-30B、gpt-oss-20b)跑两个交互式编码基准:SWE-Together(106 个带用户反馈的仓库级任务)和 Lost-in-Conversation(100 个需求散落在多轮对话里的代码任务),对比 7 个基线,包括 Codex 式摘要、LLMLingua 系提示压缩、KV 驱逐。

先看钱。摘要式压缩每次触发要吃 7.67 秒(Qwen)的压缩延迟外加 7 万多 prompt token;ReCAP 全程 0.02 秒、零额外 token。把「压缩开销 + 冷恢复 TTFT」加总,ReCAP 比各基线低94.5%–95.6%(Qwen)/ 76.2%–94.9%(gpt-oss)。对全量历史而言,冷启动首 token 时间也从 0.985 秒降到 0.395 秒(2.49 倍)。

再看质量,这里有个反直觉的亮点。在 SWE-Together 上,ReCAP(28.5)与摘要式(28.7)打平、胜过全量历史(24.4),上下文只用了全量的一半。但在 LiC 上画风突变:ReCAP 用平均 94 个 token 的上下文拿到 85.4 分,全量历史(1,121 token)反而只有 65.6 分。需求藏在对话细节里时,把干扰一并塞给模型不如精准递上相关的几块——省成本和提质量,这次是同一件事。

还有两个工程上很贴心的发现。其一,被丢掉的历史能复活:SWE-Together 上 70% 的轮转换里,ReCAP 会重新选中之前某轮被略过的块——摘要是单行道,图是可逆的。其二,闭源 API 也能用:注意力拿不到?用一个 0.6B 的小模型(约主模型 2–3% 的参数量)重放上下文代替,三个设置下效果差异不超过 0.6 分。

消融实验也干净利落:把注意力图拆掉、只靠标识符匹配,LiC 掉 8.8 分——注意力信号是主要增益来源;把块切得更碎(按段落/按行),分数掉、上下文反而膨胀——「工具调用与结果成组」这个粒度设计是对的。

泼冷水:三个该打问号的地方

优点讲完了,按惯例泼点冷水,三个地方值得打问号。

  • 「95%」的分母要看清:这是「压缩开销 + 冷恢复延迟」的合并估计(单卡串行测算),不是生产环境端到端 A/B。如果你的场景前缀缓存命中率高、几乎不触发冷恢复,收益会打折。
  • SWE-Together 上它并没有赢摘要式:质量持平(28.5 vs 28.7),换来延迟优势的代价是 3 倍于摘要的工作上下文(15.3k vs 5.2k token)。若摘要调用极其便宜、prefill 单价又低,这笔账可能反转。
  • 只在 30B/20B 开源模型上验证:前沿规模模型的注意力是否同样稀疏集中、标识符匹配对非代码任务(自然语言、模糊指代)是否同样好使,论文没有给答案。

写在最后:对你的项目意味着什么

回头看,这篇论文最值钱的是一个视角转换:「该保留哪些历史」不需要模型来判断,模型推理时早就用注意力投过票了,你只是没记账。

如果你在自建 Agent 基础设施,ReCAP 的三个组件都可以单独抄:执行期顺手聚合注意力做重要性评分、请求期用「存量重要性 + 标识符匹配」的免调用选择、「用户消息 + 最新编辑无条件保留」的保护集设计(论文附录里两个翻车案例——任务描述被挤掉后 Agent 编造问题、自己的修改记录被挤掉后以为已修复——就是没有保护集的下场)。

至于做闭源 API Agent 的同学,0.6B 小模型代理注意力那条实验可能是全文最实用的一行:上下文管理这件事,正在从「模型能力」变成「工程账本」。谁把这本账算得细,谁家的 Agent 就转得又快又稳。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询