AKV 缓存工程开源:智能体成本降 27.7%,分数升 1.7 分

一句话结论:AKV 把智能体的 KV Cache 当成可编程对象直接删改,绕开重新预填充的代价,在三个模型四个基准上平均成本降 27.7%、任务分数升 1.7 分。

智能体跑长任务时,账单是怎么堆起来的。论文给了一组很直接的测算:KV Cache 读取占整个 API 成本的 82.4%。剩下的才是真正的输入输出 token。智能体每完成一轮工具调用,就把一大段观测结果写进历史;历史越来越长,缓存越来越贵,最后一次读取的钱比前面所有轮次加起来还多。

清华与香港中文大学团队给出的方案叫 AKV,全称 Cache Engineering for Agents,论文 2026 年 10 月 20 日挂上 arXiv,代码以 Apache-2.0 开源,仓库创建于 9 月 28 日,到 10 月 26 日已积累 129 个 star 和 15 个 fork。

它和市面上大多数做法最不一样的地方在于:不去改文本历史,改文本历史就要重算,不改文本历史就没法省。这篇把 AKV 的机制、实测数字和服务端实现拆开讲清楚。

上下文工程的两难:省了钱就丢了分

传统做法叫上下文工程。轨迹长了就修剪或总结历史。问题在于,一旦改了前缀,后面所有 KV 状态全部失效,保留下来的后缀必须重新预填充一遍。这笔重算成本会吃掉省下来的空间,所以框架往往在靠后的轮次才敢动手做激进总结,代价是中间轮次的细节先丢了。

论文在 GPT-OSS-120B 上做了 100 道 BrowseComp-Plus 任务、每题 4 次试验、最多 100 轮智能体回合的对照,结果分成两种情况。修剪式上下文工程只保留最近 12 轮工具响应,成本是全上下文基线的 1.85 倍,也就是说又贵又没省下来。总结式上下文工程用 48K token 阈值触发摘要,成本降了大约 7%,但准确率掉了 5 个百分点。

两种常见做法,一个两头不占。论文把这叫做 re-prefill 成本与任务准确率之间的两难,并且给出了一条第三条路。

直接丢弃旧的工具响应缓存,保留部分可以直接复用,不需要重新预填充。准确率和成本同时改善。这里还有个细节:被丢弃的历史可能已经参与过保留部分的计算,保留的 KV 里其实已经隐含了那些信息。

三个缓存操作:append、drop、repos

AKV 定义了三个基本操作,直接操作缓存,不重写逻辑 token 序列。

append 是标准更新,处理新 token 并把它追加到缓存尾部。位置编码索引从零开始,每次 append 加一,repos 可以重置下一个索引。

drop 把选定的 KV 状态从后续注意力里移除,同时保持保留状态、它们的位置编码和逻辑 token 序列不变。操作对象是一组活跃的逻辑 token 索引,移除后保留条目的顺序不变。

repos 是关键的一步。它用 RoPE 旋转把保留的 key 重写到 0 到 r-1 的连续位置上,value 保持不变。数学上写成 K 变成 R(q)R(p) 的逆再乘 K。因为只旋转 key 不动 value,也不需要重算隐藏状态,这一步的代价远低于重新预填充。

论文把一串这样的操作定义成缓存操作序列 o(1:m),每个元素取自 append、drop、repos 三种。这个形式化的意义在下一节会变得关键。

历史依赖:为什么前缀匹配不够用了

AKV 论文里最值得单独拎出来的一节,是它指出了一个朴素做法会踩的坑。

同样的 token 序列,在不同的缓存操作历史下会产生不同的缓存状态。论文构造了三条轨迹做对照:轨迹一先 append A 和 B 再 drop A 的 KV;轨迹二先 drop A 的 KV 再 append C;轨迹三从 B 单独开始再 append C。三条轨迹最终都保留了 B 和 C。

