大模型的命中缓存,是什么意思
同样的输入,为什么第二次便宜十倍。搞懂 KV 缓存,一个十步的 Agent 能从三十五块压到八块。
同一段话,发给同一个模型,账单能差五十倍。模型没有变聪明,也没有变笨,它只是认出了一句:这段话,我刚刚算过。
账单:同一段话,两个价格
DeepSeek 的官方定价页把输入分成两栏:CACHE HIT 和 CACHE MISS。命中那一栏,每百万 token 收 0.006 美元;没有命中的那一栏,收 0.3 美元。 [〔1〕]
Anthropic 的算法不一样,它把缓存读写拆成两项:写入时加价,五分钟的缓存收原价的 1.25 倍,一小时的缓存收 2 倍;但之后每一次读取,只收原价的十分之一。 [〔2〕]
OpenAI 的说法更直接:符合条件的前缀缓存输入,最高可以打到一折,也就是省下九成。 [〔3〕]
便宜不是打折,是少算了。 模型算的还是同一套东西,只是这一次,它把上一次的中间结果直接拿来用了。
所以真正要拆开的不是价格表,而是一个更基础的问题:模型读你那句话的时候,到底算出了什么,又为什么能留下来。
本质:先读,再写
大模型生成回答,分两个阶段:先读,再写。读的阶段叫预填充,要把你输入里的每个 token 过一遍所有的层;写的阶段叫解码,一个字一个字往外蹦。贵的是第一阶段,因为那一大段输入,都要老老实实算一遍。
注意力,让长输入越来越贵
解码阶段每蹦一个字,还要回头看一遍前面所有内容,这就是注意力机制。它有个特点:每多一个 token,就要和前面所有 token 都算一次。所以输入越长,计算量涨得越快,这是上下文变长以后特别贵的原因。
留下来的那一坨,叫 KV 缓存
模型会把每个 token 变成三个向量:查询、键、值。查询说的是我在找什么,键说的是我是什么,值说的是我能给什么。
每读一个 token,都要算出它的键和值,存起来给后面的字用。存下来的这部分,就是 KV 缓存——模型读你输入的时候,把中间结果留在了显存里。
vLLM 官方文档:新的请求如果和之前的请求共享同样的前缀,就可以直接复用 KV 缓存,跳过那部分计算,只算新的内容。 [〔4〕]
这就是命中缓存:复用已经算好的中间结果。注意,它复用的是计算结果,不是所谓的理解。模型没有记住你,它只是省了一次重复劳动。
条件:差一个字,全部重算
缓存这东西脾气很怪:差一个字,全都不算。它要求从第一个 token 开始,逐字相同——不是意思差不多,是字面完全一致。
DeepSeek 的文档里写得很明确:只有两个请求的前缀内容相同时,才算重复,而且必须从第零个 token 开始,从中间开始的重复不算。 [〔5〕]
命中率瞬间归零的两种写法:把系统提示改一个标点,或者在开头拼上一个当前时间,后面的缓存就全部作废。很多 AI 应用,就是这么把钱烧掉的。
还有一层容易被忽略:缓存是按块存的,块有最小尺寸。DeepSeek 以 64 个 token 为一个存储单位,比这更短的内容根本不会进缓存;OpenAI 要求至少 1024 个 token,之后按 128 个往上递增。所以短问题本来也没多少可省的,这套机制本来就是给很长的上下文准备的。 [〔5〕][〔3〕]
这也解释了一个特别常见的误会:语义相似,不等于命中。你把「代码分析助手」换成「软件代码分析智能体」,意思一样,字不一样,缓存就是不认。它不是拿向量去比相似度,而是一个字一个字地对齐。
缓存本质上是字符串匹配,不是语义理解。 想让缓存命中,就要把不变的东西放前面,变的东西放后面。这个顺序,在 Agent 时代变成了硬约束。
各家:缓存存在哪,活多久
DeepSeek 走了一条很特别的路:把缓存放到硬盘上。为什么敢?因为它的模型结构把 KV 缓存压得足够小。官方说法是,128K 的重复输入,首字延迟从 13 秒降到 500 毫秒,而且不用改代码,自动生效,按实际命中情况计费。 [〔5〕]
| 厂商 | 缓存怎么用 | 价格口径 |
|---|---|---|
| DeepSeek | 硬盘缓存,自动生效 | 命中 0.1 元 / 百万 token |
| Claude | 手动标记,写入加价 | 读取按原价 1/10 计 |
| Kimi K3 | 自动命中,按量计费 | 命中 2 元 / 百万 |
| OpenAI | 共享前缀,30 分钟内复用 | 最高省 90% |
| Gemini | 隐式缓存默认开启 | 命中自动减价 |
Claude 是另一套逻辑:缓存要你自己标出来,写入的时候还要加钱。但只要多读几次,这笔账就划算。 [〔2〕]
Kimi 的 K3 更极端:命中的输入每百万两块钱,没命中的输入每百万二十块,输出另算,每百万一百块。 [〔6〕]
OpenAI 还配了两个工具,一个看命中率,一个诊断为什么没命中。 [〔3〕]
Gemini 最省事:隐式缓存默认就开着,你什么都不用做,命中了自动减价。 [〔7〕]
但要注意,缓存不会一直活着。隔一晚上再来问,缓存早被清掉了;显存紧张的时候,旧缓存还要给别人让位。所以命中率不是一个固定值,它是个要维护的指标。
账本:Agent 时代,缓存变成架构约束
为什么这两年所有厂商都在拼命做缓存?因为 Agent 把账本改写了。一个会调用工具的 Agent,跑十步,可能只输出五百个字;但它每一轮都要把系统提示、工具定义、历史对话重新发一遍。十轮下来,输入可能到八十万 token,而这些内容绝大部分是完全重复的。
-
固定前缀放最前面:系统提示、规则、工具定义、长期记忆,一个字都不要动。
-
变化的部分放最后:用户问题、工具返回、当前状态,这些天然每次都变。
-
盯住返回里的命中数:命中率掉了,先回头查开头有没有被改过。
有人算过一笔账:一个 175K 的上下文跑十轮循环,全部不命中,成本三十五块;能命中 150K 的话,成本压到八块。差了四倍多,代码没改,只是把顺序调对了。
命中的是输入,不是输出:同一句话,输出那一部分永远是全价,一个字都不打折。缓存省的是理解你的成本,不是回答你的成本。
其实各家都把命中率写在接口返回里了,写个脚本天天看这个数,比什么都实在。
DeepSeek 的返回里直接给了两个数:命中的 token 数,和未命中的 token 数。
"prompt_cache_hit_tokens": 20480
"prompt_cache_miss_tokens": 512
OpenAI 在用量明细里单列一项 cached_tokens;Claude 则把读取和写入分开计,读的那一项就是命中。三个名字记不住也没关系,看见返回里那两个一高一低的数,就知道该看哪里了。
回到最开始那张账单
命中缓存,不是模型记住了你。是它把读你这段话时算出的中间结果,存了下来;下一次遇到同样的开头,接着用,不用再算。
它便宜,是因为少干活;它快,也是因为少干活。它命不中,往往不是运气差,是你把开头改掉了。
缓存命中,是大模型世界里的复利:你的上下文越稳定,它就越便宜。
参考资料
- 〔1〕DeepSeek API|Models & Pricing(缓存命中与未命中两档输入价)
- 〔2〕Anthropic|Claude 平台定价文档(缓存写入与读取价格)
- 〔3〕OpenAI|为 GPT-6 打造更出色的提示词缓存
- 〔4〕vLLM|Automatic Prefix Caching 官方文档
- 〔5〕DeepSeek API|创新采用硬盘缓存,价格再降一个数量级
- 〔6〕Kimi 开放平台|上下文缓存(Context Caching)文档
- 〔7〕Gemini API|Context caching 官方文档
我是硅基比特,分享 AI 观察,把技术讲清楚。
下次调用模型,先看一眼返回里的缓存命中数;掉了,就去查开头。