L

[LLM] KV Cache的多种策略

RoLingG 其他 2026-06-30

KV Cache的多种策略

粗浅理解大模型 KV Cache 中,我们已经了解了 KV Cache 的作用:缓存历史 Token 的 Key 和 Value,避免每次生成新 Token 时重新计算整个上下文。

但是,你会发现文章中通篇都在提 KV Cache 进行缓存数据,但并没有聊到在什么情况下会触发缓存,缓存又是什么都缓存还是有一定规则缓存?

这是因为 KV Cache 的缓存策略其实过多过于复杂,单单一两句话讲不清楚,下面让我们一起从 Hugging Face 官方文档给出的描述,慢慢了解 KV Cache 相关的缓存策略。

使用 Hugging Face 官方的描述是因为其较为主流,具有一定的代表性,但不完全等于整个行业的设计和发展方向。如有什么问题,恳请指出,本文会积极修改。

Hugging Face 官方文档提供了很多种 Cache:

  • Dynamic Cache
  • Static Cache
  • Offloaded Cache
  • Quantized Cache
  • Sliding Window Cache
  • Sink Cache

这些都是不同的缓存管理策略(Cache Strategy)。真正变化的不是 Transformer,而是如何管理 KV Cache


为什么需要不同的缓存策略?

如果让我们自己实现一个最简单的 KV Cache,大概率会写成这样:cache = append(cache, newKV)

每生成一个 Token:

  1. 计算新的 K、V。
  2. 追加到缓存末尾。
  3. 下一轮继续使用。

整个流程非常简单。

但是,当上下文从 4K Token 变成 128K Token 甚至 1M Token,事情就没那么简单了。

这时候会遇到很多工程问题,例如:

  • GPU 显存够不够?
  • 一直 append 会不会导致内存重新分配?
  • 多个用户同时推理怎么办?
  • Beam Search 怎么共享缓存?
  • 长上下文是不是一定要全部保留?

所以,现代推理框架开始研究:KV 应该怎么存?怎么释放?怎么压缩?怎么共享?

于是就有了各种 Cache Strategy。


各种缓存策略

Dynamic Cache(动态缓存)

这是最直观,也是 Hugging Face 默认使用的方式。

它的工作方式非常简单:

Token1
 ↓
KV1
 ↓
Token2
 ↓
KV2
 ↓
Token3
 ↓
KV3

每生成一个 Token,就把新的 KV 追加到缓存中,缓存会不断增长。

优点

  • 实现简单。
  • 不浪费空间。
  • 上下文长度可以动态增长。

缺点

由于缓存不断扩容,GPU 可能需要重新申请内存。

如果上下文非常长,就可能出现:

  • 内存碎片
  • 扩容开销
  • Batch 管理困难

因此,Dynamic Cache 更适合普通聊天场景。

例如:

你好
 ↓
介绍一下 Go
 ↓
Go GMP 为什么高效?

上下文长度无法提前预测。


Static Cache(静态缓存)

Static Cache 的思路正好相反。

它不会随着生成动态增长,而是在一开始就申请好全部空间。

例如:最大支持 128K Token

那么一开始就直接申请:

□□□□□□□□□□□□□□□□□□□□□□□□

假设目前只有 100 Token

那么实际使用的是:

■■■■□□□□□□□□□□□□□□□□□□□□

后面生成的新 Token,只需要继续往后写。

优点

整个缓存地址不会变化。

GPU 很喜欢这种固定地址,因为:

  • 更容易优化
  • 更适合 CUDA Graph
  • 推理速度更加稳定

缺点

  • 空间浪费。如果你的上下文只有 512 Token,却申请了 128K Token,那么绝大多数空间都会浪费。

因此,Static Cache 更适合生产部署。


Offloaded Cache(缓存卸载)

KV Cache 最大的问题其实不是计算,而是 占显存。

假设 GPU 拥有 80GB,模型已经占用了 60GB,那么 KV Cache 可能很快就把剩下的显存占满。怎么办?

一种思路就是:把不用的 KV 放到 CPU 内存。

例如:

  • GPU:最近 8K Token
  • CPU:更早的 100K Token

需要的时候再搬回来。

这个思想其实很像操作系统里的 Swap

优点

可以支持非常长的上下文。

缺点

  • CPU 和 GPU 之间的数据传输远远慢于 GPU 显存,因此推理速度会下降。

通常用于:

  • 长文档分析
  • 法律文本
  • 小说生成

Quantized Cache(量化缓存)

KV Cache 本质上是一堆浮点数。

例如:FP16 每个元素占 2 Byte,如果改成 INT8,那么就只占用 1 Byte,显存占用直接减半。进一步 INT4 还能继续减少更多占用。

因此,量化 Cache 的目标就是用更少的显存保存更多 Token。

