
大模型推理优化全解KV Cache、PagedAttention、连续批处理与投机解码一、一个真实的为什么这么慢搭了个大模型服务用户一上来就问你为什么这么慢盯着屏幕看推理时间——7 秒一个 token。回头一看配置一个 Llama-2-7B单张 A100。理论上应该跑飞快结果慢得像拨号上网。问题出在哪先把大模型是怎么干活的搞清楚每次生成一个 token模型都要看之前的所有 token。生成第 100 个 token 时模型要把前 99 个 token 都算一遍。这就是自回归解码天然 O(n²) 复杂度。更糟糕的是显存带宽。你算得再快数据从显存搬到 GPU 核心要时间。现代推理的瓶颈不是计算是带宽。有人以为加 GPU 就能解决结果两张 A100 并在一起性能提升不到 40%——因为数据还是得从显存搬运到计算核心带宽没变。二、KV Cache不要重复算KV Cache 是第一道防线。原理很简单每层 attention 都要算 Q、K、V 三个矩阵而 K 和 V 只依赖之前的 token生成新 token 时没必要重新算存下来就行。每个 token 的 KV Cache 大小大约是 0.5MB7B 模型、32 层、4096 维、FP16。生成 4096 个 token光 KV Cache 就占 2GB 显存。用了 KV Cache 之后推理速度直接提升 3-5 倍——代价是显存占用翻倍。Llama-2-7B 本身 13GB长文本场景轻松破 30GB单张 A100 都装不下。这里引出一个关键矛盾KV Cache 是速度的钥匙也是显存的杀手。所有推理优化的核心命题本质上都是如何在更少的显存里装下更多 KV Cache同时保持访问效率。三、PagedAttention把显存利用率从 40% 拉到 90%vLLM 的核心创新就是 PagedAttention。传统 KV Cache 分配是静态的——预分配固定大小假设你要支持 2048 上下文不管用户发多少字显存都给满了利用率只有 40%。PagedAttention 借鉴操作系统虚拟内存的思想把 KV Cache 分页动态申请和释放用户发 100 字就只申请 100 字的显存。# vLLM 启动命令--block-size 16 就是页大小默认 16 个 token 一页python-m vllm.entrypoints.api_server \--model meta-llama/Llama-2-7b-hf \--tensor-parallel-size1\--gpu-memory-utilization0.9\--block-size16 实测下来vLLM 比 HuggingFace Transformers 快3-5倍显存利用率从40%提到90%。同样4096上下文显存占用只有原来的60%吞吐量直接翻倍。 分页带来的另一个隐性收益是**前缀共享**多个请求如果有相同的系统提示可以共享同一段 KV Cache 块进一步省显存。这在所有请求共用同一套角色设定的服务里收益巨大。## 四、投机解码小模型猜大模型验证投机解码的原理用一个小模型比如1.1B快速生成一堆 token然后用大模型比如 7B并行验证。验证通过就用不过就回退。 python# vLLM 开启投机解码python-m vllm.entrypoints.api_server \--model meta-llama/Llama-2-7b-hf \--speculative-model TinyLlama/TinyLlama-1.1B-Chat-v1.0\--num-speculative-tokens5 --num-speculative-tokens5 表示小模型一次猜5个 token。实测 Llama-2-7B 配合1.1B 小模型推理速度从50tokens/s 提升到130tokens/s。 但投机解码有个前提小模型猜得准。如果猜错太多反而会拖后腿。我在自己的数据集上测试过小模型猜错率高达30%的场景投机解码反而比不用还慢。**这是推理优化里最反直觉的一点加速技术不是无条件生效的必须实测。**## 五、连续批处理动态拼 batch传统批处理是静态的——等凑够32个请求再一起跑用户少的时候 GPU 就空着。连续批处理Continuous Batching是动态的来一个就跑一个中间有请求结束立刻塞新的进去GPU 永远不闲着。vLLM 默认开启不用额外配置。 用 HuggingFace Transformers 时用户一少 GPU 利用率掉到20%切到 vLLM哪怕只有一个用户利用率也能维持在70%以上。连续批处理是高并发场景收益最大的优化项——尤其是请求长度差异大的在线服务。## 六、量化INT8/FP8显存减半速度翻倍量化就是把模型参数从 FP16 压缩到 INT8 或 FP8。FP16→INT8显存占用减半带宽需求减半推理速度翻倍代价是精度掉1-2个点实际效果差别不大。vLLM 支持 AWQ 和 GPTQ 两种量化格式 bash python-m vllm.entrypoints.api_server \--model TheBloke/Llama-2-7B-AWQ \--quantization awq 试过 AWQ4-bit 量化Llama-2-7B 从 13GB 压到 4GB推理速度从50tokens/s 提升到90tokens/s精度肉眼几乎看不出来。 量化选择建议效果要求严格、显存充足的场景优先 INT8稳健性最好损失在1%以内显存受限、成本敏感或边缘部署选 INT4H100 硬件可以用 FP8几乎无损。无论选哪种部署前务必在目标任务真实评测集上对比原模型——量化损失在数学推理、代码生成这类精度敏感任务上会更明显。## 七、监控让优化有据可依优化做完不能一跑了之。要监控的关键指标KV Cache 利用率gpu_cache_usage_perc反映显存分配是否健康、首 Token 延迟time_to_first_token_seconds用户可感知的第一道门槛、吞吐每秒处理请求数、抢占次数num_preemptions_total抢占多说明 KV Cache 不够。这些指标接入 Prometheus 之后每次调参都有前后对比而不是凭感觉判断好像变快了。## 八、实战建议什么场景用什么组合搞懂了原理剩下的就是组合拳**短对话512token 以内**普通推理就行显存够的话 FP16 最稳不需要额外优化。**长文档问答2048-4096token**必须用 KV CachePagedAttentionvLLM 默认配置就能跑显存不够就上 AWQ 量化。**高并发在线服务**vLLM连续批处理投机解码可选看小模型质量7B 以下模型 INT8 量化就够。**成本敏感场景**4-bit AWQ 量化vLLM显存减75%速度提升2-3倍接受1-2个点精度损失。## 八、最后说句大实话推理优化这东西理论再多不如实测。别相信任何理论数据相信你自己的 benchmark。核心建议先测自己的数据再选方案。vLLM 是个好起点默认配置就够用80%的场景剩下20%一个个试——投机解码、量化、连续批处理、前缀缓存。监控显存利用率和吞吐量哪个好用哪个。 再补充两条容易被忽略的经验一是**量化选型要与业务绑定**客服问答这类事实型任务对量化损失不敏感但数学推理、代码生成这类任务INT4 的退化可能超预期一定要在真实评测集上对比后再定二是**不要同时改多个变量**投机解码和量化一起上出问题了分不清是谁的锅——一次只动一个参数用监控数据确认收益再动下一个。 推理优化的本质是系统工程KV Cache 解决重复计算PagedAttention 解决显存浪费连续批处理解决GPU 空闲量化解决带宽瓶颈投机解码解决解码太慢。五把钥匙缺一不可但也没有一把是万能的。先建立压测和监控的度量体系让每一次优化都有数据支撑——这比背下所有优化参数都重要。