KV Cache 讲透:为啥大模型“第一个字慢得要命”,后面却像开了机关枪?
你肯定见过这个场景:
你把一段 prompt 发给 ChatGPT/Claude
光标闪啊闪,半天才吐出第一个字
然后就开始连续输出,像开闸放水一样
这不是玄学。
背后就是 KV Caching(KV 缓存)。
这篇文章咱们不绕弯子,按你真正会遇到的推理链路,把它讲清楚:
LLM 是怎么“一个 token 一个 token”吐字的
Attention 里到底在算啥
计算浪费发生在哪里
KV Cache 怎么把浪费砍掉
为啥第一个字最慢(prefill)
为啥 KV Cache 会把显存吃爆(以及工程上怎么救)
1)LLM 吐 token 的方式:每次只关心“最后一个位置”
Transformer 做推理时,会把输入序列里 每个 token 都过一遍网络。
得到一堆 hidden state:
token1 → h1
token2 → h2
...
tokenN → hN
关键点来了:
真正用来预测“下一个 token”的,是 最后一个 token 的 hidden state(hN)。
前面的 h1…h(N-1) 并不是没用。
它们更像“为最后一步服务的中间产物”。模型需要它们来做上下文建模,但在“生成下一个 token”这件事上,只有最后一个位置负责出结果。
你可以把它想成:
你问模型一句话
模型要把整段上下文都读懂
真正开口回答时,只从最后这个位置往外续写
2)Attention 到底在算什么:Q、K、V 是怎么用的
每一层 attention 里,每个 token 都会变成三样东西:
Q(Query):我现在要查什么
K(Key):我这里有什么线索
V(Value):线索对应的内容
当模型要算“最后一个 token”的输出,它会做这件事:
拿 最后一个 token 的 Q
去和 所有 token 的 K 做匹配(相似度)
用匹配权重去加权汇总 所有 token 的 V
一句话:
生成下一个 token 时,最后一个位置会“回头看”整个上下文。
这就是为啥大模型能记得你前面说的梗、你的约束条件、你的上下文细节。
3)真正的浪费:每生成一个 token,都在“从头复读”
现在看浪费点。
假设你已经生成到第 50 个 token。
你要生成第 51 个 token 时,attention 需要什么?
token1~token50 的 K、V
token51(当前最后一个位置)的 Q
问题是:
生成第 50 个 token 时,token1~token49 的 K、V 已经算过了
到生成第 51 个 token,token1~token49 的 K、V 根本没变
如果你每一步都把整段序列重新过一遍 Transformer,那就是:
反复重算老 token 的 K、V
序列越长,重复越离谱
复杂度直观感受:
不缓存:越写越慢,计算量接近 O(n²) 的增长(长对话直接炸)
有缓存:每步只做增量,增长更像 线性
你平时觉得“越聊越卡”,很多时候就是这里在作妖。
4)KV Cache 怎么干活:把算过的 K/V 存起来,后面直接用
KV Cache 的做法很粗暴,也很有效:
第一次把 prompt 全部跑一遍
把每层每个 token 的 K、V 都存起来
后续每生成一个新 token:
只算这个新 token 的 Q/K/V
把新 token 的 K/V 追加到缓存
用新 token 的 Q 去对“完整缓存”做 attention
你可以把 KV Cache 理解成:
以前每次写字都要把前面全文重新抄一遍;现在把全文复印件放旁边,写新句子只补最后一行。
这就是为什么主流推理框架离不开 KV Cache:
vLLM
TGI
TensorRT-LLM
没 KV Cache 的推理,基本没法看。
5)为啥第一个字最慢:prefill 才是最吃算力的那一下 😵💫
你发 prompt 的那一刻,模型干的是一件“大工程”。
它要把整段输入一次性处理完:
全部 token 过网络
全层的 K/V 计算出来
KV Cache 建好
这段叫:Prefill(预填充)。
Prefill 的特点:
token 很多
并行计算量巨大
GPU 负载高
等 prefill 做完,模型进入另一段:Decode(逐 token 解码)。
Decode 的特点:
一次只生成 1 个 token(自回归)
每步只算“新 token”的那点东西
KV Cache 让历史部分不用重算
所以你看到的现象就很自然了:
第一个 token 慢:prefill 在干重活
后面快:decode 在吃缓存红利
如果你在做产品体验优化,建议把指标拆开看:
TTFT(Time To First Token,首 token 延迟)
TPS(Tokens Per Second,持续输出速度)
很多团队只盯 TPS,然后用户还在骂“怎么老半天不出字”,就是没把 TTFT 当回事。
6)代价:KV Cache 吃显存,吃到你怀疑人生
KV Cache 省的是计算,花的是显存。
而且是每个请求一份。
模型越大、层数越多、上下文越长、并发越高,KV Cache 越夸张。
你可以记住这条朴素规律:
长上下文 + 高并发
最先顶不住的往往不是算力
是显存(KV Cache 把卡塞满了)
有些大模型(比如 70B 级别)在长对话场景下,单请求的 KV Cache 就能吃掉好几 GB 显存。
并发一上来,KV Cache 甚至可能比模型权重还占地方。
这也是为啥工程界搞了很多“省 KV”方案:
MQA/GQA:让多个 query head 共享更少的 K/V head,减少缓存体积
Paged Attention:把 KV Cache 当成分页内存来管理,减少碎片,提升并发下的显存利用率
你照着做:推理优化时怎么用 KV Cache 思路排查问题
把下面这张“排查清单”贴到工位上都行。
✅ 你想让“首字更快”
盯 prefill:
prompt 砍短一点(少废话、少长系统提示)
控制输入上下文长度(别无限拼历史)
用更快的推理引擎/更激进的 kernel 优化
✅ 你想让“持续输出更快”
盯 decode:
确认 KV Cache 真在用(很多自研代码一不小心就没 cache)
batch/并发策略要合理(别让 GPU 空转)
✅ 你想让“并发更高不爆显存”
盯 KV Cache 占用:
上 GQA/MQA 的模型版本
用支持 Paged Attention 的框架(典型是 vLLM 思路)
限制每个会话的最大上下文长度(这是最直接也最有效的开关)
常见坑:很多人优化半天,其实输在这几件事上
以为慢是网络问题:其实是 TTFT(prefill)太慢
只看平均延迟:用户感知更在意“多久看到第一个字”
无限堆上下文:历史越长,prefill 越重,KV 越大,并发越差
没把 KV Cache 当成本:显存预算不做,线上迟早炸
一句话收尾
你看到的“第一个字慢、后面飞快”,不是模型在装。
是 prefill 在狠狠干活,KV Cache 建好后,decode 才开始享受增量计算的爽感。
真要把推理体验做好,别只盯模型有多大。盯住 TTFT、TPS、KV Cache 显存 这三件事,才是真正能让你少加班的东西。