# KV 缓存与分页注意力

拉普拉斯的迷你世界 · 图版 F55 · 人工智能

> 前面每个词元的键和值都要存着，越写越多。分成一样大的小块存放，像操作系统的内存页，写到哪里拿到哪里。

- 可交互的模型：https://world.lapla.si/zh/kvcache/
- 嵌入页：https://world.lapla.si/embed/zh/kvcache/
- English：https://world.lapla.si/en/kvcache/
- 更新于：2026-10-28

## 01 能做到什么

语言模型一次写一个词元。写每个新词元，注意力都要用到前面每个词元的键和值；把它们存着、不再重算，这份存储叫 KV 缓存。服务一个模型时，很多段话同时在写，各有各的缓存，都放在 GPU 的显存里。

2023 年的 vLLM 论文测得：在它之前的服务系统里，留给 KV 缓存的显存只有 20.4 % 到 38.2 % 真正存着词元的键和值。它提出的分页注意力（PagedAttention）把这个比例做到 96.3 %；在同样的延迟下，吞吐量是 FasterTransformer 和 Orca 的 2 到 4 倍。

台上中间是留给缓存的那块显存，做成一台有 44 个格位的机器：一个格位是一块，装 4 个词元；一个词元是一对针，圆头的是键，方头的是值，颜色表示它属于哪一段话。后面是块表，前面是每段话已经写出的字。

*之前的系统：存着词元的只有 20.4⁠–⁠38.2 % · 分页注意力：96.3 % · 同样延迟下吞吐量 2⁠–⁠4 倍*

## 02 一次写一个词元

论文把生成分成两步。先是提示词阶段：整段提示一次算完，同时得到每个提示词元的键和值。然后是生成阶段：每一轮只进一个词元，算出它自己的键和值，再和前面所有的键、值做注意力，得到下一个词元。（键和值是什么，见图版「Transformer 的注意力」。）

前面词元的键和值，在后面的轮次里不会再变，所以算一次就存起来，每一轮只算新的那一个。论文写道，生成阶段一轮只算一个词元，用不满 GPU 的算力，受内存的限制，一段话的延迟大多花在这里。

台上每一轮，在写的每段话先把自己的针亮一遍：读它全部的缓存；再落下一对新针，前面的字模也多一个。新来的一段话，整段提示的针一次落下。

*提示词阶段：整段一次 · 生成阶段：一轮一个词元 · 每一轮只算新词元的键和值*

## 03 一个词元 800 KB

每个词元在每一层都有一个键、一个值。论文的例子 OPT-⁠13B 有 40 层，每层的键和值各 5,120 个数，每个数用 2 字⁠节的 16 位浮点。一个词元就是 2 × 5,120 × 40 × 2 = 819,200 字⁠节，论文写作 800 KB。OPT 一段最长 2,048 个词元，一段话的缓存可以多到 1.6 GB。

论文的图 1：在一块 40 GB 的 NVIDIA A100 上跑 13B 的模型，权重占 26 GB，约 65 %；缓存约 30 %，按论文的表 1 是 12 GB，能放约 15,700 个词元的键和值。每段话都按 2,048 个词元算，只够 7 段。

台上切开一角：盖板下面是 40 层薄板，一层代表模型的一层。一对针从顶上一直穿到底，一个词元的键和值，每一层都有一份。

*OPT-⁠13B：2 × 5,120 × 40 × 2 字⁠节 ≈ 800 KB 一个词元 · 2,048 个词元 ≈ 1.6 GB*

## 04 先占好最长的位置

在 vLLM 之前，服务系统把一段话的缓存存成一整块连续的内存：深度学习框架里的运算，大多要求张量在内存里是连续的。一段话最后写多长，事先不知道，于是按它可能的最大长度，比如 2,048 个词元，一开始就留够。

论文在实验里重做了 Orca 的三种留法。全按最大长度留的那种，OPT-⁠13B 在 40 GB 的 A100 上平均一次只能同时写 7.00 段话，正是 12 GB 除以 2,048 个位置的结果。