优点

  • Context 可以更长。
  • GPU 显存压力明显下降。

缺点

  • 量化不可避免会带来一定精度损失。

不过大量研究表明:KV Cache 对量化其实比较敏感,但经过专门设计后,影响可以控制得很小。

因此,近年来 KV Quantization 已经成为热门研究方向。


Sliding Window Cache(滑动窗口)

如果一直保存所有 Token,缓存一定越来越大。那么能不能只保留最近的一部分?

例如:

窗口大小:8K Token

那么:

Token1
  ↓
Token8000

一直保留。生成:

Token8001

以后,最早的:

Token1

直接丢弃。窗口变成:

Token2
  ↓
Token8001

一直向前滑动。

优点

显存占用始终保持稳定。

缺点

  • 模型会忘记很久以前的内容。

因此适合:

  • 长时间聊天
  • 实时对话

而不适合:

  • 需要完整上下文的推理任务。
Gemini 的缓存思路,基本就是这个策略,其他的一些早期的大模型也是这种遗忘策略。

6. Sink Cache(Attention Sink)

Sliding Window 有一个问题:有些 Token 是不能删的。

例如:

System Prompt
      ↓
你是一位 Go 专家。

如果把它删掉:

模型的人设就没了。

因此:

Sink Cache 会把:

  • 开头的重要 Token
  • 最近生成的 Token

同时保留,中间部分则允许被丢弃。

示意图:

[System Prompt]
        ↑
     永远保留
......
[最近8K Token]
        ↑
     永远保留

因此,它比普通 Sliding Window 更智能。很多 Agent 系统都会采用类似策略。


这些策略可以组合使用吗?

多种策略其实是针对于不同场景使用,它们关注的是不同问题。

例如:

  • 对策略 Static:缓存如何组织?
  • Quantized:缓存如何压缩?
  • Offloaded:缓存放在哪里?
  • Sliding Window:缓存保留哪些内容?

因此完全可以组合。

例如:Paged Cache + Quantized Cache + Offloaded Cache 都是现实中存在的方案。


工程实践中如何选择 KV Cache?

了解完各种缓存策略后,一个很自然的问题就是:实际部署大模型时,到底应该选择哪一种?

事实上,并没有一种策略能够适用于所有场景。不同的缓存策略,本质上是在 性能、显存占用、上下文长度 三者之间做取舍。

下面举一些例子:

普通聊天机器人

特点:

  • 上下文长度不可预测
  • 更关注响应速度
  • 用户数量较多

通常会优先选择:

  • Dynamic Cache
  • Paged Cache(多数现代推理框架默认采用)

这样既能够灵活增长上下文,又能保证较好的显存利用率。


长文档分析

例如:

  • 法律合同
  • 学术论文
  • 技术文档

特点:

  • Context 非常长
  • 更关注能够容纳更多 Token

通常会结合:

  • Quantized Cache
  • Offloaded Cache

必要时还会配合更大的 Context Window,以换取更长的上下文处理能力。


在线聊天、Agent

对于持续数小时甚至更长时间运行的 Agent 来说:

无限增长的 KV Cache 并不现实。

因此很多系统会采用:

  • Sliding Window
  • Sink Cache

既保留模型的长期设定(System Prompt),又控制缓存大小,使显存占用保持稳定。


高并发推理服务

对于需要同时服务大量用户的推理服务器来说:

真正重要的不只是单次推理速度,而是:

  • GPU 利用率
  • 显存碎片
  • Batch 调度效率

因此:

现代推理框架(如 vLLM、TensorRT-LLM、SGLang)往往会采用:

  • Paged Cache
  • Static Cache
  • Quantized Cache

甚至组合多种策略,以获得更高的吞吐量。


从上述例子中可以发现缓存策略并不存在 "最好" 这一说,只有是否适合当前业务场景。

很多时候,一个成熟的推理框架都会同时结合多种缓存策略,而不是只依赖某一种实现。


总结

KV Cache 从来都不是一种固定的数据结构,而是一套缓存管理思想。

随着上下文越来越长、用户越来越多,真正影响推理性能的已经不仅仅是模型本身,而是 KV Cache 如何存储、如何压缩、如何释放、如何共享

因此,不同 Cache Strategy 的目标其实可以归纳成三个方向:

目标对应策略
如何存储 KVDynamic、Static、Paged
如何减少显存占用Quantized、Offloaded
如何管理超长上下文Sliding Window、Sink

也正因为如此,如今众多推理框架,很多优化工作都集中在 KV Cache 的管理上。可以说,现代 LLM 推理的竞争,很大程度上已经从 "模型算法" 转移到了 "缓存工程"。

PREV
[LLM] 大模型处理Token流程
NEXT
[LLM] Paged Cache策略

评论(0)

发布评论