KV Cache 是什么?为什么大模型长上下文推理这么吃显存?
面试怎么回答
生成每个新 Token 时注意力要用到前面所有 Token 的 Key 和 Value,KV Cache 就是把算过的 K、V 缓存下来,每步只算新 Token,用显存换计算。它的大小约等于 2 乘层数乘 KV 头数乘头维度乘序列长度乘字节数,随序列长度和并发数线性增长,长上下文时单请求能到十几 GB,甚至超过模型权重,直接挤压了并发数。优化上模型层面用 GQA、MQA 减少 KV 头数,或滑动窗口注意力;系统层面用分页管理减少碎片、KV Cache 量化、前缀共享、卸载到 CPU 或 SSD;应用层面控制上下文长度、压缩长对话,长上下文请求单独规划容量。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
同一个模型,输入从 4K Token 变成 128K Token,能同时服务的请求数从几十个掉到个位数,显存频频不足。原因就在 KV Cache。面试官问这题,想看你能不能讲清 KV Cache 的作用、大小怎么估算,以及有哪些优化思路。
KV Cache 是什么
Transformer 生成每个新 Token 时,注意力机制需要用到前面所有 Token 的 Key 和 Value 向量。如果每生成一个 Token 都重新计算前面所有 Token 的 K 和 V,计算量会随长度平方增长。
KV Cache 就是把已经计算过的 K 和 V 缓存起来,生成新 Token 时只计算新 Token 的 K、V 并追加进去。这是用显存换计算。
大小怎么估算
单个请求的 KV Cache 大小约为:
2(K 和 V)× 层数 × KV 头数 × 每个头的维度 × 序列长度 × 每个数值的字节数
以一个中等规模的模型为例,粗略量级是每个 Token 占用几十 KB 到上百 KB。那么:
- 4K Token 的请求,KV Cache 几百 MB;
- 128K Token 的请求,KV Cache 可以达到十几 GB,甚至超过模型权重本身。
KV Cache 随序列长度线性增长,随并发请求数线性增长。显存 = 模型权重 + 所有请求的 KV Cache + 运行时开销,所以长上下文直接挤压了并发数。
优化思路
模型结构层面
- GQA / MQA:多个查询头共享一组 K、V 头,KV 头数减少,KV Cache 成倍缩小。现在很多模型都采用了 GQA;
- 其他注意力结构的改进,比如滑动窗口注意力,只保留最近一部分 Token 的 KV。
推理系统层面
- 分页管理:像操作系统管理内存页一样管理 KV Cache,按需分配,减少碎片和预留浪费(vLLM 的 PagedAttention);
- KV Cache 量化:用 FP8 或 INT8 存储,显存减半甚至更多;
- 前缀共享:多个请求共享相同前缀的 KV Cache;
- 卸载:把暂时不用的 KV Cache 放到 CPU 内存或 SSD,需要时再加载。
应用层面
- 控制上下文长度:不要因为窗口大就把所有内容都塞进去;
- 长对话做压缩和摘要;
- 不同长度的请求分到不同的部署,长上下文请求单独规划容量。