台上换成这种做法：每段话一开始就占下连续的一整排格位，从头往后填。块表用不上了，翻牌都是空的。

*一段话一整块连续的内存 · 按最大长度先留够 · 12 GB 里只放得下 7 段 2,048 个词元*

## 05 三种浪费

论文把这种留法的浪费分成三种。预留：给还没写出的词元留着的位置，最后会用上，可在这段话写完之前，别人也用不了。内部碎片：按最大长度多留、到写完也没用上的位置。外部碎片：分配器在各段之间留下的空隙，太小，放不进新的一段。

外部碎片一开始就知道用不上；内部碎片要等一段话写完才知道。论文测得，三种 Orca 的缓存里存着词元的只有 20.4 %（按最大长度留）、26.8 %（最多多留一倍）和 38.2 %（假设事先知道每段写多长，实际做不到）。

台上：针是写好的词元；浅色的环是预留，暗色的环是内部碎片，灰色的环是外部碎片。

*存着词元的只有 20.4⁠–⁠38.2 % · 其余是预留、内部碎片、外部碎片*

## 06 像内存分页

分页注意力借的是操作系统的办法：虚拟内存和分页。操作系统把内存切成一样大的页；程序看来连续的页，可以落在不连续的物理内存里，也不用事先全部留好。论文的比方是：块就是页，词元就是字节，请求就是进程。

每段话的缓存切成块，一块装固定个数词元的键和值。在一段话自己看来，它的块是连续的，叫逻辑块；它们实际放在显存的哪里都行，叫物理块。块都一样大，所以没有外部碎片。

vLLM 默认一块装 16 个词元（论文 2023 年的设定，今天的 v0.32.0 仍以 16 为默认）。台上一块画 4 个，和论文的插图一样。一段话的针，散在各处的格位里。

*块是页 · 词元是字节 · 请求是进程 · vLLM 默认一块 16 个词元，台上画 4 个*

## 07 块表

每段话有一张块表。论文写道，表里每一项记下一个逻辑块对应的物理块，和这一块已经填了几个位置。台上后面的翻牌板就是块表：一行一段话，一格一个逻辑块，翻出来的数是物理块的编号，下面四个小点是填了几个。

新的物理块，只在前面的块都填满时才分配。所以一段话浪费的，最多是它最后一块里没填的位置，不到一块。论文的图 2 里，vLLM 的缓存有 96.3 % 存着词元。

注意力也按块来算：内核照着块表一块块取出键和值，块和块在显存里不必相邻。一段话写完，它的块就还回去，给别的话用。

*块表一项：物理块编号 · 已填几个 · 前面的块填满了才分配新块*

## 08 共用，写时复制

同一段提示要几个不同的回答时（并行采样），提示的缓存只存一份：几个回答的块表指向同样的物理块，每个物理块记一个引用计数，有几段话在用。

回答写出不同的词元以后，就不能再共用。轮到一个回答往共用的块里写时，系统先把这一块复制一份，写进副本，原来那块的计数减一；这叫写时复制，操作系统复制进程时也这样做。台上两个回答共用提示的两块；最后一块只填了一半，第一个回答要写进去时，它被复制到另一个格位。

论文测得，在 Alpaca 数据上跑 OPT-⁠13B，共用块省下的缓存：并行采样 2 到 6 个回答时 6.1 % 到 9.8 %，束搜索宽度 2 到 6 时 37.6 % 到 55.2 %。同样的实验换成 ShareGPT 数据，是 16.2 % 到 30.5 % 和 44.3 % 到 66.3 %。

*引用计数 2 → 1 · 写之前先复制 · 省下的缓存：并行采样 6.1⁠–⁠9.8 %，束搜索 37.6⁠–⁠55.2 %（OPT-⁠13B，Alpaca）*

## 09 放不下的时候

