首页
看点啥
插画图片
首页 看点啥 AI Token 缓存:命中省 10 倍 不命中白扔钱

AI Token 缓存:命中省 10 倍 不命中白扔钱

2026-07-22 0

所谓"缓存命中便宜、不命中贵",省的不是 token 本身,是模型把你的 prompt 跑一遍预计算(prefill)的算力。命中就是复用上次算好的中间成果、跳过重复计算;不命中就得从头再算一遍。同一段 system prompt,第一次老实算,后面次次白嫖——账单差就在这。

AI Token 缓存:命中省 10 倍,不命中白扔钱

一、先用一个比喻搞懂

把大模型想成一个赶作业的学霸。你每次交的"卷子",开头都要写一段一模一样的 2000 字个人陈述(这就是你的 system prompt)。

这里的**"复印件"就是缓存(KV cache)**——模型算好的中间成果。

为什么只有"开头"能复印?因为模型是逐字往后读的,后面每个字的理解都依赖前面的字。只要前面一样,前面的计算成果就能整个搬来用;前面一改,后面全得重来。所以缓存只认前缀。

这笔账有多夸张

拿 Anthropic 定价举例(base $5 / 百万 token):一段 2000 token 的 system prompt,每次再带 50 token 的用户问题。

方式单次成本10 次总成本
不缓存2050 token 全原价 ≈ $0.0103≈ $0.103
缓存(首写 1.25x,后续读 0.1x)0.0128,后续0.0128,后续 0.0013≈ $0.024

省了 3/4 以上。 请求越多越省,百次级能砍掉 85%+。这还只是 2000 token 的 system prompt——如果你的 prompt 里塞的是一整份几万 token 的文档(RAG、长文档问答),差距会拉到 10 倍。

二、硬核原理:KV Cache 与为什么前缀能复用

2.1 预计算(prefill)到底算了什么

Transformer 处理你的 prompt 时,会把整段文字过一遍所有层。每一层都给每个 token 算出两组向量:Key(K)和 Value(V),合称 KV。生成回答时,模型靠 attention 去"回顾"前面所有 token 的 K 和 V。为了不每次重算,推理框架把算过的 KV 留在显存里——这就是 KV cache。

关键点:attention 是单向的,只往后看。 第 1 到第 N 个 token 的 KV 向量,只取决于这前 N 个 token 自己,跟后面跟了什么话没关系。所以只要两个请求的前 N 个 token 一模一样,它们前 N 个位置的 KV cache 就分毫不差。第二个请求直接把这块 KV 捞出来用,省掉前 N 个 token 的预计算。

这块显存其实挺贵。拿 Llama-2 70B 算一笔账:每个 token 每层 KV 约 4KB(FP16,GQA 后 8 个 KV head),80 层就是 320KB/token。一个 2000 token 的 system prompt,KV cache 要占 ~640MB 显存。每次请求都重算再扔掉,纯属浪费——prefix caching 就是把这块显存留住、复用。

2.2 实际是按"块"复用,不是按 token

推理框架不会傻到逐 token 比对,而是把 KV 切成固定大小的块(vLLM 用 PagedAttention,16 token 一块;SGLang 用 RadixAttention,前缀树组织)。匹配靠链式哈希:

key_0 = hash(tokens[0 : 16])key_1 = hash(key_0 || tokens[16 : 32])key_2 = hash(key_1 || tokens[32 : 48])...

为什么搞链式?因为两个 prompt 可能末尾一样、前面不一样。比如"A 国首都是巴黎,2+2=?"和"B 国首都是巴黎,2+2=?",最后那句"2+2=?"的 KV 其实不同——前面上下文变了,它 attend 到的东西就不同。链式哈希保证:只要前面某一块对不上,后面所有块的 key 全变,自然不会误命中。

