上一篇我们知道了 KV Cache 的核心矛盾:不存不行(O(n²)太慢),全存也不行(内存爆炸)。这篇来看解决方案——从”少存一点”到”存得更聪明”。

策略一:共享 KV 头——MQA / GQA / MLA

问题:32 个头真的需要 32 套独立的 KV 吗?

标准 Multi-Head Attention(MHA)中,每个注意力头有自己独立的 Query、Key、Value 投影。32 个头 = 32 套 K 和 V 存储在 cache 中。

但仔细想想——不同头的 Key 和 Value 之间高度相关。它们都在表示同一段文本的信息,只是从不同”角度”看。这种冗余可以利用。

从 MQA 到 GQA 到 MLA:越来越精细的共享

MHA 每头独立KV K₁ K₂ K₃ K₄ V₁ V₂ Cache: 8 向量/token 压缩: 1× GQA 分组共享KV K组1 K组2 Q₁Q₂→组1 Q₃Q₄→组2 Cache: 4 向量/token 压缩: 2× MQA 全部共享1组KV K Cache: 2 向量/token 压缩: 4× MLA 低秩压缩潜向量 c_t d_c ≪ H×d_h Cache: ~0.5 向量 压缩: 16-32×

MQA (2019):所有 query 头共享一组 KV。压缩最狠(32×),但质量有损——一个 KV 头承载所有信息,成了瓶颈。

GQA (2023, LLaMA 2 采用):把 32 个 query 头分成 8 组,每组共享一个 KV 头。4× 压缩,质量损失几乎可忽略。这是当前最流行的方案。

MLA (2024, DeepSeek-V2):最激进——不存 K 和 V 本身,而是存一个低秩压缩潜向量 $c_t$,需要时再解压还原。压缩 16-32×,质量反而更好(因为联合优化了压缩方式)。

策略二:量化——用更少的位数存

KV Cache 默认用 FP16(16位)。但实验发现,attention 对 K/V 的数值精度并不那么敏感。

  • INT8 量化:每个值从 2 字节降到 1 字节 → 2× 内存减半,质量损失 < 0.5%
  • INT4 量化:4 位存储 → 4× 压缩,需要更精细的量化策略
  • KIVI (2024):发现 Key 和 Value 有不同的量化特性(Key 按通道有异常值,Value 按 token 有异常值),针对性地用不同策略量化到 2 位,质量几乎无损

量化可以和 GQA/MLA 叠加:GQA (4×) + INT4 (4×) = 16× 总压缩

策略三:PagedAttention——像操作系统管内存

碎片化才是真正的敌人

传统系统给每个请求预分配一大块连续内存(准备好最大可能长度)。但大部分请求用不了那么多——就像停车场全画大车位,结果来的都是小车。

研究表明 60-80% 的 KV Cache 内存被碎片化浪费

PagedAttention 的操作系统思维

vLLM 的 PagedAttention 直接借鉴了操作系统的虚拟内存管理:

传统:连续预分配 Seq A 实际 浪费 (预分配) Seq B 实际 浪费 外部碎片 (无法利用) C 巨大浪费 利用率: ~20-40% PagedAttention:分页按需分配 A B A C B B A C B Block Table: A→[0,2,6] B→[1,4,5,8] C→[3,7] 非连续存储,按需分配,用完释放 利用率: ~96%+ 吞吐提升 2-4×

核心思想:把 KV Cache 切成固定大小的页(blocks),散落在 GPU 内存的任何位置。用一个”页表”记录每个序列的 blocks 在哪。按需分配,用完即释。

效果:内存浪费从 60-80% 降到 < 4%,同一张 GPU 可以同时服务 2-4× 更多请求

策略四:选择性遗忘——不是每个 token 都值得记住

如果上下文实在太长,即使压缩+分页也装不下呢?一个激进但有效的思路:只保留重要的 token,扔掉不重要的。

H₂O (Heavy Hitter Oracle):追踪每个 token 累积获得的 attention 分数。高分的(”重量级选手”)保留,低分的淘汰。只保留 20% 的 KV Cache 就能维持质量。

StreamingLLM:发现了一个有趣现象——序列最开头的几个 token(不管内容是什么)会获得异常高的 attention,它们是”注意力水槽”(attention sinks)。如果你把它们删了,模型就崩了。解决方案:永远保留前 4 个 token + 最近 L 个 token 的滑动窗口。可以稳定生成超过400 万 token 而内存不增长。

滑动窗口 (Mistral):更简单粗暴——只保留最近 W 个 token 的 KV(W=4096),超过的直接覆盖。通过多层堆叠,有效感受野远大于 W。

这些技术可以叠加

一个生产级系统可能同时使用:

  • GQA (架构层面) → 4× 压缩
  • INT4 量化 (精度层面) → 4× 压缩
  • PagedAttention (内存管理) → 消除 60-80% 浪费
  • H₂O 淘汰 (容量控制) → 再减 5×

总效果:相比朴素 MHA + FP16 + 连续分配,可以实现 50-100× 的等效内存节省

下一篇我们来看一个更上层的优化:如果很多请求的 prompt 开头都一样(比如系统提示、few-shot 示例),能不能只算一次前缀的 KV Cache,后面所有请求复用?这就是 Prompt Caching——一个能帮你省 90% API 账单的技术。