但 B 的 KV 在轨迹一和轨迹二里相同(两者都以 A 为条件计算),在轨迹三里不同(没有前缀)。C 的 KV 在三条轨迹里全都不同:轨迹一是在 A 和 B 都在场的情况下算出来的,轨迹二和轨迹三虽然都看不到 A,但用了不同的 B 缓存。

结论很直接。普通的 radix tree 前缀匹配,只看 token 前缀,会把不同操作历史产生的状态误认为可复用,从而复用出错误的缓存。要正确复用和恢复,token 历史和缓存操作历史两者都必须记录。

这一点对部署的含义是实打实的。AKV 的服务端接口因此要求每个请求完整描述它所使用的缓存状态,不依赖上一轮遗留的物理缓存。这样即使内存压力导致缓存被驱逐,也能在下一次请求里完整恢复。论文明确写道,服务端必须保证每个请求的输出分布不受物理缓存驻留和别的请求的缓存操作影响,即便多个请求共享同一个前缀缓存,drop 也只能影响发起请求自己的注意力。

AKV 服务端:扩展 radix tree 与 drop 感知驱逐

AKV 分成智能体侧和服务端两侧。智能体侧的 akv.agent 负责决定丢哪些消息、什么时候压缩位置;服务端的 akv.system 负责在 SGLang 的 OpenAI 兼容接口上执行这些操作,同时复用兼容的 KV 缓存。

服务端要同时保住三个传统性质:等价才复用、驱逐不影响请求隔离、被驱逐的状态能靠一次预填充恢复。对应三个挑战,论文给了三件工具。

挑战 AKV 的解法 具体机制
token 前缀不再唯一决定缓存状态 扩展 radix tree 插入 drop 节点,记录被丢弃的逻辑 token 索引,保留前缀共享的同时区分后续状态
一个请求丢弃的缓存可能仍被别的请求需要 drop 感知驱逐 只有在没有活跃计算或恢复需要时才可回收,缓存条目与请求生命周期绑定
普通因果预填充复现不出 drop 与 repos 后的状态 segment-batch attention 用一次预填充恢复被驱逐的状态

接口设计得相当克制。AKV 扩展标准消息体,加一个可选的 cache 字段:drop 的键是消息索引,值是要丢弃的消息索引列表;reposition 列出在哪些消息之后执行 repos。消息索引从零开始,同一边界上 drop 先于 repos。messages 里的每一条都隐含一次 append 操作。仓库里同时提供了一个 sglang.patch 补丁,以及基于 Rust 扩展的实现。

实测:三个模型四个基准的成本与分数

主实验用 GPT-OSS-120B(5.1B 激活)、MiniMax-M2.7(230B 总参数、10B 激活)和 MiroThinker-1.7-Mini(30B 总参数、3B 激活)三个模型,跑 BrowseComp-Plus、GAIA-Text、SWE-Verified、xbench-DeepSearch 四个基准。成本按 Groq 和 MiniMax 的官方 token 单价折算成美分,repos 操作的 token 按缓存命中价计费,属于刻意高估的保守算法。

GPT-OSS-120B 的结果最能说明问题。

方法 BCP 分数 BCP 成本 GAIA-Text 分数 GAIA 成本 SWE 分数 SWE 成本 xbench 分数 xbench 成本 平均分数 平均成本
Standard 57.5 13.1 68.0 5.4 40.0 20.0 38.5 6.2 51.0 11.2
Text Engineering 52.7 12.6 65.1 6.8 36.8 15.8 38.5 5.4 48.3 10.2
AKV 61.9 11.4 69.9 4.1 43.2 9.7 37.5 3.8 53.1 7.3

平均分数从 51.0 涨到 53.1,平均成本从 11.2 美分降到 7.3 美分,分数涨 2.1 分而成本降 34.8%。SWE-Verified 上成本从 20.0 美分掉到 9.7 美分,降幅超过一半。

