04. 注意力与 KV 缓存
本篇导读
上一篇把 KV 看作显存中的计算便笺。本篇接着拆开它:便笺记了什么、为什么能保留、什么时候能共用、怎样摆放。先比较有无便笺的重复工作,再区分 KV cache、前缀缓存、PagedAttention 与 FlashAttention;最后才接触具体索引和公式。
有便笺与没有便笺
小林的问题已经读完,模型开始写“先、提交、申请”。如果每写一块,都为全部历史位置重新建立 K/V,旧工作就会反复做。保留这些状态后,下轮只需为新位置建立自己的 K/V,再查询已有历史。
年假怎么申请?先提交读题新算新算新算新算——接着写复用复用复用复用新算—再写复用复用复用复用复用新算
本轮计算已有状态
三轮共建立 4 + 1 + 1 = 6 个位置的 K/V。历史便笺保留下来,只为新位置建立状态。
词块仅为教学 token。这里只数 K/V 位置的重复建立;每个新位置仍要查询历史,表格不代表整体 FLOP 或加速倍数。
这就是 KV cache 的第一层意义:在同一条生成序列里,保存已经计算过的历史状态。它保存的是多层数值数组,不是完整答案,也不是把原文复制进一个普通笔记本。
Q、K、V 可以怎样理解
可以用“拿着问题查索引,再读取内容”帮助记忆:Q 是当前查询,K 参与计算与各历史位置的关联,V 是随后加权汇总的信息。它们都由模型投影得到,并不是人手编好的关键词目录。
缓存避免重复建立历史 K/V,新查询仍要使用历史信息。因此资料越来越长时,每一步仍可能更慢;有便笺不代表查便笺没有成本。
深入:注意力公式与缓存成立条件
Attention(Q,K,V) = softmax(QKᵀ / √d + causal_mask)V。常规因果模型中,历史位置不依赖未来 token,可以保留各层 K/V;新位置计算自己的 Q/K/V,再查询历史。通常不必缓存所有旧 Q,因为下一步主要使用新位置的 Q。
不同位置、LoRA、模板、模型和多模态输入可能改变状态。滑动窗口、MLA、递归与混合模型还需要各自的存储与恢复规则。
另一个人问同一份制度,能共用便笺吗
小林和小周都读同一段制度,只在末尾提出不同问题。此前缀的计算状态若兼容,就有机会跨请求复用,省去重复 prefill。这是前缀缓存,比同一请求内保留历史多了一步“查找别人是否已经算过”。
下面将输入写成显式 token ID,避免把文字相近误当成命中。先改末尾,再改开头,比较结果。
找到可复用的前缀显式 token ID 演示,最多显示 40 个
已缓存ABCDEFGHIJKL
新请求ABCDEFGXIJKL
相同前缀 7 token → 完整页可复用 4 → 至少重算 8
绿色是可复用页,黄色是相同但未凑成完整页的位置。首次不同时,后面即使再次相同也不能直接续用。此处假设模型、LoRA、位置及其他状态标识全部兼容;两个引擎的实际粒度还受模型与后端限制。
开头改动以后,后面虽然还出现相同字母,历史已经不同,不能直接接回旧状态。如果只允许完整页复用,还要把相同前缀向下取整到页边界。真正的页粒度受后端与模型限制。
便笺怎样放,怎样读
PagedAttention 像把便笺分成固定大小的小册页:逻辑顺序靠块表连接,物理上不必挤在一大片连续空间里。结束后可归还页,新增内容再申请页;未填满的尾页仍有内部浪费。
FlashAttention 关注计算时如何少搬运中间矩阵:分块处理,让更多中间结果留在片上。可以类比为在工作台边分批算完,避免把整张大草稿反复搬进搬出;它没有让常规稠密注意力的所有关联计算凭空消失。
分页负责放在哪里,前缀缓存负责谁能复用,FlashAttention 负责怎样更有效地计算和搬运。它们能够配合,不是互相替代的三个框架。
深入:引擎怎样找状态,为什么有时命中也不快?
vLLM 常规完整块路径将父块哈希、当前 token 与额外状态标识组织成键;SGLang 用压缩前缀树组织共享路径。索引之外,两者都要管理物理页、活跃引用与淘汰。一个请求结束,不能回收仍被另一个请求使用的页。
时间戳放在开头会缩短公共前缀;随机路由可能把热请求送往冷实例;CPU 或远端命中还要付传输成本。应观察命中 token、节省的 prefill、层级、队列和总时延,不能只看请求命中率。
常规精确 FlashAttention 优化 IO 和执行组织,并未把稠密注意力的二次运算改为线性。PagedAttention 也不自动等于 CPU 换页。稀疏注意力、窗口和近似淘汰是其他路线,要另评估质量。
本篇回顾
- KV cache 保存历史计算状态,减少重复建立;仍要读取相关历史。
- 跨请求复用要求兼容的相同前缀,文字语义相近不足以命中。
- 分页解决摆放,前缀缓存解决共享,FlashAttention 改善执行和搬运,可以共同工作。
便笺已经会保存和复用了。下一篇面对新的场景:许多同事同时提问,谁应该一起算,短请求为什么不必一直等长请求? 进入批处理与调度。
