KV Cache 与 Prompt Cache:区别在哪,又有什么关系

🇨🇳🇺🇸

大模型每生成一个 token,都会用到前面的内容。如果每一步都从头计算,回答会慢很多。做 Agent 时,同一套 system prompt、工具定义和对话历史还会被反复携带;如果每次都重新处理,延迟和费用也会不断增加。

这两类重复计算,分别对应两个经常被混淆的概念:KV CachePrompt Cache。模型处理一次请求通常分为 prefilldecode 两个阶段:KV Cache 避免 decode 时重复计算历史 token 的 K/V,Prompt Cache 则让后续请求复用相同前缀的 prefill 结果。

简单来说,KV Cache 是底层状态和推理机制;Prompt Cache 是跨请求复用这些预处理结果的策略或产品能力。很多 Prompt Cache 的底层,复用的正是已经计算好的 K/V 状态。

阅读提示:下文会提到 Q、K、V、prefill、decode、前缀匹配和缓存断点(也就是缓存边界),但读懂本文不需要数学或 API 基础。阅读时,可以先把 Q、K、V 理解为注意力计算中的“中间向量”,再跟着“北京天气”和“产品手册”两个例子往下读。

KV Cache:模型生成时的“中间结果”

大模型逐 token 生成内容。每生成一个新 token,都要关注前面已经出现的 token。

以标准 Transformer 的自注意力层为例,每个 token 会在每一层产生 Q、K、V 三组向量。可以粗略地把 Q 理解成“我正在找什么”,K 是“我这里有什么”,V 则是“如果关注到我,应该取走什么信息”。

在自回归解码中,历史 token 的 Q 不会被后续步骤复用;它们的 K 和 V,却会被后面生成的 token 反复查询。因此,模型会把这些 K 和 V 保存下来,这就是 KV Cache

例如,你问:“北京的天气怎么样?”在 prefill 阶段,模型会处理整段问题,并在每一层保存这些 token 的 K 和 V。进入 decode 后,每一步只为刚加入序列的 token 计算新的 Q、K、V。模型把当前的 K、V 与历史缓存拼接,再用当前 Q 对历史和当前的 K、V 做注意力计算,以预测下一个 token。这样,历史 token 的 K 和 V 就不必反复计算。

这并不意味着长上下文没有代价。对于标准全注意力模型,上下文越长,KV Cache 占用的显存越多,每一步需要读取的历史 K/V 通常也越多。因此长对话仍可能越来越慢;滑动窗口等注意力结构则会限制可读取的历史范围。

KV Cache 通常由推理引擎管理,应用开发者很少直接操作。它主要用于一次生成内部的增量解码,但缓存下来的 K/V 状态也可以被推理框架用于跨请求的前缀复用。后者通常被称为 Prompt CachePrefix Cache

Prompt Cache:让相同前缀不必重复处理

提到“缓存”,很多人首先想到的是:同一个问题以前回答过,就直接返回旧答案。但 Prompt Cache 不是这种 Output Cache。即使缓存命中,模型仍然会重新生成回答。

Prompt Cache 复用的是 prompt 前缀在 prefill 阶段产生的中间结果,通常是 K/V 状态或其他等价的预处理结果。缓存命中后,可以减少重复的 prefill 计算、缩短首 token 延迟;如果 API 服务商提供缓存输入价格,还可以降低重复输入的费用。

例如,你把一份 50 页的产品手册交给模型,第一次问:

产品手册 → 保修期限是多久?

过一会儿,你又基于同一份手册询问:

产品手册 → 退货需要满足什么条件?

两次请求的产品手册完全相同,只有最后的问题发生变化。如果这段公共前缀命中缓存,第二次请求就可以复用手册对应的预处理结果,只处理后面的新问题。反过来,如果这份手册只会使用一次,Prompt Cache 就未必能带来多少收益。

对于自动匹配或缓存断点式的 Prompt Cache,可复用部分通常必须是从 prompt 开头起连续相同的前缀。因此,应把变化慢、复用范围大的内容放在前面,把频繁变化的内容放在后面。例如:

长期稳定内容:system prompt、工具定义
→ 阶段性稳定内容:用户配置、参考文档、任务背景
→ 会话内容:对话历史、任务状态
→ 本次请求:当前时间、临时信息、用户问题

这不是固定不变的分类,关键是按稳定程度排列,但不应因此改变消息角色、指令优先级和业务语义。不同服务商可能采用自动匹配、显式缓存断点或独立缓存对象,最小长度、有效期和计费规则也会随模型变化,接入时应以当前模型文档和响应中的缓存统计为准。

