多轮 Agent 推理,怎样让上一轮的 KV 缓存在下一轮真正复用?

简介: 跨轮 KV 值不值得回读,先看本地还缺多少。

一次工具调用结束,Agent 把结果追加进历史再请求模型继续工作。上一轮处理过的输入和生成内容又出现在下一轮输入里。在 Prefill/Decode 分离部署中,新请求先交给 Prefill,而上一轮生成阶段的 KV 留在 Decode。要减少重复计算,系统需要让这份历史跨过工具等待,并在下一轮计算前到达 Prefill。

这里需要同时考虑两项成本:为等待下一轮而保留 KV 会占用多少缓存资源;下一轮真正需要它时,取得这些状态又要花多久。实践中常见两种保留位置——直接留在 Decode 的设备内存,或先把副本写到主机内存再由 Prefill 获取。两种方式把资源占用与获取延迟放在不同位置。

本文以 vLLM 双向 KV 传输及相关卸载实践「Improve TTFT for Multi-Turn Agentic Workloads with Bi-Directional KV Transfer in vLLM」为观察对象。比较保留与取回的代价之前,先要确定下一轮 Prefill 本地究竟缺少多少历史。

先计算下一轮缺少的历史

假设上一轮输入为 H,Decode 随后生成 R,工具返回的新增输入为 T。在聊天模板保持旧 Token 序列一致的情况下,下一轮输入可以表示为 H + R + T。

Prefill 是否仍保留 H 对应的 KV,直接影响下一轮需要取回或重新计算多少历史。如果本地仍能命中 H 对应的 KV,就不需要重新计算这部分输入;此时,可以尝试从 Decode 取回 R 中已经计算、但 Prefill 尚未持有的 KV,新增的 T 则仍需本地计算。如果 H 对应的本地 KV 已被淘汰,那么 H 也进入需要从远端取回或重新计算的历史范围。

在 vLLM 的双向 KV 传输实现中,调度阶段会先扣除本地已覆盖的部分。设本轮输入长度为 N,Prefill 本地已覆盖 L 个 Token,Decode 宣告的可复用范围为 C,那么候选的额外远程复用量为:

M=max⁡(0,min⁡(C,N)−L)

该计数建立在远端状态确实对应当前输入前缀的前提上,实际读取还需要映射到可传输块。

用一组假设值看这次决策:当前输入有 19,456 个 Token,Decode 可提供前 18,432 个,还有 1,024 个 Token 未被远端提供的范围覆盖。

同一份 Decode 历史,在两种本地状态下对应相差九倍的远程复用量。判断读取是否划算时,应比较这些增量各自的读取与重算时间。

以候选增量为 2,048 Token 的情况为例,它超过了默认的 64-token 门槛,因此可以形成读取候选。之后仍需满足实际读取条件,元数据有效、块仍在 TTL 内、前缀对齐等。成功加载后,远端范围之外的 1,024 个 Token 继续由 Prefill 本地计算。若候选增量只有 32 Token,则在默认门槛下不被计作远程加载,直接走本地计算路径。

以候选远程复用量为 2,048 Token 为例(假设块大小为 16 Token,约对应 128 个块)。

  • 设备**内存**回读路径:定位来源与连接建立、NIXL 读取、完成后对剩余 1,024 Token 的本地计算。总耗时 ≈ 定位与读取耗时 + 剩余计算耗时。

  • 直接重算路径:2,048 + 1,024 = 3,072 Token 全部由 Prefill 本地计算。 当定位与读取耗时 + 剩余计算耗时 < 全量重算耗时 时,读取更优。CPU 副本路径还需额外计入对等传输与设备加载时间。

注:以上为结构示意,具体数值需按模型、硬件与网络实测。

这会改变保留成本与复用收益之间的关系。在这个例子里,即使 Prefill 只缺 2,048 个历史 Token,Decode 仍可能保留覆盖更长历史的块。实际显存占用应按被额外保留的物理块计量,并考虑共享前缀。会话总长度、额外可省的重算量和实际占用的显存,是三项不同的数据。

工具执行期间决定保留位置

保留与读取发生在两个不同的时点。保留决策发生在上一轮结束时。此时系统只知道本次生成了哪些块、当前缓存压力,以及可能的下一轮等待时长,并不知道下一轮 Prefill 本地会覆盖多少。因此,上一轮的 TTL 或 CPU 卸载决策,只能基于“可能被复用”的预期,而不能依赖下一轮实际的候选远程复用量。

读取决策发生在下一轮请求到达 Prefill 之后,此时本地覆盖已确定,才能计算出候选远程复用量,并与阈值比较,决定是否发起读取。

