Amit Shekhar
2026-03-27
D
原文
---
title: "LLM 中的 KV Cache"
author: "Amit Shekhar"
source_url: "https://outcomeschool.com/blog/kv-cache-in-llms"
published_at: "2026-03-27T00:00:00.000Z"
fetched_at: "2026-07-01T23:10:53Z"
updated_at: "2026-07-01T23:14:00Z"
language: "zh"
review_status: "draft"
---
# LLM 中的 KV Cache

在这篇文章里,我们会学习 **KV Cache**:K 代表 Key,V 代表 Value;也会理解它为什么会用在大语言模型(LLM)里,用来加速文本生成。
我们会先看 LLM 如何一次生成一个 token,理解 Key、Value 和 Query 在模型内部的作用;再通过一个例子看看重复计算的问题;最后一步步看 KV Cache 如何通过保存并复用过去的结果来解决这个问题。
我是 **Amit Shekhar**,[Outcome School](https://outcomeschool.com) 创始人。我教过并辅导过很多开发者,他们靠自己的努力拿到了高薪技术岗位;我也帮助过许多科技公司解决各自独特的问题,并创建过很多被顶级公司使用的开源库。我热衷于通过开源、博客和视频分享知识。
我在 Outcome School 教 [AI and Machine Learning](https://outcomeschool.com/program/ai-and-machine-learning)。
我们开始吧。
## LLM 如何生成文本
在理解 KV Cache 之前,我们先要理解 LLM 如何生成文本。
LLM,也就是大语言模型,是一种在海量文本数据上训练出来的模型。它可以理解并生成人类语言。当我们给它一句话时,它会预测接下来应该是什么。
LLM 生成文本是**一次一个 token**。token 是一小段文本,可以是一个词、词的一部分,甚至是单个字符。为了简单起见,我们先把每个词当作一个 token。
假设我们给模型这个输入:
```text
"I love"
```
模型看到 **“I”** 和 **“love”**,预测下一个 token:**“teaching”(教学)**。
现在完整序列变成:
```text
"I love teaching"
```
模型看到 **“I”**、**“love”** 和 **“teaching”**,预测下一个 token:**“AI”**。
现在完整序列变成:
```text
"I love teaching AI"
```
这个过程会一次一个 token 地持续下去,直到模型决定停止。
这里最重要的一点是:模型每次预测一个新 token 时,都需要查看**所有之前的 token**,才能决定接下来是什么。
## 模型内部发生了什么
现在,我们来理解模型生成每个 token 时内部发生了什么。
模型里有一个组件叫 **注意力层(attention layer)**,它是 [Transformer 架构](https://outcomeschool.com/blog/decoding-transformer-architecture)的核心。注意力层的任务,是帮助模型判断哪些之前的 token 对预测下一个 token 重要。不是所有之前的 token 都同样有用。有些更重要,有些没那么重要。
在注意力层内部,每个 token 都会被转换成三样东西。我们用一个简单类比来理解它们。
想象一个教室,新同学加入进来,想知道谁能帮他解决某个主题的问题:
- **Query(Q)**:新同学的问题——“这里谁懂这个主题?”每个正在被预测的 token 都会有一个 Query。它表示这个 token 正在寻找什么。
- **Key(K)**:每个现有学生戴着的名牌,上面写着他们知道什么——“我懂数学”或“我懂科学”。每个之前的 token 都会有一个 Key。它描述这个 token 持有什么信息。
- **Value(V)**:每个学生真正拥有的笔记。新同学用名牌(Key)找到合适的人以后,真正会用到的是笔记(Value)。每个之前的 token 都会有一个 Value。它承载实际信息。
所以,当前 token 会用自己的 **Query** 去和所有之前 token 的 **Key** 比较。这个比较会产生 **注意力分数(attention score)**,也就是一些数字,告诉模型应该给每个之前的 token 多少关注。分数越高,说明那个 token 越相关;分数越低,说明没那么相关。然后,模型会用这些分数从相关 token 中收集 **Value**。如果想深入理解 Q、K、V 是怎么计算出来的,我们有一篇详细文章:[Math behind Attention: Q, K, V](https://outcomeschool.com/blog/math-behind-attention-qkv)。
这就是注意力层的工作方式。
接下来看看问题在哪里。
如果想深入学习注意力层、Q/K/V 内部机制和 Transformer 架构,可以看看 Outcome School 的 [AI and Machine Learning Program](https://outcomeschool.com/program/ai-and-machine-learning)。
## 问题:重复计算
模型每次预测下一个 token 时,都会为**序列中的所有 token** 计算 Key、Value 和 Query,而不只是为新 token 计算。
我们用前面的例子一步步看会发生什么:
**第 1 步:** 输入是 **“I love”**
模型为下面这些 token 计算 Key、Value 和 Query:
- “I”
- “love”
它用这些结果预测下一个 token:**“teaching”(教学)**。
**第 2 步:** 输入是 **“I love teaching”**
模型为下面这些 token 计算 Key、Value 和 Query:
- “I”(第 1 步已经算过,但又算了一遍)
- “love”(第 1 步已经算过,但又算了一遍)
- “teaching”(新的)
它用这些结果预测下一个 token:**“AI”**。
**第 3 步:** 输入是 **“I love teaching AI”**
模型为下面这些 token 计算 Key、Value 和 Query:
- “I”(第 1 步和第 2 步已经算过,但又算了一遍)
- “love”(第 1 步和第 2 步已经算过,但又算了一遍)
- “teaching”(第 2 步已经算过,但又算了一遍)
- “AI”(新的)
你看到问题了吗?
**“I”** 的 Key 和 Value 在第 1 步已经算过。但模型在第 2 步又算了一遍,在第 3 步又算了一遍。**“love”** 和 **“teaching”** 也是一样。
**模型在为已经见过的 token 重复做同样的工作。** 这就是浪费的计算。
随着序列变长,这个问题会越来越严重。如果模型已经生成了 100 个 token,那么下一步为了预测 1 个新 token,它会重新计算前面所有 100 个 token 的 Key 和 Value。这会让文本生成变得很慢。
**给你一个小提示**
无论你在哪个技术领域工作,都应该熟悉这些主题:
- LLM
- RAG
- MCP
- Agent
- Fine-tuning
- Quantization
我们把它们整理进了一个视频:
[AI Engineering Explained: LLM, RAG, MCP, Agent, Fine-Tuning, and Quantization](https://www.youtube.com/watch?v=lnfWvX66FUk)
不用现在停下来去看——先收藏,等有时间再看。未来的你会感谢现在的你。
现在,我们回到主题。
## 解决方案:KV Cache
**KV Cache** 背后的思路很简单:**每个 token 的 Key 和 Value 只计算一次,保存起来,并在之后每一步复用**。
可以把它想成做笔记。假设你在开会。每次有新人发言时,你不需要让前面所有发言者把说过的话再重复一遍,只要读自己的笔记,然后只听新发言者说什么就行。笔记就是你的缓存。
同样,**KV Cache** 是一块内存,用来保存每个已经处理过的 token 的 Key 和 Value。这样模型就不必再次计算它们。
我们看看同一个例子在使用 KV Cache 时会怎么运行:
**第 1 步:** 输入是 **“I love”**
模型为下面这些 token 计算 Key、Value 和 Query:
- “I”
- “love”
它把 **“I”** 和 **“love”** 的 Key 和 Value 保存到 **KV Cache** 中。
它用这些结果预测下一个 token:**“teaching”(教学)**。
**现在 KV Cache 包含:** “I”、“love” 的 Key 和 Value
**第 2 步:** 输入只有 **“teaching”**(只有新的 token)
模型从 KV Cache 中取回 **“I”** 和 **“love”** 的 Key 和 Value。**不需要重新计算。**
它只为新的 token **“teaching”** 计算 Key、Value 和 Query。
它把 **“teaching”** 的 Key 和 Value 保存到 KV Cache 中。
它把所有这些一起用于预测下一个 token:**“AI”**。
**现在 KV Cache 包含:** “I”、“love”、“teaching” 的 Key 和 Value
**第 3 步:** 输入只有 **“AI”**(只有新的 token)
模型从 KV Cache 中取回 **“I”**、**“love”** 和 **“teaching”** 的 Key 和 Value。**不需要重新计算。**
它只为新的 token **“AI”** 计算 Key、Value 和 Query。
它把 **“AI”** 的 Key 和 Value 保存到 KV Cache 中。
**现在 KV Cache 包含:** “I”、“love”、“teaching”、“AI” 的 Key 和 Value
所以,模型不再每一步都为每个 token 重新计算 Key 和 Value,而是只为**新的 token** 计算,并复用所有之前 token 的缓存值。
这就是 **KV Cache** 避免重复计算的方式。
同样的思路还可以再进一步:在很多共享相同开头文本的请求之间复用已经缓存的 Key 和 Value。我们有一篇详细介绍 [Prompt Caching](https://outcomeschool.com/blog/how-does-prompt-caching-work) 的文章,解释了这是怎么工作的。
## 为什么只缓存 Key 和 Value,而不缓存 Query
你自然会问:为什么我们只缓存 Key 和 Value,而不缓存 Query?
Query 只对**当前 token** 有用,也就是正在生成的那个 token。当前 token 会用自己的 Query 去和所有之前 token 的 Key 比较,找出哪些 token 相关。一旦预测完成,这个 Query 就不再需要了。
但每个过去 token 的 Key 和 Value 在**之后每一步**都会被用到,因为每个新 token 都必须查看所有之前的 token 才能完成预测。
所以,我们只需要保存 Key 和 Value。这就是为什么它叫 **KV Cache**:它缓存的是 Key 和 Value。
## 速度能快多少
我们把两种做法放在一起对比:
**没有 KV Cache:**
```text
Step 1: Compute K, V, Q for 2 tokens
Step 2: Compute K, V, Q for 3 tokens (2 recomputed)
Step 3: Compute K, V, Q for 4 tokens (3 recomputed)
Step 4: Compute K, V, Q for 5 tokens (4 recomputed)
...
Step N: Compute K, V, Q for (N+1) tokens (N recomputed)
```
计算量会在每一步持续增长。
**使用 KV Cache:**
```text
Step 1: Compute K, V, Q for 2 tokens → Save K, V for 2 tokens in cache
Step 2: Compute K, V, Q for 1 token → Reuse K, V for 2 tokens from cache
Step 3: Compute K, V, Q for 1 token → Reuse K, V for 3 tokens from cache
Step 4: Compute K, V, Q for 1 token → Reuse K, V for 4 tokens from cache
...
Step N: Compute K, V, Q for 1 token → Reuse K, V for N tokens from cache
```
第一步之后,模型每一步只为**一个新 token** 计算,而不是为整个序列重新计算。
换个角度看:如果模型要生成一个 100 个 token 的序列,没有 KV Cache 时,所有步骤里的 Key 和 Value 计算总数会是 2 + 3 + 4 + ... + 100 = **5,049 次计算**。使用 KV Cache 时,会变成 2 + 1 + 1 + ... + 1 = **101 次计算**。大约少了 **50 倍计算量**。序列越长,节省越大。
这就是 KV Cache 能有效加速文本生成的原因。
## 取舍:速度与内存
KV Cache 会让生成更快,但也有一个取舍:它需要额外内存来保存到目前为止已经生成的每个 token 的 Key 和 Value 信息。
序列越长,缓存就越大。对于包含数千个 token 的超长序列,缓存可能会占用相当多内存。
所以,KV Cache 是一种取舍:**我们用更多内存换取计算时间**。对大多数用例来说,这个取舍非常值得,因为速度提升很明显。
当我们同时为很多用户提供 LLM 服务时,高效管理 KV Cache 内存会变得非常关键。我们有一篇详细介绍 [vLLM](https://outcomeschool.com/blog/how-does-vllm-work) 的文章,解释了服务系统如何端到端处理这件事。
现在,我们已经理解了 LLM 中的 KV Cache。
在下一篇文章里,我们会学习 **[Paged Attention](https://outcomeschool.com/blog/paged-attention-in-llms)**,它解决的是 KV Cache 的内存问题。
准备 AI 工程面试可以看这里:[AI Engineering Interview Questions](https://github.com/amitshekhariitbhu/ai-engineering-interview-questions)
这次就到这里。
谢谢
**Amit Shekhar**
[Outcome School](https://outcomeschool.com) 创始人