另外两个模型的表现有一个值得注意的分歧。MiniMax-M2.7 上标准方案的分数是 58.9、文本工程是 62.3,AKV 是 58.9,没能超过文本工程;MiroThinker-1.7-Mini 上标准方案只有 44.1 分,AKV 做到 45.8。论文把 MiniMax 的这个落差归到最差情况,具体机制没有展开。

主表之外还有一组 20 任务的子集实验,AKV 平均 45.2 分对标准方案 44.0 分,文本工程只有 38.2 分。成本上 AKV 4.8 美分,标准 6.2 美分,文本工程 4.6 美分。

服务端性能:高并发下优势扩大

效率数据来自 GPT-OSS-120B 在 SWE-Verified 的 Top-80 任务上,8 张 A800-80GB,4 张预填充 4 张解码,张量并行度 4,全部 BF16 权重,静态显存比例 0.85,KV 页大小为一个 token,预填充分块 8192 token。

并发 方法 请求延迟均值 TTFT 均值 TPOT 均值 输入吞吐 输出吞吐
8 Standard 12.16 3.18 26.57 25200 217
8 Text Engineering 12.84 4.94 23.23 17313 228
8 AKV 7.79 1.87 23.50 39227 245
12 Standard 12.39 2.97 28.00 33832 313
12 Text Engineering 16.83 8.86 23.24 19945 264
12 AKV 8.47 2.60 23.06 48923 339
16 Standard 36.50 27.71 24.83 10866 138
16 Text Engineering 23.00 14.48 24.44 19595 267
16 AKV 10.32 4.16 24.84 50817 369

并发 16 这一行最能说明问题。标准方案的请求延迟 P95 冲到 229.90 秒,输入吞吐掉到 10866;AKV 的延迟 P95 是 30.63 秒,输入吞吐 50817,输出吞吐 369 对 138。

论文把效率提升拆成两块。同批大小下,AKV 把全注意力耗时压掉 59.8%,总解码步耗时压掉 16.0%,原因是丢弃旧的工具响应 KV 缩短了活跃上下文,后续解码步从显存读的 KV 更少、做的注意力计算更少。成本侧,缓存读取成本相对标准方案降约 17%,相比文本工程方案,缓存未命中输入成本降约 48%,因为 AKV 直接复用保留的 KV,不需要总结改写历史后重新预填充那一步。

有意思的是活跃上下文长度的曲线形状。标准方案在达到 96K 摘要阈值前一直堆积历史,触发摘要时上下文长度陡降;AKV 的活跃上下文因为推理内容持续累积仍在增长,只是慢得多,工具响应部分被持续丢弃。这说明 AKV 省的主要是缓存读取和重复预填充,而不是让上下文彻底不长。

消融:丢什么、什么时候重定位

丢的目标选谁,repos 用不用,两组消融给出了答案。

策略 启用 repos BCP 分数 BCP 成本 SWE 分数 SWE 成本
Standard 否 56.0 13.5 41.0 19.1
仅丢工具响应 否 55.0 7.1 41.0 9.4
仅丢推理内容 是 56.5 8.2 36.5 14.2
两者都丢 是 56.5 8.7 34.5 7.8
仅丢工具响应 是 62.0 10.9 41.0 9.5

加了 repos 之后,BCP 通过率从 55% 升到 62%。论文解释是 repos 让探索能越过原本会终止执行的位置限制。同时丢推理内容会拉低两个基准的通过率,说明推理轨迹本身比工具结果更不该被丢。

这和注意力分布的实测是对上的。论文分析了 10 条 BrowseComp-Plus 轨迹里每个 token 的注意力密度,按层和消息索引做平均,划分为旧推理、旧工具响应和近期历史。旧工具响应在多数层获得的注意力少于旧推理,而近期历史普遍更高。这给滚动丢弃工具响应提供了经验依据,也解释了为什么丢推理内容会掉分。

