🧠AI 部署与项目实战

推理量化与加速

难度:⭐⭐⭐ | 高频指数:🔥🔥 | 应用岗相关度:★★

面试回答

常见问法

  • INT8、INT4、FP16、BF16、AWQ、GPTQ、GGUF 分别是什么,怎么选?
  • 量化会损失多少精度?哪些层对量化敏感?
  • vLLM、TensorRT-LLM、llama.cpp、SGLang、Ollama 各自定位是什么?
  • PagedAttention 和 Continuous Batching 分别解决了什么问题?
  • KV Cache 为什么会越来越大?怎么管?
  • Speculative Decoding 是怎么工作的?什么时候开了反而更慢?

回答

推理加速要分两层看。模型层是”怎么压”——量化、蒸馏、稀疏化、MoE,目标是同样质量下让模型更小更轻。系统层是”怎么调度”——Batching、KV Cache 管理、并行策略、Speculative Decoding,目标是把 GPU 跑满。两层是乘法关系,单独优化一层都不够。

工程上的核心认知是:显存是 LLM 推理最先卡住的资源,不是算力。一张 80G 的 H100,跑 70B 模型只剩二十几个 G 给 KV Cache,长上下文 + 高并发立刻 OOM。所以量化(压权重)和 PagedAttention(压 KV Cache)是同等重要的两条线。

面试时要表现出的判断力是:知道不同优化手段的适用场景——量化适合显存受限,Continuous Batching 适合高并发短请求,PagedAttention 适合长上下文,Speculative Decoding 适合输出长且 Draft 模型够准的场景。乱开优化经常负优化。

追问

  • GPTQ 和 AWQ 哪个精度损失更小?为什么?
  • GGUF 是格式还是量化方法?它和 GGML 什么关系?
  • 为什么 vLLM 在高并发场景吊打 HuggingFace transformers?
  • TensorRT-LLM 比 vLLM 强在哪?为什么大家还没全部切过去?
  • Continuous Batching 和传统 Static Batching 的核心区别是什么?
  • Speculative Decoding 的接受率怎么算?低于多少就不该开?

原理展开

1. 推理为什么慢,瓶颈到底在哪

LLM 推理可以拆成两个阶段,瓶颈完全不一样:

  • Prefill 阶段:处理输入 Prompt,把整段一次性算完,算力瓶颈(compute-bound),GPU 利用率高
  • Decode 阶段:一个 token 一个 token 往外吐,每生成一个 token 要把整个模型权重和所有历史 KV Cache 都从显存搬一遍,显存带宽瓶颈(memory-bound),GPU 利用率经常只有 20-30%

绝大多数推理优化都在打 Decode 阶段。因为输出长、占主要耗时、又卡在带宽,提升空间最大。理解这一点之后再看各种优化手段,逻辑就顺了——量化是压权重减少搬运量,KV Cache 量化和 PagedAttention 是治 KV 膨胀,Batching 是让一次搬运服务多个请求,Speculative Decoding 是一次前向算多个 token。

2. 量化的几种类型

按精度从高到低:

类型位数典型场景精度影响
FP3232-bit训练 / 科学计算基准
BF1616-bit训练 + 推理主流几乎无损
FP1616-bit推理主流(老 GPU)几乎无损
FP88-bitH100/H200 推理极小(< 1%)
INT88-bit推理常用小(1-2%)
INT44-bit边缘 / 显存紧张中(2-5%)
INT2/32-3-bit极限压缩大,需精调

BF16 和 FP16 的关键差异:BF16 指数位多,动态范围大,训练稳定;FP16 精度位多,但容易溢出。新模型基本都用 BF16 训练,所以推理也优先 BF16。

量化方法上几个常见名词:

  • GPTQ:基于二阶信息(Hessian)的训练后量化,逐层做,精度高,适合 INT4
  • AWQ:Activation-aware Weight Quantization,发现并保护激活值大的少数权重,比 GPTQ 更稳,社区主流
  • SmoothQuant:把激活的 outlier 挪到权重侧,让两边都好量化,常用于 INT8
  • GGUF这是格式不是量化方法,llama.cpp 的统一权重容器,里面可以装各种量化方案
  • NF4 / FP4:QLoRA 论文里的 4-bit 浮点表示,QLoRA 微调常用

3. 量化对精度的真实影响

实战上的经验数:

  • INT8 / FP8:几乎无损,大多数下游任务掉点 < 1%
  • AWQ INT4:通用任务掉 1-3%,代码 / 数学等 reasoning 重的任务掉得多一些
  • GPTQ INT4:和 AWQ 接近,部分场景略差
  • 更激进的 INT3 / INT2:必须重新评测,掉点不可忽略

敏感层:Attention 的 Q/K/V 投影、最后一层 lm_head 通常更敏感,部分实现会把这些层保留 FP16。

