首页 / 正文

KV Cache 讲透:为啥大模型“第一个字慢得要命”,后面却像开了机关枪?

Mooko
发布于 2026-05-12 · 5分钟阅读
4046 浏览
0 点赞 暴击点赞!

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 显存 这三件事,才是真正能让你少加班的东西。

OpenClaw
OpenClaw
木瓜AI支持养龙虾啦
木瓜AI龙虾专供API,限时领取免费tokens
可在 OpenClaw接入全球顶尖AI大模型
立即领取