人人都会AI编程

22.3 推理加速技术:KV 缓存、批量推理、连续批处理、投机采样

更新时间:2026-07-09

在第 22 章的前两节,你已经掌握了推理的核心指标(延迟、吞吐量、显存占用)和量化压缩技术。但在实际生产环境中,量化只是推理优化的“第一条腿”。另一条腿,是在不改变模型权重的前提下,通过改变计算和调度策略来榨干硬件性能。

本节介绍四种已被主流推理框架(vLLM、TGI、TensorRT-LLM 等)广泛采用的核心加速技术。它们相互叠加后,通常能带来 2–10 倍的吞吐提升,是推理工程落地的必修课。


一、KV 缓存(KV Cache):你不需要每次都“重新认识”前面的词

1. 问题的根源

回忆 1.1 节描述的自回归生成过程:模型每生成一个新 Token,都要把它拼回输入序列,重新计算整个序列的注意力

这带来了严重的计算浪费。假设你要生成“今天天气真好”:

  • 生成“今”时:计算[今]的注意力;
  • 生成“天”时:计算[今, 天]的注意力——“今”的部分被重算了一遍;
  • 生成“气”时:计算[今, 天, 气]——“今”和“天”又被重算;
  • ……

生成 n 个 Token,计算量是 O(n²) 而不是 O(n),且绝大部分计算都在重复推导已经生成的 Token。

2. KV 缓存的原理

在注意力计算中,每个 Token 会产出三个矩阵:Q(Query)、K(Key)、V(Value)。对于一个已经生成的 Token,它的 K 和 V 向量在后续步骤中是完全不变的(因为自回归掩码机制下,未来 Token 不会影响过去)。

KV 缓存的核心思想就是空间换时间:把已经计算过的 K 和 V 向量存入显存,生成下一个 Token 时:

  • 只计算最后一个新 Token 的 Q、K、V
  • 新的 Q 直接与缓存中的所有历史 K、V 做注意力计算;
  • 计算量从 O(n²) 降至 O(n),每步只做一次新 Token 的完整计算 + 增量注意力。

3. 工程价值与成本

  • 提速效果:对于长序列生成,KV 缓存能减少 50%–90% 的计算量。
  • 显存代价:这是 KV 缓存的核心约束。显存占用公式:
KV 缓存显存 = 2 × 层数 × d_model × 上下文长度 × 精度字节数

以 Llama 2 70B(80 层、d_model=8192、FP16)为例,处理 4096 Token 的上下文时需要约 10 GB 额外显存仅用于缓存

当上下文窗口扩展到 128K 甚至 1M 时,KV 缓存可能比模型权重本身更占显存。这就是 22.2 节量化技术的关键应用场景之一——KV 缓存压缩(如 K-V 量化至 INT8/INT4)。

4. 实用认知

你不需要手写 KV 缓存逻辑,vLLM、TGI 等框架已内置。你需要关心的是:预估并发请求数 × 平均上下文长度 × 单请求 KV 缓存大小,是否会打爆 GPU 显存。


二、批量推理(Batching):让 GPU 同时伺候多个请求

1. 为什么需要批处理

GPU 的设计哲学是大规模并行。单次推理如果只处理一个请求,GPU 的 Tensor Core 大部分时间在“空转”——算力利用率(MFU)可能不到 30%,因为单个请求的计算量不足以填满所有计算单元。

2. 静态批处理(Static Batching)

最朴素的做法:把多个用户请求拼成一个大矩阵,一次性喂给 GPU。

  • 优势:硬件利用率显著提升,吞吐量随 batch size 线性增长;
  • 致命缺陷:所有请求必须等最慢的那个完成,才能一起返回。如果 batch 里有一个生成长度 2000 Token 的复杂任务,其他只需 50 Token 的简单请求全被拖累。这导致延迟分布极不均匀,用户体验极差。

静态批处理只适合离线评测,不适合生产服务。

3. 实用认知

理解静态批处理的局限性,是引入下一项技术“连续批处理”的前提。如果你的推理服务还停留在“来一个请求处理一个”或“固定 batch 等齐再发”的阶段,你的 GPU 钱包正在无声哭泣。


三、连续批处理(Continuous Batching):流水线式的动态调度

这是 2023 年以来推理框架最关键的工程突破之一,代表是 vLLM 的PagedAttention(分页注意力)和 TGI 的类似机制。

1. 核心思想

打破“一个 batch 同进同出”的僵化约束,让请求随时可加入、随时可退出

  • 每个生成步,GPU 处理当前所有活跃请求的一个新 Token;
  • 某个请求生成结束(遇到 EOS Token 或达到最大长度)后,立即释放其占用的 KV 缓存槽位;
  • 新请求无需等待当前 batch 全部完成,在下一轮迭代直接加入

2. 为什么提速