最容易踩的坑:用通用 benchmark(MMLU / HellaSwag)看不出问题,但实际业务 prompt 一上就掉。所以量化后一定要跑一遍业务自己的评估集,不能只看公开榜单。

4. KV Cache 为什么是大头

Transformer Decode 时,每一层要存所有历史 token 的 K 和 V。KV Cache 大小近似:

KV Cache = 2 (K+V) × num_layers × num_heads × head_dim × seq_len × dtype_bytes

举个数:70B 模型,80 层,64 head,head_dim 128,BF16(2 字节),单 token 大约 2.5MB。一个 8K 上下文的请求,KV Cache 就是 20GB。100 个并发请求轻松把 80GB 的 H100 撑爆。

所以 KV Cache 必须管:

  • KV Cache 量化:FP8 / INT8,典型节省 30-50% 显存,精度几乎无损
  • PagedAttention:分页管理,消灭碎片
  • Prefix Caching:相同前缀的 KV 复用
  • 滑动窗口 / Sink Attention:只保留最近 N 个 token,长序列必备

5. PagedAttention:KV Cache 的虚拟内存

vLLM 的核心创新。传统 KV Cache 是连续内存分配——为每个请求预留 max_seq_len 的空间,实际只用了几百 token 也照样占完,碎片严重。

PagedAttention 把 KV Cache 切成固定大小的块(比如 16 token 一块),按需分配,逻辑地址通过页表映射到物理块:

请求 A 的 KV:  [block 7] → [block 2] → [block 9]
请求 B 的 KV:  [block 4] → [block 11]
请求 C 的 KV:  [block 8]

            页表把逻辑顺序映射到物理 block

收益是两个:

  • 几乎零碎片:显存利用率从 30-50% 提到 90%+
  • 共享前缀:多个请求共享同一段 Prompt(System Prompt / Few-shot 例子)的 KV,物理 block 只存一份

这是为什么 vLLM 在高并发下吊打老引擎的根本原因——同样显存能塞下两三倍的并发。

6. Continuous Batching:动态拼车

传统 Static Batching 是攒齐一个 batch 一起算,问题是长短不一——batch 里最长的请求决定整体耗时,短的算完只能干等。

Continuous Batching(也叫 in-flight batching)按 iteration 调度:每生成一个 token,调度器就检查——有请求结束了?立刻让新请求进来填空位;有新请求到达?下一个 iteration 立刻加入。

传统 Static Batching:
[req1 长]  ████████████
[req2 中]  ██████      ←  空等
[req3 短]  ███         ←  空等更多
              ↑ batch 结束时间 = 最长的那个

Continuous Batching:
[req1 长]  ████████████
[req2 中]  ██████[req4 新进来]██████
[req3 短]  ███[req5 新进来]██████████
              ↑ GPU 永远是满的

在线 Serving 场景,Continuous Batching 是几倍吞吐提升。所有现代推理引擎都有。

7. Speculative Decoding:小模型抢跑

思路:用一个小 Draft 模型一次生成 N 个 token,大模型只做”验证”——一次前向同时检查这 N 个 token 是否符合自己的分布。接受的就直接用,第一个不接受的位置开始重新生成

收益的本质:Decode 是 memory-bound,一次前向多算几个 token 几乎不增加耗时。如果接受率 60%,理论加速 ~2 倍。

接受率怎么算:Draft 预测的 token 和大模型自己采样会得到的 token 一致的比例。

什么时候开了反而更慢

  • 接受率低(< 30%),验证后大量重算,纯亏
  • Draft 模型本身大,单次前向就慢
  • 输出短(几个 token),开销摊不下来
  • 长尾任务(创意写作)随机性高,Draft 难命中

工程上一般要 A/B,不是无脑打开。Llama 3 系列、Medusa、EAGLE 是常见的 Draft 方案。

8. 主流推理引擎对比

引擎定位强项适合场景
vLLM开源通用 ServingPagedAttention 原产地、社区活跃、多模型支持广高并发 在线 Serving
TensorRT-LLMNVIDIA 官方极致性能、深度融合 CUDA 算子对延迟 / 吞吐有极致要求的大型在线服务
SGLang新兴 Serving 引擎RadixAttention 前缀共享、结构化输出快Agent / 多轮 / 高前缀复用场景
llama.cppC++ 推理CPU / Apple Silicon / 边缘端、GGUF 生态本地部署、边缘设备
Ollamallama.cpp 的友好封装一行命令跑模型个人开发 / Demo
TGIHuggingFace 自家和 HF 生态贴合HF 生态内部署
MLXApple 自家Mac Apple Silicon 原生M 系列 Mac 本地推理

