1. KV cache 到底缓存了什么
在每一层 self-attention 中,已生成或已输入的 token 都已经被投影为 key K 和 value V。下一 token 的 query 不必重新计算旧 token 的 K/V,只需读取它们与新 query 做 attention。于是每个 active sequence 保留每层、每个历史位置的 K/V;新 token 到来时,追加一小块状态。
这里的“cache”与 HTTP response cache 不同:它是模型内部状态,只有当模型权重、位置编码、token 前缀、adapter 和相关执行配置语义一致时,才能安全复用。它也不等于 hidden state;通常保存的是 attention 所需的 projected K/V 表示。
2. 先算字节:为什么 KV 很快超过直觉
对标准 multi-head attention,单个 token 的总 KV 原始字节可粗估为:
例:80 层、8 个 KV heads、128 head dim、BF16(2 bytes),约为 2 × 80 × 8 × 128 × 2 = 327,680 bytes,即每 token 约 320 KiB。一个 128K-token 会话原始 KV 约 40 GiB;这还未计 page table、对齐、运行时余量和并发。这只是标准注意力公式,MLA、压缩 KV、局部/稀疏注意力会有不同状态结构,必须回到模型与引擎实现重新计算。
3. GQA、MLA 和稀疏 attention 改了哪个乘数
GQA 让多组 query heads 共享一个 KV head,直接减小公式中的 Hkv,因此既少占 KV,也少读 KV。MQA 是更极端的共享。MLA 或类似潜变量/压缩表示不保留每个头完整 K/V,而使用更小的 latent 或分解表示;其速度收益取决于重建计算、kernel 和 cache layout 是否高效。稀疏/局部 attention 则可能减少每一步需要读取的历史范围,但未必减少已存状态总量。
“KV cache 压缩”这个说法容易混淆层次。模型结构、存储格式、decode 访问集合和运行时量化都可能减少字节,但作用位置不同。部署记录应分别写清逻辑 token 状态、物理存储格式,以及 attention kernel 实际读取的内容。
4. 为什么采用 page/block 而不是为每个请求预留连续数组
在线请求长度不一致且不断结束。若给每个 sequence 预留最大长度的连续 KV 数组,绝大部分空槽浪费 HBM,而且频繁申请释放会造成碎片。PagedAttention 将 KV 切成固定 token 数的 physical blocks;每个 sequence 只维护从逻辑 block 到物理 block 的映射表。随着 token 追加,分配一个新 block;结束时归还 blocks。
这类似虚拟内存的页表,但不是 CPU 虚拟内存替代品。它的 page size 是服务引擎决定的 token block;GPU attention kernel 通过 block table 找到各段 K/V。page 越小,浪费越少、共享粒度更细,但表项、调度和 kernel 间接寻址更多;page 越大则相反。
5. Prefix sharing:同一块 KV 可以有多个拥有者
长 system prompt、相同文档前缀、树形 beam、agent 共同历史可共享已完成的 KV blocks。常见实现用哈希将完整 block 的 token 内容与必要配置标识为 key;后续请求找到最长匹配 block 链并引用它,而不是重算 prefill。对共享 block 需要引用计数或不可变版本语义:一个请求追加 token 时只能分配新的尾部 block,不能改写共享 prefix。
安全的 cache key 至少要覆盖模型权重/版本、token IDs、位置处理、LoRA/adapter、KV dtype/布局、multimodal token 化与预处理配置。仅按原始字符串或 URL 命中会产生语义错配。跨租户共享还涉及私密 prompt、文档权限和删除权,不能因为技术上可复用就默认允许。
6. 内部碎片、外部碎片与显存水位
固定 page 的最后一个 block 常未写满,这是内部碎片;不同大小、不同 dtype 的对象混排导致难以分配连续空间,这是外部碎片。运行时还必须预留 activation、CUDA graph workspace、NCCL buffer、临时候选 token、图像/视频编码状态,因此“KV 总空闲字节”不等于“可以接一个新长请求”。
生产系统通常用 token/block budget 而非纯请求数 admission:在高水位前拒绝或排队超长输入;必要时抢占低优先级 sequence,把其可恢复状态换出;并留出 headroom 防止一个 iteration 在新 token 写入时 OOM。若只在 OOM 后再清理,尾延迟和稳定性都会很差。
7. 逐出不是 LRU 一句话就能解决
对于可重算的 prefix cache,LRU 是一种起点,但价值还取决于 block 长度、重算 prefill 成本、命中概率、位置是否靠前、租户配额、数据敏感等级和所在 worker。对于正在 decode 的 session,直接逐出意味着暂停甚至重算;对于 agent 中途等待工具的 session,保留它的 KV 可能比保留一段公共 prompt 更重要。
较合理的策略把状态分层:活跃 decode 保持在 HBM;可恢复但近期可能返回的 session 进入 CPU/DRAM 或远端层;高价值共享 prefix 保持可路由;低价值冷条目过期。任何 policy 都要测量 hit-rate、节省的 prefill token、miss 的尾延迟、迁移字节和 eviction 后重算,不能只报告一个命中率。
8. KV 量化:减少字节,增加格式与精度责任
把 K/V 从 BF16/FP16 改存为 FP8、INT8、INT4 或分组量化表示,可以容纳更多 token;代价是 attention kernel 读取时要应用 scale 并处理数值范围。不同层、head 和 block 的统计特性各异。更细的量化粒度通常精度更好,同时也会增加 metadata。某些模型和长上下文任务对 KV 误差尤其敏感。
应分别验证短问答、长文档检索、代码、工具调用以及多轮 conversation 的准确性,尤其观察深层 token 与罕见事实的退化。性能评估还要包含反量化开销、page 对齐和 cache transfer:标称“4x KV 压缩”不一定等于端到端 4x 更多有效会话。
9. HBM、CPU、NVMe 与远端 KV 的分层
HBM 延迟和带宽最适合正在 decode 的 KV;CPU DRAM 容量大但经过 PCIe/NVLink-C2C 等路径,若每个 decode step 都去取会损害 ITL;NVMe 更适合冷数据或 checkpoint 式恢复,不适合热 token-by-token attention。远端 GPU/内存层能在数据中心共享容量,但需要 RDMA、可靠传输、placement 和网络隔离。
用于当前 decode 和最近复用的 prefix;容量最稀缺,必须严格计划水位。
用于暂停会话、共享缓存或跨 PD 转交;容量更大,但每次恢复都要计入网络/复制代价。
“KV 可以放在 SSD”只意味着可持久保存或按需恢复,不代表在线 decode 能以相同 ITL 使用它。
10. PD 分离中的 KV transfer 是一次数据面协议
prefill worker 生成的 KV 要供 decode worker 使用。传输协议必须说明 block 的物理格式、dtype、版本、层顺序、校验、传输完成通知和失败重试;调度器要把后续 decode 路由到已经完整接收必要 blocks 的 worker。若传输和 decode 可流式重叠,还要保证“某层/某 block 可用”的依赖边界。
数十万 token、几十层的 KV 可能达到数 GB,远超普通 RPC payload 的处理方式。迁移会同时占用网卡、PCIe/NVLink、GPU copy engine 和目标 HBM。评估 PD 分离时必须扣除这些资源成本,并验证网络故障、worker 重启和重复请求下的正确性。后续 08 讨论控制面与路由。
11. 共享与多租户需要什么边界
KV 可以包含用户输入、检索文档、工具结果和系统提示的隐式表示。即便它不是可直接阅读的原文,也属于敏感推理状态。多租户系统应将 cache namespace、访问控制、TTL、加密/传输安全、审计和删除请求纳入设计;跨租户 prefix dedup 只有在明确允许的公共内容集合中才可考虑。
还有一个容易遗漏的边界是模型升级:不同权重、不同 tokenizer、不同 RoPE scaling、不同 KV quantization 版本的 blocks 不可混用。cache key 和 rollout 策略必须把版本隔离做成硬约束,否则会出现难以定位的输出错误。
12. 一个容量规划例子
继续使用第 2 节的约 320 KiB/token 例子。若希望在一台机器上同时支撑 16 个、每个平均保留 32K token 的会话,原始 KV 约为 16 × 32K × 320 KiB ≈ 160 GiB,还未加入共享/尾块/工作区。使用 GQA 更多 KV heads 减少、FP8 KV、prefix sharing 和合理的 block allocator 都可能降低实际占用;但它们各有模型与质量条件,不能把这四种收益简单相乘。
容量计划至少要列出模型配置、KV bytes/token、目标平均与最大上下文、活跃 session、共享率假设、各 tier 容量、headroom 以及目标 miss/eviction 率。有了这些字段,才能反推 GPU 数量,并判断是否需要 PD 或远端 KV。
13. 来源与进一步阅读
- vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention:分页 KV 与共享块基础。
- vLLM Automatic Prefix Caching 设计文档:hash、block 与引用的实现边界。
- KIVI: A Tuning-Free Asymmetric 2bit Quantization for KV Cache:KV 量化代表性工作。
- Mooncake:KV cache disaggregation 的系统背景。
- RTP-LLM 与 Scaling Pain:2026 层级 KV、RDMA 和生产经验。