长跑型 Agent 的成本大头,已经从“生成”挪到了“反复重算缓存”。这篇名为《Cache Engineering for Agents》的论文给出了一个反直觉但很实用的方案:不让上下文工程去改历史,而是让 Agent 自己管理活跃的 KV 缓存——用 drop 和 repos 两个动作,把不再需要的缓存排除出注意力、把保留下来的位置编码重新摆正,轨迹一个字都不动。实测结果是平均分高 1.7 分、平均成本低 27.7%,配合同步设计的 AKV 服务引擎还能拿到 1.2 倍输出吞吐和 1.5 倍的 P95 延迟改善。

先看清楚旧方案为什么在这里失效

过去一年,处理长轨迹的主流手段是上下文工程(context engineering):修剪历史、把旧对话摘要成一段、或者只保留最近若干轮。它确实能把上下文压短,但代价是两条:

于是出现一个荒唐的循环:为了省缓存而裁剪历史,裁剪导致缓存失效并触发重算,重算又把成本推高。Agent 轨迹越长,这个循环转得越贵。

从系统视角看,这个循环消耗的两样东西值得分开数:一是显存与显存带宽——缓存本身要驻留、要搬运;二是 prefill 的算力——重算一遍保留下来的上下文。论文的判断很明确:随着轨迹变长,KV 缓存的 I/O 与存储已经成为主导成本,而不是生成 token 本身。这也意味着,任何只在“输出更短”上做优化的手段,天花板都很低;真正的杠杆在于“哪些缓存还值得留着参与注意力”。

缓存工程:把 KV 缓存变成 Agent 可控的动作

论文提出的“缓存工程”(cache engineering)换了一个作用对象:不动轨迹,动缓存本身。核心是两个原语:

这个设计的价值在于“可逆性”:轨迹保持只增不改,审计、回放、复现都还成立;但实际参与注意力的缓存可以被裁到很小。对那些动辄几十轮工具调用、每轮输出几千 token 的 Agent 来说,工具返回值恰好是最“一次性”的部分,也正是最该被 drop 的对象。

一个被忽略的服务端难题:历史依赖

论文点出了一个非常工程化的坑,叫历史依赖(history dependence):同样的 token 序列,在不同的缓存操作序列下,会得到不同的缓存状态。

这意味着传统推理服务里最省事的那招——按前缀哈希匹配并复用 KV 缓存——不再可靠。你以为命中了同一段前缀,实际上那份缓存是在另一套 drop/repos 操作下生成的,状态并不相同。前缀相同,语义与数值都不同,复用就是错的。

这解释了为什么作者必须连服务引擎一起设计,而不是只发一个策略:接口层的问题可以在应用层解决,状态层的正确性必须在推理引擎里解决。

AKV 引擎:对外无状态,对内记状态

作者的解法是 AKV:对外暴露与现有 serving API 兼容的无状态接口,调用方不需要改协议;对内则维护有状态的缓存复用、淘汰与恢复。换句话说,把“这套缓存是怎么被操作出来的”这件事,收进引擎内部管理,而不是指望上层每次把操作历史拼进 key 里。

对做平台的团队来说,这是唯一现实的分层方式:应用团队只想说“这段我不要了”,不想关心缓存键怎么构造。

实测数字与可迁移的经验

论文给出的对照实验用的是“工具返回滚动 drop”策略(tool-response rolling-drop),基线是传统的阈值触发摘要(threshold-triggered summarization):

把这套结论搬到自己的 Agent 上,有五个可以立刻落地的判断:

适用范围与局限

需要说清楚的是,这套方法不是纯应用层能拿到的能力:它要求推理服务端支持等价于 AKV 的缓存操作接口,直接调商用 API 的团队暂时用不上。另外 1.7 分是基准平均,不代表每个任务都涨;论文的验证范围也有限,跨模型、跨任务形态的泛化还没有定论。

代码已开放在 github.com/thu-nics/AKV,作者为 Tianyu Fu 等(论文页标注 2026-10-20)。如果你的 Agent 已经长到要按 token 算钱,这篇值得先读摘要再看实现。

原文链接:https://huggingface.co/papers/2610.28577

阅读原文 → 返回 AI 技术文档

内容与图片版权归原作者所有 · 原文: https://huggingface.co/papers/2610.28577