几个常见误区澄清

  • TensorRT-LLM 性能更强但模型适配慢,新模型经常 vLLM 先支持
  • SGLang 不只是快,结构化输出 / Agent 多轮场景下的前缀复用收益巨大
  • llama.cpp 不是”低端选择”,Apple Silicon 上跑 70B 体验比想象的好
  • Ollama 适合个人不适合生产,Serving 能力远不如 vLLM

9. 选型决策路径

场景一:在线高并发对客 Serving (QPS > 10)
  → vLLM (主流) / TensorRT-LLM (极致) / SGLang (Agent 多轮)
  + AWQ INT4 (省显存) / FP8 (H100)
  + Continuous Batching (默认开)
  + Speculative Decoding (评估后再开)

场景二:单机 / 离线批量推理
  → vLLM offline mode / TensorRT-LLM
  + 大 Batch Size 拉满吞吐
  + 不需要 Continuous Batching

场景三:边缘 / 本地部署
  → llama.cpp + GGUF (Q4_K_M 起步)
  + INT4 / INT5 量化
  + 没有 Batching 需求

场景四:Mac 本地
  → llama.cpp (Metal) 或 MLX
  + GGUF Q4

场景五:Agent / 多轮 / 工具调用
  → SGLang (前缀复用收益最大)
  + 结构化输出能力

判断标准:先看部署形态(在线 Serving / 离线批 / 边缘),再看显存预算(决定量化精度),最后看请求特征(决定是否开 Speculative / 前缀缓存)。

对比总结

场景推荐
高并发在线 ServingvLLM + Continuous Batching + PagedAttention
极致延迟 / 吞吐(大厂在线)TensorRT-LLM + FP8 (H100)
Agent 多轮 / 高前缀复用SGLang + RadixAttention
Mac 本地 / 边缘部署llama.cpp + GGUF Q4
显存紧张但要保质量AWQ INT4,必测业务评估集
H100/H200 集群FP8 + PagedAttention
长上下文场景PagedAttention + KV Cache 量化 + Prefix Caching
输出长且 Draft 准Speculative Decoding(先 A/B)

易错点

  • 认为 INT4 量化掉点可以忽略——必须跑业务自己的评估集,公开榜单看不出问题
  • 把 GGUF 当成量化方法——GGUF 是格式,里面装的才是量化方案(Q4_K_M 等)
  • Speculative Decoding 无脑开——接受率低或输出短的场景开了更慢
  • 只调 Batch Size 不调 KV Cache 上限——OOM 出在 KV 上不是权重上
  • 以为 Continuous Batching 是 vLLM 独有——现在所有现代引擎都有,区别在调度细节
  • 用 transformers 直接跑做 Serving——单请求还行,并发立刻被吊打
  • 混用 vLLM / TGI / TensorRT-LLM 的术语——它们的 batching 机制和配置项不一样
  • 忽略 Prefill 和 Decode 是两个不同瓶颈——很多优化只对其中一个有效

记忆技巧

记三组锚点:

  1. 两层优化:模型层(量化、蒸馏、稀疏)+ 系统层(Batching、KV 管理、Speculative)
  2. 三件 KV 工具:PagedAttention(分页)+ KV 量化(压缩)+ Prefix Caching(复用)
  3. 选型口诀:在线 Serving 看 vLLM,极致性能上 TensorRT-LLM,多轮 Agent 选 SGLang,边缘本地 llama.cpp

一句话总结:显存比算力更先卡住,所以量化和 KV Cache 管理是同等重要的两条主线。

面试速答版

LLM 推理加速分两层。模型层做量化——INT8/FP8 几乎无损,AWQ INT4 是显存紧张时的主流选择;系统层做调度——PagedAttention 解决 KV Cache 碎片,Continuous Batching 解决长短请求空等,Speculative Decoding 用小模型抢跑加速 Decode。

真正的瓶颈在 Decode 阶段的显存带宽,不是算力。所以 vLLM 这类引擎能把 GPU 吃满靠的就是 PagedAttention(消除显存碎片,提升并发)和 Continuous Batching(动态拼车,永不空等)。

选型上:在线 Serving 主流 vLLM,极致性能上 TensorRT-LLM,Agent 多轮选 SGLang,边缘本地用 llama.cpp + GGUF。

面试加分版

如果想多讲一层,可以补:

  • Prefill 和 Decode 是两个完全不同的瓶颈——前者算力 bound,后者显存带宽 bound,优化手段不通用
  • PagedAttention 的设计灵感来自 OS 虚拟内存——把”分页 + 页表”的思路搬到 KV Cache,这是 vLLM 论文的核心贡献
  • Speculative Decoding 的接受率要看 Draft 和 Target 的分布相似度——同系列的 1B + 70B 接受率高,跨系列效果差
  • FP8 是 H100/H200 的免费午餐——硬件原生支持,精度损失比 INT8 还小,但老卡(A100 / V100)享受不到
Related · 部署与项目实战