请求太多、块不够时，vLLM 先来先服务：最早到的先写，最晚到的先让出位置。一段话的块要么全留，要么全让，因为写下一个词元要用到它全部的缓存。

让出的块，论文给了两种办法：搬到 CPU 的内存里，轮到时再搬回来；或者干脆丢掉，轮到时把提示和已经写出的词元当成一段新的提示，一次重新算出缓存。论文测得，块很小时搬来搬去更慢；16 到 64 个词元一块时，两种做法差不多。

今天的 vLLM 去掉了论文里搬到 CPU 的那种做法，让出的请求重算。台上来的话比格位多：最晚开始的一段让出全部格位，等别的写完，再一次把针全部落回去。

*先来先服务 · 一段话的块全留或全让 · 搬到 CPU，或者丢掉重算*

## 10 快了多少

论文在 A100 上测了 OPT-⁠13B、66B、175B 和 LLaMA-⁠13B，按 ShareGPT 和 Alpaca 两个数据集里输入、输出的长度造出请求。同样的延迟下，vLLM 的吞吐量是 FasterTransformer 和 Orca 的 2 到 4 倍；序列越长、模型越大、解码方法越复杂，差得越多。

快在同时能写的段数。OPT-⁠13B，ShareGPT 数据，每秒 2 个请求：vLLM 平均同时写 30.42 段话，按实际长度留的 Orca 13.62 段，最多多留一倍的 9.81 段，按最大长度留的 7.00 段。

也有差得不多的时候：OPT-⁠175B 用 8 块 GPU 跑 Alpaca，显存宽裕、句子短，按实际长度留和最多多留一倍的 Orca 也能同时写很多段，瓶颈变成了算力。

*OPT-⁠13B，ShareGPT，每秒 2 个请求：同时 30.42 段 · 13.62 段 · 9.81 段 · 7.00 段*

## 11 后来的做法

很多请求开头相同，比如同一段系统提示。论文里，服务方可以为预先定好的前缀留出一组块，让请求直接共用。今天的 vLLM 默认自动做前缀缓存：每个写满的块按它的词元和它前面的全部内容算一个散列，新请求开头相同，就用现成的块。文档说，它只省下处理提示的时间，不加快生成新词元。SGLang 用基数树管理这些缓存。

也有办法让每个词元本身小一点：让几个注意力头共用一组键和值。Falcon-⁠7B 所有头共用一组，一个词元 8 KB；Llama 2 的 70B 模型 64 个头只配 8 组键和值，一个词元 320 KB，模型大得多，缓存却是 OPT-⁠13B 的五分之二。

还可以把缓存存得粗一点：vLLM 支持用 8 位浮点存，每个数 1 字⁠节，同样的显存放下约两倍的词元。（缓存的量化，见图版「大模型量化」。）

*前缀缓存：相同的开头只存一份 · 每个词元：OPT-⁠13B 800 KB · Llama 2 70B 320 KB · Falcon-⁠7B 8 KB*

## 12 它没有说的

分页省下的是浪费，不是每个词元的大小：一个词元的键和值还是那么多，缓存还是随着词元一个个变长。KV 缓存也不让模型能读更长的文字，能读多长是训练定的：Llama 2 的上下文从上一代的 2,048 个词元加到 4,096 个，靠的是训练。

按块去找也有代价。论文的测试里，vLLM 的注意力内核比 FasterTransformer 的慢 20 % 到 26 %；这只是注意力一个运算，整体上 vLLM 仍然快得多。论文也写道，训练，以及受算力限制、不是大语言模型的服务，用不上这套办法，反而可能更慢。

同一个词出现在不同位置，键和值不同，不能共用；能共用的只有完全相同的开头。

*每个词元的大小不变 · 能读多长由训练决定 · 注意力内核慢 20⁠–⁠26 %（论文的测试）*

## 13 拆开来看

台子拆成几件：带格位的盖板，44 块插板，一对对的针，40 层薄板，底座；后面是块表的翻牌板，前面是字模和字盘。