flowchart LRsubgraph A["请求1: system + 问题X"]A1["Token 1..2000
system prompt"] --> A2["Token 2001..2010
问题X"]endsubgraph B["请求2: system + 问题Y"]B1["Token 1..2000
system prompt"] --> B2["Token 2001..2012
问题Y"]endKV[("GPU 显存
Token 1..2000 的 KV Cache")]A1 -->|"首次计算并驻留"| KVB1 -->|"命中前缀·直接复用"| KV

2.3 从调用栈看,这事儿分四层

flowchart TDApp["应用层: 你的代码
cache_control / prompt_cache_key"] --> Product["产品层: 厂商 API
Prompt Caching / Context Caching
按命中差价计费"]Product --> Engine["系统层: 推理引擎
vLLM PagedAttention / SGLang RadixAttention
按块哈希命中前缀"]Engine --> GPU["物理层: GPU 显存
KV Cache
每层每 token 的 K/V 向量"]

我们平时说的"token 缓存命中",落到最底下就是物理层那块 KV 被复用了。

三、命中 / 不命中,流程上差在哪

flowchart TDReq["新请求到达"] --> Hash["对 prompt 前缀做哈希"]Hash --> Match{"缓存里有
相同前缀?"}Match -->|"命中"| Reuse["复用已算好的 KV
只算尾部新增 token
按 cache read 低价计费"]Match -->|"不命中"| Full["整段 prefill 重算
按正常 input 价计费"]Full --> Store["把前缀 KV 写入缓存
供后续请求复用
部分厂商收写入费"]

两个反直觉、但必须记住的点:

  1. 缓存只对"前缀"生效。 一旦 prompt 从某个位置开始跟缓存版本不一样(换了 user 消息、换了一份 RAG 文档),那个位置之后的缓存就废了。
  2. 字节级精确匹配。 多一个空格、改个标点,缓存直接失效。不是"意思差不多就行"。

四、三家实现和定价,差别比想象大

厂商触发方式最小可缓存命中折扣TTL写入费
Anthropic显式 cache_control1024 token90% off(0.1x)5min(默认)/ 1h(付费)5min 写 1.25x / 1h 写 2x
OpenAI全自动(>1024)1024 token,128 递增50%~90% 不等,越新越深5–10min,1h 内清老模型免费;GPT-5.6+ 写 1.25x
Gemini隐式自动 + 显式 API隐式 1024 / 显式 32768隐式 75% off / 显式约 90%显式可配,默认 1h存储 $1.00/M token/小时

几个我踩过或观察到的坑:

五、实战:怎么更容易命中(按性价比排序)

回到开头的"抄作业"比喻——你想 photocopy 的那段,必须每次都一模一样、且放在最前面。

1. 静态内容放最前,动态内容放最后。 这是铁律。system prompt、few-shot 示例、工具定义、RAG 文档这些不变的,全堆在 prompt 头部;用户每次不同的输入放尾巴。缓存只看前缀,尾巴随便变不影响前缀命中。

2. 顺序要稳定。 system → tools → 记忆 → 历史对话 → 当前消息,这个顺序每次保持一致。工具定义按名字排序(确定性顺序)。OpenAI 的匹配是"最长精确前缀",你 reorder 一下前面,整段缓存就断了。

3. 别在缓存前缀里塞"会变的量"。 时间戳、请求 ID、随机种子、当次日期——这些只要出现在被缓存的前缀段里,每次都不同,缓存必失。需要的话把它们挪到尾部动态区。我见过有人把 当前时间:{now()} 写进 system prompt,结果缓存一次都没命中过,排查了半天才发现。

4. Anthropic 把 breakpoint 打在稳定边界上。 最多 4 个:system prompt 结尾、工具定义结尾、静态文档结尾、历史对话前缀结尾。每个 breakpoint 之前到上一个 breakpoint 之间的内容被缓存。让"会变的部分"恰好落在最后一个 breakpoint 之后。

5. 低频负载的处理。 5 分钟 TTL 对低频接口是诅咒——请求间隔一长,缓存早过期,你每次都交写入费。两个办法:用 1h TTL(写贵一倍,但命中赚更多);或者搞个缓存 warmer,定时用同一前缀打一个低成本请求把缓存焐热。

6. 一定要监控命中率。 别凭感觉。Anthropic 看 cache_read_input_tokens / cache_creation_input_tokens;OpenAI 看 cached_tokens;Gemini 看缓存对象的复用统计。命中率为 0 但你以为开了——多半是前缀没对齐或没过最小 token 阈值(1024)。

7. 不在每次都变的内容上浪费缓存。 缓存只对"会被重复的前缀"有意义。一份每请求都不同的 RAG 上下文塞进缓存,等于每次都写、从不读,纯亏写入费。判断标准一句话:这个前缀,后面还会有请求用一模一样的开头吗?不会就别缓存。

六、收尾

Token 缓存不是玄学,就是"相同前缀别重复算"这一件事,被三家包装成了不同的 API 和价目表。要把它用明白,记住三件事:静态前置、字节一致、盯着命中率。做到了,长 system prompt / 多轮对话 / 大文档问答这类负载,账单砍掉 60%~90% 很常见;做不到,你可能一直在交 1.25x 的写入费,还以为自己省了。

喜欢(0)

上一篇

浅谈Workflow与Agent的区别

浅谈Workflow与Agent的区别

下一篇

数字遗民抢救“赛博爱人”:豆包智能体下线引发数据大迁移:“AI导出鸭”成最后稻草

数字遗民抢救“赛博爱人”:豆包智能体下线引发数据大迁移:“AI导出鸭”成最后稻草
猜你喜欢