常见的两个 Bad Case:这些写法会让缓存悄悄失效

下面用两个常见场景说明。代码以 Anthropic 的 cache_control 为例;其他服务商可能采用自动匹配、不同的缓存标记或独立缓存对象,不能直接照搬字段。

1. 动态内容破坏前缀稳定性

依赖前缀匹配时,某处内容发生变化,这个位置之后的旧前缀通常就不能继续复用。因此,把每次都会变化的时间戳放进缓存前缀,会连带影响后面的固定规则。

// ❌ 时间戳包含在缓存前缀中,每次请求都会变化
const system = [{
  type: "text",
  text: `当前时间:${new Date().toISOString()}
你是一个代码助手。以下是固定的行为规则……`,
  cache_control: { type: "ephemeral" }
}]

更合适的做法是把长期稳定的内容放在前面,并在稳定前缀的末尾设置缓存断点;时间戳等动态信息放在缓存断点之后。

// ✅ 稳定内容在前,动态信息放在缓存断点之后
const system = [
  {
    type: "text",
    text: "你是一个代码助手。以下是固定的行为规则……"
  },
  {
    type: "text",
    text: "以下是固定的工具使用说明……",
    cache_control: { type: "ephemeral" }
  },
  {
    type: "text",
    text: `当前时间:${new Date().toISOString()}`
  }
]

项目配置、参考资料等内容可能介于“长期稳定”和“每次变化”之间,可以按稳定程度排列;支持多个缓存断点时,再为不同长度的稳定前缀设置断点。需要保持一致的不只是文字,工具定义及其顺序、图片参数等也可能参与匹配。

2. 多轮对话只缓存 system prompt

多轮对话通常会在每次请求中重新携带历史消息。如果只在 system prompt 末尾设置缓存断点,又没有启用自动缓存,那么增长的对话历史仍要重复处理。

// ❌ 只缓存 system prompt,对话历史不在缓存边界内
const request = {
  system: [{
    type: "text",
    text: "你是一个代码助手……",
    cache_control: { type: "ephemeral" }
  }],
  messages: history
}

以 Anthropic 当前的自动缓存为例,可以在请求顶层启用 cache_control,让缓存点随着对话增长自动向后移动:

// ✅ 自动缓存不断增长的对话前缀
const request = {
  cache_control: { type: "ephemeral" },
  system: [{ type: "text", text: "你是一个代码助手……" }],
  messages: history
}

启用后,下一轮请求可以复用上一轮已经缓存的前缀,只处理后来新增的回答、工具调用、工具结果和当前问题,并为后续请求写入新的缓存前缀。因此,它减少的是对话历史的重复处理,并不意味着只有最后一条消息是 cache miss。

如果服务商不支持自动缓存,则需要按照其规则,将显式缓存断点放在对话尾部仍然稳定的位置。

设置了缓存也不等于一定命中。首次遇到某个前缀时通常要先完成计算并写入缓存;缓存过期、未达到最小长度、历史前缀发生变化,或者缓存条目尚未可用,都可能导致 miss。截至 2026 年 8 月,Anthropic 的每个缓存断点最多只会在最近 20 个 content block 范围内查找此前写入的缓存条目,一轮 Agent 循环新增太多 block 时也可能 miss。

判断缓存是否真正带来收益,不能只看请求里有没有缓存配置。应查看 API 返回的缓存读取、写入或命中指标;如果关注延迟,还应在应用侧记录首 token 延迟,并结合实际价格评估缓存效果。

最后分清两者

概念 核心作用
KV Cache(推理机制) 在生成过程中复用历史 token 的 K/V,避免每一步重复计算
Prompt Cache / Prefix Cache(跨请求复用) 在不同请求之间复用相同 prompt 前缀的 prefill 结果

所以,两者不能等同,也不是毫无关系:KV Cache 是底层状态和推理机制,Prompt Cache 则把已经计算过的前缀状态复用到其他请求。对应用开发者来说,最实用的做法仍然是保持公共前缀稳定,并把时间戳、临时信息和当前问题尽量放在后面。

参考

本站原创文章皆遵循“署名—非商业性使用—相同方式共享 4.0 协议 (CC BY-NC-SA 4.0)”。共享、演绎请保留以下标注:

原文作者:Sunny Zhang,来源:「KV Cache 与 Prompt Cache:区别在哪,又有什么关系」

1
0 0 1

延伸阅读

发表回复

登录后才能评论
分享本页
返回顶部