设备内存路径可以直接利用 Decode 刚生成的 KV,以下按 v0.29.0 文档中的 CUDA device-buffer 双向模式讨论,P、D 两端均需启用 bidirectional_kv_xfer。正常结束请求时,NixlConnector 延后释放相关块,并导出块位置、已计算 Token 数与到期时间。decoder_kv_blocks_ttl 控制这次延后释放的期限,默认 480 秒。

工具等待较短、旧块仍能保留时,下一轮可以直接从设备上的已有状态读取。随着等待会话增加,这些已经停止生成、却仍在等待取用的块,也会占用缓存池。延长 TTL 会扩大等待下一轮的窗口。若会话迟迟没有发起读取,也会延长相关块被额外保留的时间;若预期消费者已读完并完成通知,延后释放可以提前结束。评估驻留成本时,应记录被额外保留的物理块和实际持有时长。

主机内存副本提供了另一种保留方式:先把 KV 写到 CPU 内存,后续复用不再要求原来的设备页一直为它保留。它增加写出和恢复过程,换来设备缓存被回收后仍有副本可找的机会。vLLM 的 CPU KV 卸载实践「Inside vLLM's New KV Offloading Connector: Smarter Memory Transfer for Maximizing Inference Throughput」将写出设计为异步操作,读回则仍需在相应状态被使用前完成。

本文所引 CPU P2P 路径依据 llm-d dev 文档,该路径目前标为实验性;使用时需确保引擎与路由组件版本相互兼容。

跨轮场景还有一个容易遗漏的条件:CPU 副本是否包含生成阶段的 R。只保存输入 H,在 Prefill 本地已经命中 H 时,无法补上本轮真正缺少的生成历史。llm-d 的 Prefill/Decode 点对点指南因此要求 Decode 使用 offload_prompt_only=false,并配合能够保持生成序列一致的聊天模板。

CPU 也有容量边界。所核对的分层实现使用可配置的缓存替换策略,默认最近最少使用;旧副本可能因后续访问和容量压力被淘汰。v0.29.0 的卸载连接器还将保存视为尽力而为:一次保存未能完成,会减少后续命中机会,不能把“启用了卸载”直接当成“历史已经存好”。

因此,工具等待时间需要和缓存层的实际保留行为一起观察。短等待也可能遭遇设备内存压力;长等待也不保证 CPU 副本仍在。评估时重点看状态能否跨过等待、被额外保留的物理块数量与持有时长。

Prefill 定位并取得历史状态

设备内存路径使用上一轮导出的具体位置。多轮路由器按 conversation_id 保存 Decode 的 kv_transfer_params,在下一轮将它们交给 Prefill。Prefill 知道来源引擎、请求、块 ID 和连接地址后,发起 NIXL 读取,将可复用 KV 读入本地接收位置,再处理剩余输入。路由器只负责请求与元数据,KV 不经过路由器。

CPU 副本路径需要找到仍持有相应前缀的来源。llm-d 的跨 P/D 配置通过多连接器组合常规 NIXL P/D 交接与卸载连接器/P2P 层。缓存事件索引用于定位候选源,来源信息被传给实际执行 Prefill 的实例;该实例请求需要的块,源端确认可提供的部分,再完成对等传输。

两条路径的搬运位置不同:

图注:设备内存路径由 Prefill 直接发起 NIXL 读取;CPU 副本路径需先卸载、对等传输再加载到设备。

CPU 路径中的对等传输发生在主机内存之间。消费者发起获取请求后,源端通过 NIXL 写入匹配数据;目标侧还需经 CPU 缓存加载到设备,模型才能使用。分层实现将 CPU 主层作为外部数据进入 GPU 的入口。

这使两种定位方式承担了不同的条件。设备路径依赖上一轮那组位置仍有效;CPU 路径依赖索引可见、块仍存在且能够匹配。连接地址正确并不足以证明内容可复用,CPU 路径还要核对块大小、哈希与 KV 布局的兼容性。

以 vLLM 的设备回读路径为例,上一轮 Decode 在生成结束后保留可复用状态,并向路由器返回位置元数据。工具返回、下一轮请求到达后,路由器将旧来源信息交给 Prefill;Prefill 完成本地匹配,计算候选增量并形成远程加载候选,工作进程再在实际读取前检查到期等条件。上一轮 KV 的来源 Decode 与本轮生成目标 Decode 可以是不同节点。

两条路径最终都需要让历史状态在 Prefill 设备上就绪,再由 Prefill 处理未被覆盖的输入,随后完成本轮 P→D 交接并进入生成。

按实际路径校准读取阈值

沿上述路径取回历史状态,需要与直接重算作同条件比较。回到第一节的例子,本地命中充分时只缺 2,048 个历史 Token,本地缓存丢失时则缺 18,432 个。更大的候选范围提供了更多减少重算的机会,也需要搬运更多 KV。它是否值得读取,还取决于模型的重算成本、KV 数据量和传输路径。