想象一个餐厅的类比:

  • 静态批处理:厨师必须等所有人吃完才能换下一桌——大厅永远有人在等位;
  • 连续批处理:吃完一个立即清台、引入新客——餐桌利用率最大化。

在推理场景中,这意味着:

  • 长延时请求不再阻塞短请求。短请求“快进快出”,GPU 槽位始终保持高密度;
  • 吞吐量大幅提升(通常 2–10×),同时P50/P99 延迟也显著降低

3. 工程实现要点

  • KV 缓存的动态分配与回收:vLLM 引入类似操作系统“虚拟内存分页”的机制,将 KV 缓存切分为固定大小的 Page,按需分配、自动回收,彻底避免碎片;
  • 抢占与优先级调度:紧急请求可以插队,低优先级离线任务让出资源。

4. 实用指南

目前 vLLM 和 TGI 均默认开启连续批处理。部署时你只需关心 max batch size 和 max queue length 等参数,框架会自动优化调度。如果你用的是原生 PyTorch 手写推理循环,建议立刻迁移到上述框架,这是“白捡”的性能收益。


四、投机采样(Speculative Decoding):用小模型“猜”,用大模型“审”

1. 问题再审视

自回归生成是串行的——每一步推理都依赖上一步的输出。即使你用 KV 缓存减少了计算量,你仍然需要依次等待每个 Token 的生成。单步推理的 GPU 利用率极低(通常 < 5%),因为计算量太小,大部分时间花在 I/O 和数据搬运上。

2. 投机采样的破局思路

核心逻辑只有一句话:找一个速度快 100 倍的“小模型”(Draft Model),让它先一口气猜出接下来 N 个 Token;然后让“大模型”(Target Model)一次性验证这一串对不对。

具体流程:

  1. 草稿生成:小模型(Draft Model,通常是大模型的 1/10–1/50 规模)以自回归方式快速生成一段候选序列(如 5–8 个 Token);
  2. 批量验证:大模型将整段候选序列作为输入,并行计算每个位置的预测概率分布;
  3. 比对与接受/拒绝
  • 对于每个位置,比较小模型和大模型的概率分布;
  • 如果一致(或在某个容忍度内),接受该 Token;
  • 如果出现不一致,拒绝该位置及之后的所有候选 Token,大模型用自己的预测 Token 重新生成;
  1. 重复:从被接受的最后一个 Token 之后开始,继续上述过程。

3. 加速原理与收益

  • 在理想情况下,小模型猜得足够准,大模型只需一次前向传播就能验证 5–8 个 Token,单步推理的“有效吞吐”提升数倍;
  • 大模型仍然是唯一的“权威输出”,最终生成的 Token 序列完全等价于原模型自回归采样——加速不牺牲精度。

实际收益取决于小模型的命中率(Acceptance Rate)。在代码生成、数学推理等模式较规整的任务中,命中率可达 80% 以上,端到端加速 2–3 倍。

4. 工程与实用注意事项

  • 需要额外显存:小模型也要加载到 GPU 中,通常额外占用 1–5 GB;
  • 小模型的选择:可以用原模型的蒸馏版本(如 Llama 70B 搭配 Llama 7B)、同架构的小尺寸变体,或专门的轻量 Draft 模型;
  • 框架支持:vLLM、TGI 均已内置投机采样选项,你只需配置 draft model 路径即可开启。

五、组合策略与选型建议

四种技术并非“四选一”,而是分层叠加

┌─────────────────────────────────────────┐
│ 应用层         投机采样(Speculative Decoding) │
├─────────────────────────────────────────┤
│ 调度层    连续批处理(Continuous Batching)    │
├─────────────────────────────────────────┤
│ 执行层   批量推理(Batching)+ KV 缓存压缩    │
├─────────────────────────────────────────┤
│ 基础层           量化模型 + 推理框架           │
└─────────────────────────────────────────┘

实际落地时的典型配置:

| 场景 | 推荐组合 | 预期加速(相比原生) |
|------|---------|-------------------|
| 低并发、长文本(如文档摘要) | KV 缓存 + FlashAttention + 量化 | 延迟降低 50%–70% |
| 高并发、短文本(如聊天客服) | 连续批处理 + 量化 | 吞吐提升 5–20× |
| 高并发、代码生成 | 连续批处理 + 投机采样 | 吞吐再提升 2–3× |
| 端侧或边缘设备 | KV 缓存压缩 + INT4 量化 | 显存占用降至 1/4 |

最后,记住一条实用原则:先优化调度的智能化(连续批处理),再优化计算的并行度(KV 缓存、批量推理),最后才考虑投机采样这类需要额外模型的技术。 大多数团队在开启连续批处理后,性能提升已经足够满足业务需求,投机采样更多用于极端追求吞吐的 API 服务场景。