简介:本文从推理系统底层出发,对比精确前缀缓存与语义缓存两套机制的差异,拆解KV Cache复用规则如何影响token计费,并给出自建推理引擎与托管API在缓存实现、成本结构、运维复杂度上的选型依据,帮助读者理解cached_tokens字段背后的技术约束与优化空间。
一个Agent任务跑完,模型被调用了上百次,每次请求都重发几十万token的完整对话历史,账单却没有成比例膨胀。原因记录在用量接口的一个字段里——不同厂商叫法不同,有的叫cached_tokens,有的叫cache_read_input_tokens。对Coding Agent的实测显示,Agent单步的典型形态是读取约119K token的历史前缀,只对新增的约875 token做完整计算,前者绝大部分按普通输入十分之一左右的价格计费。
这个字段背后是推理系统的一条底层规则,API定价、显存管理、集群调度、Agent框架设计全部落在它的约束之下。而围绕”如何复用已计算的中间状态”,业界实际存在两套截然不同的机制:精确前缀缓存与语义缓存。前者是推理引擎层面的KV复用,后者是检索系统层面的答案复用。二者经常被混为一谈,但在命中条件、成本结构、正确性风险和适用场景上差异巨大。本文围绕这两类机制展开对比,并进一步对比自建推理引擎与托管API在缓存能力上的实现路径差异。
自回归模型每生成一个token前,要对整个输入做一次前向计算,这一步叫prefill。prefill会在每一层为输入的每个位置生成两份张量,即Key和Value,合称KV Cache。后续token的Query直接检索这些已有的K和V,历史部分的中间结果不必重算。KV Cache的物理本质就是这段前缀已经算出的中间状态。
KV Cache能跨请求复用,靠的是因果注意力的一条性质:第i个位置的K和V只由它之前的token决定,同一个词接在不同的前缀后面,算出的张量完全不同。由此得到缓存匹配的硬规则:只有从第一个token起逐个相同的前缀才能复用,序列中任何一处不同,其后的所有KV全部作废。语义上再接近的两个prompt,只要token序列不一致就完全不命中。
市面上另有按语义相似度直接返回旧答案的语义缓存。它属于检索系统:将历史请求与答案做向量化索引,新请求到来时先检索最相似的历史问题,超过阈值即直接返回旧答案,完全不经过模型推理。其正确性取决于检索质量——相似不等于等价,阈值调高会漏命中,调低会答错。
两套机制的本质区别可以用一句话概括:精确前缀缓存复用”算到一半的中间状态”,语义缓存复用”已经给出的最终答案”。
尽管机制不同,两者在目标层面存在共性:
精确前缀缓存的命中条件是逐token完全一致,从第一个token起比对,任何一处不同即全部失效。这意味着system prompt末尾多一个空格、时间戳写在开头、工具定义顺序变化,都会导致整段前缀作废。语义缓存则允许措辞不同但语义接近的请求命中,条件宽松得多,但代价是正确性风险。
精确前缀缓存不改变模型输出分布——它只是跳过重复的prefill计算,数学上与不缓存完全等价,不存在答错风险。语义缓存则直接返回旧答案,如果两个问题语义相似但实际需要不同答案(例如同一句话在不同上下文下含义不同),就会产生错误响应。这是两者最根本的分界线:一个是计算优化,一个是答案复用。
精确前缀缓存的收益体现在输入token单价上:命中部分按普通输入价格的十分之一左右计费(具体比例因厂商而异),输出始终按输出价计费。语义缓存的收益是整次请求都不发生——既不消耗输入token也不消耗输出token,但需要额外承担向量化、索引存储与检索计算的开销。
精确前缀缓存实现在推理引擎内部,涉及显存分块管理、前缀树索引、调度器配合,属于模型服务的基础设施。语义缓存实现在应用层或网关层,涉及嵌入模型、向量数据库、相似度阈值策略,与推理引擎解耦。两者的运维主体、故障域和调优手段完全不同。
精确前缀缓存要求Agent框架尽量保持前缀稳定:system prompt固定、工具定义顺序固定、历史消息只追加不修改。这直接约束了上下文管理策略——任何”重写历史”的操作(如摘要压缩、消息重排)都会导致缓存全部失效。语义缓存则对框架无特殊要求,但需要框架接受”可能返回旧答案”的风险。
| 维度 | 精确前缀缓存 | 语义缓存 |
|---|---|---|
| 缓存内容 | KV中间张量 | 历史问答对 |
| 命中条件 | 从首token起逐位一致 | 语义相似度超阈值 |
| 正确性风险 | 无,数学等价 | 有,取决于检索质量 |
| 实现位置 | 推理引擎内部 | 应用层/网关层 |
| 成本收益 | 输入token单价降低 | 整次请求不发生 |
| 额外开销 | 显存占用、前缀索引维护 | 向量化、索引存储、检索计算 |
| 对框架约束 | 前缀必须稳定 | 无特殊约束 |
| 失效触发 | 前缀任何一处变化 | 索引过期、阈值调整 |
多轮对话的复用建立在精确前缀规则之上。客户端每一轮仍然发送从system prompt到最新消息的完整历史,服务端没有少收任何token。差异体现在服务端的实现方式上。
在自部署引擎中,上一轮算过的输入KV在请求结束后留在显存,生成阶段的输出KV续接在同一条序列上,下一轮请求的前缀与此完全一致,命中范围能一直延伸到上轮回复的末尾,引擎只对新追加的尾部做prefill。这类引擎的地基通常是分页式注意力管理:KV显存被切成固定大小的块(典型值16 token),请求按块申请,逻辑块表映射到不连续的物理块,显存碎片问题就此解决。前缀复用则通过前缀树索引实现——相同前缀的请求共享同一批物理块,引用计数归零后才释放。
自建路径的特点是:缓存策略、块大小、淘汰规则、显存配额全部可调,但需要团队自行承担容量规划、监控告警、故障恢复与版本升级。
云API用断点和计费字段对外呈现同一件事:文档描述的缓存对象是已渲染前缀对应的KV张量,本轮输出始终按输出价计费,上一轮的回复要到下一轮作为输入重发时才进入缓存范围,实际命中多少以usage字段为准,相同输入也不保证相同输出。托管路径把显存管理和调度细节隐藏起来,开发者只需保证前缀稳定,但可调参数有限,缓存保留时长、最小可缓存长度等边界由服务方定义。
选型时应围绕三个问题判断:前缀是否稳定、正确性容忍度如何、团队是否具备显存运维能力。
若前缀稳定且正确性要求高,精确前缀缓存是必选项;若团队运维能力有限,优先选择托管API并把精力放在请求构造优化上;若已有自建集群且请求规模可预测,自建路径在长期成本上更具弹性。语义缓存只建议作为精确缓存的补充,且必须评估检索质量与兜底策略。
迁移时需注意:从托管切自建,要重新评估显存容量与前缀树的内存开销;从自建切托管,要确认缓存保留时长与最小可缓存长度是否满足业务前缀长度;无论哪个方向,都要检查Agent框架是否存在重写历史、重排消息、动态插入时间戳等破坏前缀一致性的行为——这些行为在迁移前后都会让缓存命中率归零。同时关注计费字段的口径差异,命中量的统计方式可能不同,成本预估需以实际usage字段为准。
精确前缀缓存与语义缓存的分野在于:前者复用中间计算,数学等价、无正确性风险,但命中条件严格;后者复用最终答案,收益更大但引入答错风险。在精确前缀缓存内部,自建推理引擎与托管API又构成一组对比:前者可控性强、长期成本弹性大,后者运维负担轻、接入快。理解”只有从首token起逐位一致才能复用”这条硬规则,是设计缓存友好型Agent框架、评估token账单、做出合理选型决策的共同前提。