设备回读需要定位来源、必要的连接建立与元数据协商、读取和完成等待;CPU 副本路径还涉及源副本可用性、对等传输与目标侧设备加载。CPU 写出可以提前进行,但这项后台工作仍消耗带宽和容量。评估下一轮的等待时,需要区分已经提前完成的工作,以及请求到达后仍必须等待的部分。

vLLM 的 kv_recompute_threshold 默认 64 Token,在调度阶段对额外远程复用量作判断。低于阈值的增量不被计作远程加载。

CPU P2P 的来源选择使用 minCachedTokenDelta:候选源相对目标实例多覆盖的前缀,达到相应条件后才触发获取。其校准指南在 gpt-oss-120b、H200、RDMA/IB 参考配置上给出 2,048 Token;其他模型、硬件和传输条件需要重新测量。这个索引侧决策之后,引擎还需确认实际块是否可用。

64 与 2,048 作用于不同实现、不同阶段和不同路径,不能直接拿来比较方案效率。对于同一组请求,需要对照的是:相同的本地命中范围下,取得额外历史到可用于计算所花的时间,与直接重算这段历史的时间。阈值的作用是在调度阶段过滤掉明显不划算的小增量;最终是否读取,仍取决于实际读取条件是否满足。

同时记录等待占用与下一轮工作量

先固定一组真实的跨轮请求,保留其 Token 前缀、每轮新增内容与工具等待分布。只看总输入长度,无法区分第一节中 2,048 与 18,432 个远程候选 Token;只看下一轮延迟,也无法说明前一段等待占用了多少缓存。

对设备路径,需要确认上一轮是否导出元数据、块在读取时是否仍有效,以及 Prefill 实际读回多少。示例路由器的记录有效期为 450 秒,设备块默认保留期限为 480 秒。在透传了远端到期时间的双向回读中,工作进程还会在读取前检查到期风险;排队和连接建立也会消耗剩余窗口。因此,路由器侧的缓存命中仍需结合实际读取完成记录判断。

对 CPU 路径,需要把生成历史的保存、后续存活和再次命中分开记录。主机层的字节数、命中范围以及设备加载时间,才能说明副本是否补上了本轮缺口。

跨轮历史发生变化时,还要区分两种定位方式。对沿用上一轮块位置的 NIXL 回读,若摘要或剥离推理痕迹使旧状态与当前输入不再对应,上层应停止使用不适用的旧传输参数,避免读取错误位置的 KV。

CPU P2P 则按当前请求所需块的前缀哈希查找。哈希包含前序上下文,发生变化的部分不能继续匹配旧前缀,仍一致的较早前缀可能继续复用;正常查找未命中的部分由引擎计算。

性能证据也应保留原来的比较条件。vLLM 的双向传输实验使用一 Prefill 一 Decode 部署、Amazon EC2 P5en 实例与 AWS 弹性网络适配器,关闭 Prefill 本地前缀缓存来模拟缓存丢失;在 GLM-5-FP8、20K 输入的测试点,TTFT 从 2,334 毫秒降到 702 毫秒。它支持对应配置中以远程回读替代重算的收益。

llm-d 的跨 P/D 测试「Pull,Don't Recompute: Peer-to-Peer KV Cache Sharing in llm-d」则报告,在 2P4D、每 Pod 一张 H200、拉取阈值为 1,024 Token 的配置中,Llama-3.1-8B 移动了历史 KV、释放出 Prefill 计算容量,但 TTFT 接近持平。该对照同时加入了 CPU 卸载层与对等获取,效果应归于这组改动。

这两个结果提示需要分别衡量“减少了多少计算”和“请求提前返回了多久”。前者可能换来更多服务容量,后者还受到读取、恢复与排队影响。验证时同时记录等待期间的占用与下一轮实际取回量,能更清楚地判断在当前负载下,设备块保留、CPU 副本还是直接重算哪条路径更合适。

