L

[LLM] 粗浅理解大模型 KV Cache

RoLingG 其他 2026-06-30

粗浅理解大模型 KV Cache

我们先来了解一下大模型对于 Token 的处理流程(学习过 RAG 开发的应该大概知道这个处理流程):

Token
  │
  ▼
Embedding    // Token向量化
  │
  ▼
Layer1        // 不断加工向量
  │
  ▼
Layer2
  │
  ▼
...
  │
  ▼
LayerN        // N次加工向量
本文章由于篇幅原因,就不在此展开讲解处理流程相关内容,具体细节可以看:大模型处理Token流程

KV Cache是什么?作用又是什么?

KV Cache(Key-Value Cache)是大语言模型在推理过程中使用的一种缓存机制。它会缓存历史 Token 在注意力(Attention)计算中产生的 Key 和 Value 向量,使模型生成新 Token 时无需重复计算历史内容,从而显著提升推理效率。

假设用户输入一句话:

介绍一下 Go 协程

经过 Tokenizer 后,会变成多个 Token(假设状态):

[介绍][一下][Go][协程]

进入 Transformer 后,每一层都会计算三组向量:

$$ Q=XW_Q $$

其中:

  • Query(Q):当前 Token 用来"查询"其它 Token。
  • Key(K):表示每个 Token 的特征,用来和 Query 计算相关性。
  • Value(V):真正携带语义信息,被 Attention 加权后输出。

Attention 的计算公式为:

$$ Attention(Q,K,V)=softmax\left(\frac{QK^T}{\sqrt d}\right)V $$

可以发现:

当前 Token 只需要自己的 Query,但需要所有历史 Token 的 Key 和 Value。

这也是 KV Cache 存在的根本原因。

没有 KV Cache 会发生什么?

假设模型已经生成了:

Go 语言是一门

现在准备生成下一个 Token。

如果没有 KV Cache,模型实际上需要重新计算整个上下文:

Go
语言
是
一门

所有 Token 都要重新经过:

Embedding
  ↓
Layer1
  ↓
Layer2
  ↓
...
  ↓
LayerN

每一层都会重新计算:

Q
K
V

即使前面的 Token 已经计算过很多次,它们仍然会被重新计算。

这意味着:每生成一个 Token,整个上下文都会重新 Forward 一遍。

随着上下文越来越长,这种重复计算会迅速成为推理瓶颈。


KV Cache 缓存了什么?

KV Cache 的核心思想非常简单:

历史 Token 的 Key 和 Value 一旦计算完成,在后续推理过程中就不会发生变化。

例如:

Go
语言
是

已经完成计算:

Go      -> K1 V1
语言     -> K2 V2
是       -> K3 V3

这些结果会直接存入 KV Cache。

下一步生成:一门

模型只需要计算:

Q4
K4
V4

然后把:

K4
V4

追加到缓存中。

历史 Token 的:

K1
V1

K2
V2

K3
V3

全部直接读取,不需要重新计算。

因此,KV Cache 会随着模型不断生成 Token 而持续增长。


为什么不缓存 Query?

Query 只有一个作用:查询历史。

例如生成第 100 个 Token 时:

Q100

会去查询:

K1 ~ K99

得到 Attention 权重。

下一步生成:

Q101

上一轮的:

Q100

已经不会再参与任何计算。

因此,Query 是一次性的。

而:

K1
V1

却会一直被未来所有 Token 使用。

所以真正值得缓存的是:

Key
Value

而不是 Query。


KV Cache 并不是缓存一句话

很多人第一次接触 KV Cache 时,会误以为:"缓存的是整个上下文"

其实更加准确的说法应该是:

缓存的是每一层、每一个 Token 的 Key 和 Value。

例如一个拥有 32 层的 Transformer:

Layer1

Token1 KV
Token2 KV
Token3 KV

Layer2

Token1 KV
Token2 KV
Token3 KV

...

Layer32

因此:

一个 Token 会对应 32 层的 KV。

这也是为什么 上下文 (Context) 越长,显存占用增长得非常快。


Prefill 和 Decode

现代 LLM 推理通常可以分成两个阶段。

第一阶段 Prefill

假设用户输入:

介绍一下 Go 协程