两个延伸方向:让模型自己优化策略,以及把缓存管理做成工具

论文还试了两件更进一步的事。

一是递归自我改进。用 MiniMax-M2.7 在 20 道 BCP 任务上迭代优化缓存策略,再到 100 道留出任务上评估。第 3 轮和第 6 轮产出的策略,相对标准方案每任务成本分别降低 15.6% 和 17.8%,同时保持标准方案的准确率。策略由模型自己写出来,论文声称这是递归自我改进的一个实例。

二是把缓存管理暴露成工具,让智能体自己决定什么时候缩减缓存、保留什么。效果最好的一行数字出现在这里:GPT-OSS-120B 在 100 任务 BCP 子集上得分 61.0,MiniMax-M2.7 得分 64.0,都高于标准方案和文本工程方案。成本侧 GPT-OSS-120B 从 13.4 美分降到 12.1 美分,MiniMax-M2.7 从 5.4 升到 5.9 美分,因为执行了更多轮次。

仓库里的 CachePolicy 用三个组件表达这套策略:trigger 决定什么时候触发,selector 决定保留什么,reposition 决定什么时候压缩位置。README 里的示例用的是 TurnTrigger、TurnSelection(1) 和 TurnReposition,保留最近一轮完成的工具结果。

这套思路的边界

值得提醒的是几个边界。

第一,AKV 的服务接口扩展了标准 API,需要客户端配合声明缓存操作历史。现成的智能体框架要适配这套接口才能用上,仓库里的 sglang.patch 是必要的一环,不是可选优化。

第二,repos 通过旋转 key 重写位置编码,这个操作在论文里被明确按缓存命中价计费,属于刻意高估。换句话说真实的成本优势可能比表里更大,但表里的数字已经偏保守。

第三,MiniMax-M2.7 上 AKV 没能超过文本工程方案,说明这个方法不是每个模型上都灵。论文把它归为最差情况但没有展开机制。

第四,缓存工程省的是读取和重复预填充,活跃上下文仍在随推理内容增长。超长轨迹仍会撞上模型的最大上下文长度,AKV 没有解决这个上限问题。

把 AKV 放进国内推理框架的语境看,它和 llm-d 1.0 在 17000 节点上的调度优化、DeepSeek 开源 DeepInfer 推理框架解决的是不同层级的问题。前两者优化集群和算子层的效率,AKV 优化的是单个请求在服务端怎么管理缓存。两者可以叠加。

小结

AKV 最有价值的贡献是把缓存从黑盒变成可编程对象,并且诚实地暴露了这样做的代价。历史依赖这个问题是绕不过去的,同样的 token 在不同操作历史下状态不同,前缀匹配不再可靠,服务端必须带上操作历史一起管理状态。

82.4% 的成本来自缓存读取,这块占了智能体账单的大头。AKV 在三个模型四个基准上把平均成本压下 27.7%、分数提 1.7 分,代价是客户端和服务端都要适配一套新接口。

常见问题

AKV 和上下文工程的区别到底在哪?

上下文工程改的是文本历史,改完前缀就得重新预填充,论文实测这类方案要么更贵(修剪式成本是基线的 1.85 倍)要么掉分(总结式降 7% 成本、掉 5 个百分点)。AKV 不动文本,只操作缓存,保留部分直接复用,无需重算。

repos 是什么意思,为什么它关键?

repos 用 RoPE 旋转把保留的 key 重写到连续的位置上,value 不动。它让被丢弃条目留下的空位不浪费,同时避免重新预填充。加了 repos 之后 BCP 通过率从 55% 升到 62%。

这个方法能用在现有的智能体框架上吗?

需要适配。AKV 扩展了服务接口,客户端要声明 drop 和 reposition 操作历史,仓库提供 sglang.patch 修改 SGLang,也提供 Rust 实现的扩展。不改客户端的话,拿不到直接复用缓存这部分收益。

相关阅读