LLM 中的 KV Caching,讲清楚

---
title: "LLM 中的 KV Caching,讲清楚"
author: "Akshay 🚀 (@akshay_pachaar)"
source_url: "https://x.com/akshay_pachaar/status/2020840784782913605"
published_at: "2026-02-09T12:42:43.000Z"
fetched_at: "2026-06-12T06:25:34Z"
updated_at: "2026-06-12T09:44:55Z"
language: "zh"
review_status: "draft"
---

![](https://pbs.twimg.com/media/HAskdw6aIAAF1Me.jpg)

# LLM 中的 KV Caching,讲清楚

每次你用 ChatGPT 或 Claude 时,其实都见过这个现象。第一个 token 出现得明显更慢。之后剩下的 token 几乎立刻开始流式输出。

这不是 UI 小毛病,而是一个有意为之的工程决策,叫 KV caching。它能让 LLM 推理速度大约提升 5 倍。

我们从第一性原理出发,看看它到底是怎么工作的。

<video controls src="https://video.twimg.com/amplify_video/2020728959932207104/vid/avc1/1234x720/v32TulKxUQTvYRkW.mp4?tag=21"></video>

### 第 1 部分:LLM 如何生成 token

Transformer 会处理所有输入 token,并为每个 token 生成一个 hidden state。这些 hidden state 会被投影到词表空间,产生 logits(词表中每个词一个分数)。

<video autoplay loop muted playsinline src="https://video.twimg.com/tweet_video/HAsU2GeaMAAd093.mp4"></video>

但真正有用的,只有**最后一个 token** 的 logits。你从这些 logits 里采样,得到下一个 token,把它追加到输入后面,然后重复这个过程。

<video autoplay loop muted playsinline src="https://video.twimg.com/tweet_video/HAsVC0HagAA50BH.mp4"></video>

关键洞察是:要生成下一个 token,你只需要最近那个 token 的 hidden state。其他所有 hidden state 都只是中间副产物。

### 第 2 部分:Attention 实际上在算什么

在每一层 transformer 里,每个 token 都会得到三个向量:query(Q)、key(K)和 value(V)。Attention 会把 query 和 key 相乘得到分数,再用这些分数去加权 value。

<video autoplay loop muted playsinline src="https://video.twimg.com/tweet_video/HAsX1psa8AAxFOz.mp4"></video>

现在只关注最后一个 token。

<video autoplay loop muted playsinline src="https://video.twimg.com/tweet_video/HAsX_rOakAAJD8p.mp4"></video>

QK^T 的最后一行会用到:

- 最后一个 token 的 query 向量
- 序列中**所有** key 向量

这一行最终的 attention 输出会用到:

- 同一个 query 向量
- **所有** key 和 value 向量

所以,为了计算我们唯一需要的那个 hidden state,每一层 attention 都需要最新 token 的 Q,以及所有 token 的 K 和 V。

### 第 3 部分:冗余在哪里

生成第 50 个 token,需要第 1 到第 50 个 token 的 K 和 V 向量。生成第 51 个 token,又需要第 1 到第 51 个 token 的 K 和 V 向量。

第 1 到第 49 个 token 的 K 和 V 向量早就算过了。它们没有变化。同样的输入,同样的输出。但模型每一步还是会从头重新计算它们。

![](https://pbs.twimg.com/media/HAsS-rLbgAAyn-S.png)

这就是每一步 O(n) 的冗余工作。放到整段生成里,就是 O(n²) 的浪费计算。

### 第 4 部分:修法

不要在每一步都重新计算所有 K 和 V 向量,而是把它们存起来。对于每个新 token:

1. **只**为最新 token 计算 Q、K 和 V。
2. 把新的 K 和 V 追加到 cache 里。
3. 从 cache 里取出之前所有 K 和 V 向量。
4. 用新的 Q,对完整缓存下来的 K 和 V 跑 attention。

<video autoplay loop muted playsinline src="https://video.twimg.com/tweet_video/HAsYUDNbkAANhrF.mp4"></video>

这就是 KV caching。每一层、每一步只新增一个 K 和一个 V。其他一切都从内存里取。

Attention 计算本身仍然会随序列长度增长(因为你仍然要 attend 到所有 key 和 value 上)。但生成 K 和 V 的昂贵投影,每个 token 只做一次,而不是每一步都做一次。

### 第 5 部分:Time-to-First-Token

现在你就能看出为什么第一个 token 慢了。

当你发送一个 prompt 时,模型会用一次 forward pass 处理整个输入,为每个 token 计算并缓存 K 和 V 向量。这就是 **prefill 阶段**,也是整个请求里计算最重的部分。

cache 热起来之后,后续每个 token 只需要带着一个 token 做一次 forward pass。很快。

最开始这段延迟叫 **time-to-first-token(TTFT)**。prompt 越长,prefill 越长,等待也越久。优化 TTFT(chunked prefill、speculative decoding、prompt caching)本身是一个很深的话题,但背后的动态始终一样:构建 cache 很贵,读取 cache 很便宜。

### 第 6 部分:取舍

KV caching 是用内存换计算。每一层都会为每个 token 存 K 和 V 向量。以 Qwen 2.5 72B 为例(80 层、32K context、hidden dim 8192),单个请求的 KV cache 就可能消耗数 GB 的 GPU 内存。并发请求达到几百个时,它占用的内存往往会超过模型权重本身。

这就是 grouped-query attention(GQA)和 multi-query attention(MQA)存在的原因:在多个 query head 之间共享 key/value head,削减内存,质量损失很小。这也是为什么把 context length 翻倍很难。窗口翻倍,每个请求的 KV cache 也翻倍,并发用户数就会下降。

### tl;dr

KV caching 消除了自回归生成过程中的冗余计算。过去的 token 总是会产生相同的 K 和 V 向量,所以你只需要计算一次并存起来。每个新 token 只需要自己的 Q、K 和 V。然后 attention 对完整 cache 运行。

实际中大约能提速 5 倍。代价是 GPU 内存,而在规模化服务中,GPU 内存会成为硬约束。每个 LLM serving stack(vLLM、TGI、TensorRT-LLM)都建立在这个思路之上。

<video autoplay loop muted playsinline src="https://video.twimg.com/tweet_video/HAsUZcCbIAAW-dF.mp4"></video>

---

就到这里!如果你觉得有启发,转发给你的网络吧。

找我 → @akshay_pachaar ✔️  
获取更多关于 LLM、AI Agent 和机器学习的见解与教程!