一块插板就是一个物理块，4 个孔位各插一对针。块表的每一格翻牌，指向一块插板。

*盖板 · 插板 · 键和值 · 40 层 · 底座 · 块表 · 字模*

## 14 实验台

拉杆选怎么分配：一块装 1、2、4、8 或 16 个词元，或者不分块，每段话一来就按最长 20 个词元占好一整排（“最长”）。另一个选项是一共来多少段话。每按一次“运行”都从头开始：一段段话陆续到来，写完就离开，放不下的要等。

读数：同时在写的最多几段，留出的内存里平均有多少存着词元，全部写完用了几轮。

这是本页的模型：44 块、176 个格，一段话最多 20 个词元，长短是随机定的，不是论文的测量。块越大，最后一块空着的越多；块小到一个词元，几乎不浪费，可论文说，块太小时 GPU 一次读得太少，反而慢。

*读数：同时最多几段 · 存着词元的比例 · 用了几轮*

**试一试**：一块装 1 个词元时，留出的内存里存着词元的比例是多少？装 16 个呢？一段话都先占好 20 个位置时，同时能写几段？

## 模型省略了什么

台上的机器是一个模型，不是 GPU 的样子。显存画成 44 块，一块 4 个格，一共 176 个词元的位置；论文里 A100 上留给缓存的 12 GB 能放约 15,700 个，vLLM 默认一块 16 个词元。40 层薄板是 OPT-⁠13B 的层数，台上一块里放着这 4 个词元在全部 40 层的键和值；vLLM 实际按层、按头分开存，论文说两种做法性能没有差别。一个字模算一个词元，真实的分词切法不同。每一轮放慢到一秒多；针亮起来，只是表示这一轮的注意力读到了哪些键和值。论文的 KB、GB 按 1,024 进位。

## 几个容易误会的地方

20.4 % 到 38.2 % 是留给 KV 缓存的那部分显存里的比例，不是整块显存的；比较的三种 Orca 是作者按论文自己重做的（Orca 没有公开），其中按实际长度留的一种要事先知道每段写多长，实际做不到。“浪费不到 4 %”是 vLLM 博客的说法，论文写的是“接近零浪费”，图 2 里是 96.3 %。2 到 4 倍是同样延迟下的吞吐量，在论文的模型和数据上测得。分页不让每个词元变小，也不让模型能读更长的文字。同一个词出现在不同位置，缓存不同，不能共用。搬到 CPU、按请求复制共用块这些做法，今天的 vLLM 已经改了：共用改由自动前缀缓存来做。

## 常见问题

### KV 缓存是什么？

写每个新词元，注意力都要用到前面每个词元的键和值；把它们存着、不再重算，这份存储叫 KV 缓存。

