---
tags: [CANN]
doc_type: knowledge-note
返回目录: "[[计算机系/昇腾与CANN/大模型与算子专题学习导航|大模型与算子专题学习导航]]"
上一篇: "[[计算机系/昇腾与CANN/NPU推理并行策略设计|NPU推理并行策略设计]]"
下一篇: "[[计算机系/昇腾与CANN/MTP投机解码与多流预取|MTP投机解码与多流预取]]"
---

# 推理框架与 KV 缓存调度

推理框架把单次模型前向变成能持续接收请求的服务。除了计算模型，它还要决定哪些请求一起运行、KV 放在哪里、何时释放缓存，以及如何在首 Token 时延与整体吞吐之间取舍。模型计算基础见[大语言模型与推理系统](大语言模型与推理系统.md)。

## 1. 从请求到模型执行

以 SGLang 的典型结构为例，请求经过服务入口与 TokenizerManager，进入 Scheduler；调度器组织当前批次，由 TpModelWorker 和 ModelRunner 调用模型及注意力后端，最后完成采样与反分词。

![推理框架组件](.assets/CANN推理专题/framework-6.png)

调度器面对的不是一批完全相同的任务：新请求需要 Prefill，已有请求需要 Decode，还有请求刚结束或被取消。连续批处理允许在迭代边界调整批内请求，从而减少等待长请求结束造成的空闲。

vLLM 常以 PagedAttention 为代表，SGLang 常以 RadixAttention 为代表，但这不是二者能力的排他划分。现代框架都可能支持分页、前缀共享、分离部署和多种注意力后端，选型应比较目标版本的实际能力。

## 2. PagedAttention：逻辑连续，物理可分散

传统连续分配可能按最大序列长度为每个请求预留 KV，短请求会浪费空间。分页方式把缓存划成固定 Token 数的物理块，序列通过块表引用这些块。

![分页 KV 与块表](.assets/CANN推理专题/framework-12.png)

如果块大小为 $P$ 个 Token，第 $t$ 个 Token 对应逻辑块 $\lfloor t/P\rfloor$ 和块内偏移 $t\bmod P$。块表将逻辑块号转换为物理块号，注意力核按照该映射访问实际缓存。

请求只需随着生成增长逐步增加物理块。对单个序列最后一个未填满的块，闲置容量少于 $P$ 个 Token；完整系统仍有元数据、保留空间及其他内存池的开销，不能把分页等同于所有内存浪费都为零。

### 共享、引用计数与写时复制

![缓存共享与写时复制](.assets/CANN推理专题/framework-19.png)

多个请求拥有相同前缀时，可以引用相同的只读 KV 块。引用计数记录仍在使用该块的请求数；只有所有引用释放后才能回收。若共享的尾块尚未填满，而某个请求要写入自己的后续 Token，就需要写时复制，避免修改其他请求的缓存。

缓存管理必须与设备执行生命周期一致：请求已从队列删除，不代表相关异步核函数已停止访问它的内存。

## 3. RadixAttention：复用最长公共前缀

Radix Tree 将 Token 序列的公共前缀组织成树。新请求沿树匹配已有 Token，可以复用最长命中的前缀 KV，仅计算未命中的后缀。

![Radix 前缀缓存](.assets/CANN推理专题/framework-23.png)

前缀共享依赖计算语义一致：模型版本、Tokenizer、位置编码、Attention Mask、Adapter 等变化都可能使缓存失效。相同可见字符串也可能对应不同 Token 或模板，不能直接以字符串相同判断可复用。

缓存淘汰可以采用叶节点 LRU 等策略，但必须保护仍被活跃请求引用的节点。缓存感知路由能把请求送到已有前缀的副本，减少 Prefill；过度集中又可能造成排队，因此需要权衡缓存命中收益与负载均衡。

## 4. HiCache：让前缀缓存跨越设备内存

分层缓存可将热门 KV 留在 NPU HBM，把较冷数据放在主机 DRAM 或远端存储。这里的 L1、L2、L3 是软件缓存层级命名，不是处理器硬件一级、二级缓存。

![分层缓存及数据移动](.assets/CANN推理专题/framework-26.png)

一次命中可能需要匹配、异步预取、设备端安装和可用性确认。写回则把需要保留的缓存移向下层存储。只有当传输比重新计算更划算，且能被其他工作隐藏时，分层缓存才有实际收益。

设备计算可能偏好按层组织数据，跨层批量传输可能偏好按页组织数据。因此格式转换、搬运粒度和预取时机都属于缓存系统设计的一部分。缓存容量变大不代表命中后的访问时延也变小。

## 5. 隐藏调度开销与平衡专家负载

CPU 可以在设备执行当前批次时准备下一批，避免调度与设备计算完全串行。所谓低开销或零开销调度，通常表示大部分 CPU 工作被设备工作覆盖，并不意味着不需要 CPU，也不意味着后续 Token 可以绕过真实的数据依赖。

MoE 的 EPLB 通过统计专家热度、调整专家位置或引入副本，缓解热点专家。静态方案依赖预先观测；动态方案需要额外处理统计、权重迁移和映射切换。是否暂停服务、如何保持一致性，都与框架实现有关。

共享专家与路由专家在共同输入就绪后可能并行执行，最终输出处再汇合。并行收益取决于资源是否互补；如果两者争用同一计算单元或内存带宽，多流并不保证更快。

## 6. Chunked Prefill 与 PD 分离

Chunked Prefill 把长提示词拆成多个计算块，与 Decode 请求交错调度，避免一次长 Prefill 长时间占住设备。分块太小会增加调度和核启动开销，分块太大则可能抬高已有请求的输出时延。

Prefill/Decode 分离把两个阶段放在不同实例上，可以独立配置批大小、并行策略和设备资源。代价是把 Prefill 产生的 KV 传给 Decode 实例，并管理跨实例请求状态。

![Prefill 与 Decode 分离架构](.assets/CANN推理专题/framework-32.png)

典型流程是：建立传输会话，Decode 侧预分配缓存空间，Prefill 侧计算并分块发送 KV，接收侧确认必要数据到齐后进入运行队列。请求或会话标识用于关联两端状态，不能把不同请求的数据混用。

![PD 分离队列与传输阶段](.assets/CANN推理专题/framework-36.png)

Prefill 侧可能经历引导、等待、传输中等状态；Decode 侧可能经历预分配、传输、等待与运行等状态。Mooncake、NIXL 等传输方案的设备支持、缓存格式与集成方式取决于具体版本。

发生取消、超时或传输失败时，两端都要释放对应资源，并避免设备继续访问已回收内存。PD 分离的收益必须覆盖 KV 传输与协调开销，不能仅分别比较两个阶段的算子速度。

## 7. 如何评价框架优化

| 现象 | 优先观察 | 可能方向 |
| --- | --- | --- |
| 长提示词拖慢正在输出的请求 | Prefill 阻塞、批次时间 | Chunked Prefill 或 PD 分离 |
| 相似请求仍反复计算前缀 | 缓存命中、路由分布 | Radix 缓存与缓存感知路由 |
| KV 容量限制并发 | 块占用、碎片、缓存精度 | 分页、分层缓存、KV 量化 |
| 设备频繁空闲 | CPU 调度时间、同步点 | 调度重叠、图模式 |
| MoE 部分设备长时间等待 | 专家负载、AllToAll 时间 | EPLB、分组与通信优化 |

评测需要固定请求长度分布、到达率、并发与缓存冷热状态。缓存预热后的结果不能直接代表首次访问性能，平均吞吐也不能替代用户关心的尾部时延。