因为所有 Token 已经知道,所以 GPU 可以一次性并行计算整个 Prompt。

最终得到:

Prompt
↓
所有 Layer 的 KV
↓
写入 Cache

整个 Prompt 只需要 Forward 一次。

这一步通常拥有非常高的 GPU 利用率。


第二阶段 Decode

随后模型开始逐 Token 生成内容。

例如:

Go
↓
语言
↓
中
↓
...

每生成一个 Token:

都会:

计算新的 Q
↓
计算新的 K
↓
计算新的 V
↓
追加到 Cache

因此 KV Cache 会不断增长。

这里需要注意:模型自己生成的 Token,也会成为后续生成的上下文。

这也是 Transformer 被称为 Autoregressive(自回归)模型 的原因。


为什么 Context Window 越长越慢?

现在很多模型支持:

  • 128K
  • 200K
  • 甚至 1M Context

很多人认为:"上下文越长,只是缓存多一点而已"

事实上,问题没有这么简单。假设已经拥有:

100000 Token

KV Cache 中已经保存了:

100000 Token × 32 Layer × Key × Value

当模型生成下一个 Token 时:

虽然不用重新计算历史 Token。

但是,Attention 仍然需要读取:

Q_new × 100000 个历史 Key

然后再根据权重读取:

100000 个历史 Value

因此:上下文越长,每生成一个 Token,需要读取的 KV 就越多。

真正的瓶颈逐渐从 计算 → 显存带宽(Memory Bandwidth)


超长上下文效果会下降是否与 KV Cache 有关系

阅读完上面对于 KV Cache 的讲解,你可能会联想到我们用 AI 时的超长上下文问题,是不是也会因为 KV Cache 过多而受到影响?

模型在超长 Context 下效果下降,更多来自三个方面:

  • Attention 稀释。需要关注的信息越来越多,模型更难把注意力集中到真正重要的位置。
  • 位置编码的限制。即使使用 RoPE、YaRN、LongRoPE 等技术,超长距离的位置表示仍然会逐渐失真。
  • 训练数据限制。很多模型主要训练于几千到几万 Token 的上下文。

当直接推理 100 万 Token 时,模型实际上并没有见过这么长的上下文,自然容易出现性能下降。

因此KV Cache 主要影响的是推理效率,而不是模型理解能力。


为什么现在几乎所有推理框架都在优化 KV Cache?

对于现代推理框架来说,模型参数通常只需要加载一次。真正不断增长的是 每个用户会话的 KV Cache。

例如:

1000 个用户
↓
1000 份 KV Cache

随着 Context 增长,KV Cache 很可能比模型参数本身还占显存。因此,近年来大量推理优化技术,例如:

  • FlashAttention
  • PagedAttention
  • Multi-Query Attention(MQA)
  • Grouped-Query Attention(GQA)

几乎都围绕:如何减少 KV Cache 的占用、提升读取效率。

可以说现代大模型推理真正的瓶颈,很多时候不是 GPU 算力,而是如何高效管理和读取 KV Cache。

当然现在很多企业其实一定程度上还是受到 GPU 算力影响,毕竟产品是需要针对于外面客户使用的,越强的算力就意味着能够支撑更好的模型、更快地效率、更强有力的竞争价格。上面的说法只是单独针对于大模型的现阶段的发展方向而言。

总结

KV Cache 的思想其实并不复杂:

  • 历史 Token 的 Key 和 Value 不会变化,因此只计算一次。
  • Query 是一次性的,因此没有缓存价值。
  • Prompt 在 Prefill 阶段一次性建立 KV Cache。
  • 模型生成的新 Token 会不断追加自己的 KV,形成新的上下文。
  • Context 越长,KV Cache 越大,每一步需要读取的历史信息越多,因此推理速度逐渐下降。

从工程角度来看,KV Cache 是一个强有力的必要优化,是现代 Transformer 推理能够高效运行的基础。如今围绕 KV Cache 的压缩、共享、分页和管理优化,也已经成为 LLM 推理框架中最活跃的研究方向之一。

PREV
[每日算法] 基本计算器
NEXT
[LLM] 粗浅理解大模型 Promot Cache

评论(0)

发布评论