见：[01 能做到什么](https://world.lapla.si/zh/kvcache/#now)

### 分页注意力之前，KV 缓存的显存用上了多少？

2023 年的 vLLM 论文测得：在它之前的服务系统里，留给 KV 缓存的显存只有 20.4 % 到 38.2 % 真正存着词元的键和值。

见：[01 能做到什么](https://world.lapla.si/zh/kvcache/#now)

### OPT-13B 一个词元的 KV 缓存有多大？

一个词元就是 2 × 5,120 × 40 × 2 = 819,200 字⁠节，论文写作 800 KB。

见：[03 一个词元 800 KB](https://world.lapla.si/zh/kvcache/#size)

### 分页注意力为什么叫“分页”？

分页注意力借的是操作系统的办法：虚拟内存和分页。

见：[06 像内存分页](https://world.lapla.si/zh/kvcache/#pages)

### KV 缓存的写时复制是什么？

轮到一个回答往共用的块里写时，系统先把这一块复制一份，写进副本，原来那块的计数减一；这叫写时复制，操作系统复制进程时也这样做。

见：[08 共用，写时复制](https://world.lapla.si/zh/kvcache/#share)

## 资料来源

1. [Kwon、Li、Zhuang、Sheng、Zheng、Yu、Gonzalez、Zhang、Stoica（2023）：Efficient Memory Management for Large Language Model Serving with PagedAttention，SOSP 2023（arXiv 版）](https://arxiv.org/abs/2309.06180)
2. [同一篇论文，SOSP 2023 论文集（ACM）](https://doi.org/10.1145/3600006.3613165)
3. [Kwon、Li 等（2023）：vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention，vLLM 博客](https://vllm.ai/blog/2023-06-20-vllm)
4. [vLLM 文档：Automatic Prefix Caching（设计说明）](https://docs.vllm.ai/en/latest/design/prefix_caching/)
5. [vLLM 文档：Automatic Prefix Caching（功能说明）](https://docs.vllm.ai/en/latest/features/automatic_prefix_caching/)
6. [vLLM 文档：Metrics（KV Cache Offloading 一节）](https://docs.vllm.ai/en/latest/design/metrics/)
7. [vLLM 源代码 v0.32.0：vllm/config/cache.py](https://github.com/vllm-project/vllm/blob/v0.32.0/vllm/config/cache.py)
8. [vLLM 文档：Quantized KV Cache](https://docs.vllm.ai/en/latest/features/quantization/quantized_kvcache/)
9. [Zhang 等（2022）：OPT: Open Pre-trained Transformer Language Models](https://arxiv.org/abs/2205.01068)
10. [facebook/opt-⁠13b 的模型配置（Hugging Face）](https://huggingface.co/facebook/opt-13b)
11. [Vaswani 等（2017）：Attention Is All You Need](https://arxiv.org/abs/1706.03762)
12. [Pope 等（2022）：Efficiently Scaling Transformer Inference](https://arxiv.org/abs/2211.05102)
13. [Shazeer（2019）：Fast Transformer Decoding: One Write-Head is All You Need](https://arxiv.org/abs/1911.02150)
14. [Ainslie 等（2023）：GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints，EMNLP 2023](https://arxiv.org/abs/2305.13245)
15. [Touvron 等（2023）：Llama 2: Open Foundation and Fine-Tuned Chat Models](https://arxiv.org/abs/2307.09288)
16. [tiiuae/falcon-⁠7b 的模型配置（Hugging Face）](https://huggingface.co/tiiuae/falcon-7b)
17. [Zheng 等（2023）：SGLang: Efficient Execution of Structured Language Model Programs](https://arxiv.org/abs/2312.07104)
18. [NVIDIA：A100 Tensor Core GPU 数据手册](https://www.nvidia.com/content/dam/en-zz/Solutions/Data-Center/a100/pdf/nvidia-a100-datasheet-us-nvidia-1758950-r4-web.pdf)

## 数据

The machine is a model of the bookkeeping in Kwon et al., “Efficient Memory Management for Large Language Model Serving with PagedAttention” (SOSP 2023): 44 blocks of 4 token slots (vLLM’s default block is 16 tokens; the paper’s figures draw 4), 40 layer plates for OPT-⁠13B’s 40 layers. Its requests, their lengths and every count the page shows from the machine come from the page’s own simulation, not from measurements. The text on the type: eight quatrains of Tang poetry (Chinese page) and the openings of public-domain novels and the Gettysburg Address (English page), one character or one word to a token. Material presets, parts and the softbox studio of the site’s model kit are ported from AirsupHQ/machine-skill (MIT, © 2026 Air Supply Technologies Inc.).

## 许可 CC BY-NC 4.0

本页的文字、图片和模型采用 CC BY-NC 4.0 许可：可以免费用于教学和其他非商业用途，可以修改，请注明出自 world.lapla.si。上面列出的第三方素材仍按各自的许可。

https://creativecommons.org/licenses/by-nc/4.0/deed.zh-hans

## 引用这幅图版

拉普拉斯的迷你世界，图版 F55《KV 缓存与分页注意力》，https://world.lapla.si/zh/kvcache/，CC BY-NC 4.0，2026-10-28 更新。