相关文章
|
2月前
|
机器学习/深度学习 人工智能 弹性计算
周一上线|谷歌利用果蝇实现“AI 突围”?Cognition 再融 20 亿美元;AI 三巨头集体呼吁放慢脚步
本周AI圈聚焦Agent能力跃迁:SWE-2压缩无效探索,Muse实现后台自主推进,DeepSeek V4.1-Flash以新CED架构将KV Cache压至1/4,大幅降本增效;HyperFrames让Agent“写视频”,Marketing Skills拓展至营销全链路;Cognition融资超20亿美元,OpenAI因Astra火爆暂停Pro新订阅。
275 1
周一上线|谷歌利用果蝇实现“AI 突围”?Cognition 再融 20 亿美元;AI 三巨头集体呼吁放慢脚步
|
3月前
|
存储 Shell API
拆解 dsh 系列:从源码和版本变化看 DeepSeek Harness 的设计取舍
DeepSeek Harness(dsh)发布仅两周,实则历经两个月内部打磨。本文基于Git历史与npm发布数据,梳理其从0.0.1-rc.1到0.1.1-rc.2的演进:命名重构、定位升维(Coding Agent→Agent Harness)、核心与扩展边界持续厘清,展现一个开源智能体运行时如何审慎定义自身能力疆界。
438 1
拆解 dsh 系列:从源码和版本变化看 DeepSeek Harness 的设计取舍
|
3月前
|
存储 JavaScript 安全
dsh 拆解系列 Vol.01:没有特权内核的 Agent 运行时
DeepSeek Harness(dsh)是DeepSeek开源的Agent运行时框架,秉持“一切皆插件”理念,将模型适配器、工具、会话、主循环等全部解耦为可配置、可替换、可卸载的插件,基于Cordis元框架实现时空可组合性。当前v0.1.0-rc.7为开发者预览版,MIT协议,强调工程可扩展性而非仅功能堆砌。
483 2
dsh 拆解系列 Vol.01:没有特权内核的 Agent 运行时
|
2月前
|
存储 人工智能 自然语言处理
Codex 实践系列 Vol.05:长任务里的事实、边界和验收
本文以真实内部工具项目为例,探讨如何为AI编程助手Codex制定有效规则:将确认的事实写入SPEC.md、任务拆解与验收标准纳入TASKS.md;强调“先读规矩再编码”,通过硬性边界(如禁止覆盖公式列、遇人机验证即停)、可验证的验收条件(用真实样例校验结果)及最小完整流程验证,确保输出可靠。
150 1
|
2月前
|
前端开发 测试技术 API
论文解读|从经验到 Skill:Agent 的能力沉淀机制
WikiSkill 分层管理经验与 Skill,让历史知识持续参与演化
245 0
|
3月前
|
存储 Shell 数据库
Agent 小知识|长任务不重来:Agent 状态保存的工程设计
本文详解Agent状态的核心概念与工程实践:它不是简单记忆,而是任务执行的实时快照,涵盖进度、环境、内部判断与资源约束。通过结构化Schema、分层检查点和状态栏机制,实现可靠暂停恢复、高效决策与长程连贯性。
345 0
Agent 小知识|长任务不重来:Agent 状态保存的工程设计
|
3月前
|
人工智能 安全 前端开发
实测推荐 3 个 Skill,轻松上手 Codex 网页设计与交付流程
小七实测3个前端Skill:`design-taste-frontend`强化设计规范与双主题支持,`humanizer`去除AI腔、优化文案自然度,`better-interface`完成可访问性等交付级审查。结果表明——当Agent基础能力已强,Skill核心价值转向固化专业标准、流程与质量门禁。
410 0
|
3月前
|
人工智能 缓存 安全
DeepSeek V4-Flash 正式版接入 Codex,OpenAI 新模型 Astra 浮出水面,Google DeepMind 明星团队被拆
本期「周一上线」聚焦AI两大演进方向:模型加速迈向多模态与机器人,Agent则从“写代码”升级为长期协作、端到端交付与自我改进。DeepSeek V4-Flash、MiniMax H3、Gemini Robotics 2等密集发布,OpenAI Astra、Lilian Weng的RSI团队、贾扬清Intent Lab齐探AI自主进化;行业层面,AlphaFold团队拆分、字节整合飞书/豆包/火山引擎,技术与组织同步重构。
330 1
DeepSeek V4-Flash 正式版接入 Codex,OpenAI 新模型 Astra 浮出水面,Google DeepMind 明星团队被拆
|
4月前
|
SQL JSON 安全
Agent 小知识|让 Agent 调对工具:输入输出契约的设计
本文详解Agent工具调用的输入输出契约:输入契约规范工具名称、描述、参数Schema与使用边界,确保模型准确调用;输出契约定义结构化结果、状态码与错误反馈,支撑模型可靠决策。二者共同保障Agent“思考→行动→判断”闭环的稳定性与可解释性。
256 0
Agent 小知识|让 Agent 调对工具:输入输出契约的设计
|
3月前
|
人工智能 缓存 安全
给 Coding Agent 加上质量门禁:测试如何进入 Agent Loop
本文提出“质量门禁(Quality Gates)”理念,将测试、静态分析等确定性检查嵌入Coding Agent工作流,形成分层验证闭环:修改后触发快速门禁(Lint/类型检查/关联单测),任务完成前执行集成与回归测试,PR阶段由CI进行全量验证。Harness自动接管测试执行与反馈解析,失败结果结构化送回Agent驱动修复,同时通过Hook机制(如PostToolUse、Stop)实现流程管控,兼顾效率与可靠性。
248 0
给 Coding Agent 加上质量门禁:测试如何进入 Agent Loop