这里说明 paged attention 的工作方式,并记录 minivLLM 的实现进度。
审计日期:2026-06-07。基于对 multimodal/minivLLM/ 的完整静态分析。
Paged attention 借鉴了操作系统虚拟内存的页表(page table)思想,将 KV cache 切分为固定大小的"页"(blocks)。 它可以解决 contiguous KV cache 的三大问题:
传统 contiguous buffer 为每个序列预分配 max_seq_len 的连续空间。
不同序列长度差异大时,短序列浪费容量,长序列可能需要动态移动数据。
序列从 100 token 增长到 200 token 时,contiguous buffer 可能需要将全部数据复制到新位置。 Paged attention 只需分配新 block,block table 追加一个新条目即可。
多个请求往往共享相同的 prefix(如 system prompt)。 Paged attention 允许多个 block table 指向相同的物理 block,避免重复存储,这就是 prefix caching。
minivLLM 当前使用的是 contiguous buffer,不是 paged attention。
KVCache 的形状为 (num_layers, max_seq_len, num_kv_heads, head_dim),是连续的一维分配,无 block table 间接寻址。
Paged attention 需要五个组件:Block 分配器、Block Table、Slot Mapping、Paged Attention Kernel 和调度器集成。 参考 vLLM 的 PagedAttention v1/v2 实现可作为学习指南。
utils/context.py 行 14)utils/context.py 行 12)config.py 行 12)从 contiguous buffer 改为 paged attention 的最小可用实现约 350 行 Python(纯 PyTorch,无 CUDA kernel):
| 模块 | 预估代码量 | 说明 |
|---|---|---|
| Block Manager | ~100 行 | 基于 Python list 的 block 分配/释放 |
| Block Table 管理 | ~50 行 | Tensor 形状 [batch_size, max_blocks_per_seq] |
| Paged Attention Matmul | ~50 行 | 逐个 block 做 Q×K^T,纯 PyTorch |
| 调度器 | ~150 行 | FIFO scheduler + prefill/decode 切换 |
前提条件:修复 B1(Attn 参数不匹配)和 B2(act_fn=None),将 KV cache 接入 forward。
minivLLM 的 Context 和 Config 中的 paged attention 字段与 vLLM 的 AttentionMetadata 接口设计一致,说明作者在规划时参考了 vLLM。当前这些字段仅为占位符,无实现。
| 组件 | 存在 | 状态 |
|---|---|---|
| Block Manager | 无 | 不存在 |
| Block Table(分配逻辑) | 无 | 不存在(字段定义存在但未使用) |
| Slot Mapping | 无 | 不存在(字段定义存在但未使用) |
| Paged Attention Kernel | 无 | 不存在(Attn.forward 为标准 MHA) |
| Scheduler 集成 | 无 | 不存在 |
| KVCache(当前实现) | 有 | Contiguous buffer,未接线 |
| Config 预留字段 | 有 | kvcache_block_size / num_kvcache_blocks |
| Context 预留字段 | 有 | block_tables / slot_mapping / context_lens |
| 特性 | Contiguous KV Cache | Paged KV Cache |
|---|---|---|
| 分配单位 | Token 级别(位置索引) | Block 级别(block_id 索引) |
| 内存碎片 | 严重(不同序列长度导致外部碎片) | 极少(统一 block 大小,内部碎片可控) |
| 多序列支持 | 困难(需每个序列独立分配连续空间) | 天然支持(block table 映射) |
| 动态增长 | 可能需数据迁移 | 只需分配新 block |
| Prefix Caching | 不支持 | 支持(多序列共享 block) |
| 实现复杂度 | 简单 | 中等(需 block manager + 间接寻址) |
| 内存布局 | [layer, pos, kv_head, head_dim] | [num_blocks, layer, block_size, kv_head, head_dim] |