大模型推理成本优化实战:vLLM 与 KV Cache 调优指南
大模型真正进入生产环境以后,最容易被低估的问题往往不是"模型能不能跑起来",而是"每生成一个 Token 到底要花多少钱"。在实验环境中,单次请求跑得快、显存占得满,并不意味着线上服务具有良好的经济性。生产环境面对的是持续到来的并发请求、长度差异巨大的 Prompt、不断增长的 KV Cache,以及首 Token 延迟、逐 Token 生成时间、吞吐量和显存利用率之间复杂的权衡。
尤其对于长上下文和高并发场景,模型权重本身反而不一定是第一瓶颈。随着请求数量和上下文长度增长,KV Cache 会迅速占据大量 GPU 显存,并进一步限制批处理规模、并发数和整体吞吐。因此,大模型推理成本优化不能简单理解为"把模型从 FP16 换成 INT4"。真正有效的优化来自一个完整的推理栈:模型量化、分页注意力、KV Cache 管理、连续批处理、前缀缓存、内核优化、并发调度与硬件利用率优化的组合。vLLM 正是围绕这一类问题设计的高性能推理框架。
一、先理解一个事实:LLM 推理为什么昂贵
Transformer 的自回归生成过程可以简单分为两个阶段。Prefill 负责处理用户提交的 Prompt,一次性计算整个输入序列,生成对应的 Key 和 Value 并保存到 KV Cache。这个阶段通常具有较高的计算并行度,更容易表现为计算密集型任务。Decode 是生成阶段,每一步生成下一个 Token 都依赖之前已经生成的内容,是典型的自回归过程。如果每次都重新计算完整上下文,计算量会非常巨大。
KV Cache 的核心价值就在这里:已经计算过的 Key 和 Value 不需要每个解码步骤重新计算。这也是为什么 KV Cache 是现代 LLM 推理系统的核心资源之一。但 KV Cache 恰恰又是最吃显存的部分。估算一下:假设一个模型有 32 层、8 个 KV 头、128 维头维度、FP16 精度,那么每个 Token 的 KV Cache 大小大约是 128 千字节。如果一个请求上下文达到 8192 Token,单个请求就需要约 1 GB 的 KV Cache;如果同时有 16 个请求,理论上就需要接近 16 GB。所以在长上下文、高并发服务中,真正限制并发能力的往往不是模型权重,而是 KV Cache。
二、PagedAttention:把 KV Cache 像虚拟内存一样管理
最早的推理实现通常会为每个请求分配连续显存,问题在于请求长度并不固定。如果系统按照最大长度预分配,就会产生大量浪费;如果动态扩容,又容易产生显存碎片。这和传统操作系统内存分配遇到的问题非常类似。
vLLM 的 PagedAttention 借鉴了操作系统虚拟内存和分页机制。它不再要求一个请求的 KV Cache 必须连续存储,而是把 KV Cache 切成多个固定大小的块。逻辑上请求的 KV Cache 是连续的,实际 GPU 显存中这些块是离散分布的,通过块表建立映射。请求需要多少块就分配多少,请求结束立即释放,其他请求复用。带来的收益是显存碎片显著降低,显存利用率可以从三成提升到接近九五成,同等显存下吞吐量提升 2 到 4 倍。另外,共享前缀的请求可以共享 KV Cache 块,显著减少内存使用。
三、Continuous Batching:不要等待整个 Batch 结束
传统静态批处理的逻辑是:等待一批请求到齐后一起处理,处理完再处理下一批。问题是不同请求的生成长度不同,短请求完成后需要等待长请求完成才能释放资源,GPU 的计算资源因此出现大量浪费。
连续批处理则把请求生命周期拆开:某个请求完成后立即退出批处理,新请求马上进入。GPU 在每一个迭代中都可以尽可能装载更多可执行请求。这套机制配合抢占式调度,长请求可以被挂起并恢复,不会阻塞短请求。与分块预填充结合,还能解决长 Prompt 阻塞解码的问题——把超长 Prompt 拆成多个块,让预填充和解码更合理地共享 GPU 计算资源。
四、第一步优化:不要盲目追求最大 Batch
这是生产环境非常容易犯的错误。很多人看到 GPU 显存还有空间,就认为 Batch 越大越好。实际上 Batch 增大通常意味着吞吐上升、显存占用上升、排队延迟上升、首 Token 延迟可能上升、调度复杂度上升。尤其是长 Prompt 场景,Batch 等于 8 但平均输入 2K 和平均输入 32K 的 KV Cache 压力完全不是一个数量级。因此真正应该关注的是每个迭代处理的 Token 数量,而不是简单的请求数量。
vLLM 的生产调优不应该只盯着并发请求数量,更重要的是控制每个迭代中处理的 Token 数量。典型启动参数组合是:限制并发请求数量、限制单次调度 Token 工作量,两者联合调节。合理的方法是先从一个保守的配置开始,然后根据压测结果逐步调整。
五、GPU 显存利用率不是越高越好
vLLM 可以利用 GPU 显存的一定比例作为推理资源,很多生产环境喜欢直接设到 0.95 甚至 0.98。但这样做风险较高。GPU 显存并不只有模型权重,还包括 KV Cache、CUDA 运行时、临时缓冲、激活值、内核工作空间和其他运行时内存。如果把显存压得过满,可能出现偶发 OOM——这种问题比启动时直接 OOM 更难排查。更合理的方法是从 0.85 到 0.90 再到 0.92 逐级压测,找到稳定边界。
六、KV Cache 优化的核心思路
现代模型大量使用分组查询注意力或多查询注意力架构。比如查询头 32 个、KV 头 8 个,那么 KV Cache 的头数量不是 32 而是 8,理论上可以把 KV Cache 的这一部分降低到四分之一。这也是这类注意力架构对推理系统非常重要的原因。
前缀缓存是另一层关键优化。很多企业应用存在高度重复的 Prompt:系统提示词、企业知识库规则、工具定义、Agent 指令,其中前面几千 Token 可能完全相同。如果每次请求都重新预填充,是明显的浪费。前缀缓存的思想是:第一次请求计算并保存前缀的 KV Cache,后续请求匹配到相同前缀时直接复用,只计算新增内容。对聊天机器人、Agent、RAG、企业知识库、多轮对话这类场景尤其有效,能显著降低首 Token 延迟和计算成本。
KV Cache 本身也可以量化。传统情况下模型权重做量化而 KV Cache 保持 FP16 或 BF16,实际上 KV Cache 也可以进行低精度存储,例如从 FP16 降到 FP8,存储量减少一半。对于长上下文、高并发场景,这个收益非常直接。但需要注意,KV Cache 量化需要关注输出质量退化风险。可以这样概括:权重量化解决"模型装不下"的问题,KV Cache 量化解决"并发撑不住"的问题,两者不是一回事。
七、量化:降低模型权重成本
如果模型采用 BF16,一个 70B 模型仅权重理论存储量就约 140 GB。如果使用 INT4,同样模型约 35 GB,意味着同样的 GPU 集群可能运行更大的模型,或者运行更多副本。常见量化方案包括 FP8、INT8、INT4、GPTQ、AWQ 等。
但为什么不能简单认为 INT4 一定比 FP8 快?量化影响的不只是显存,还涉及内存带宽、计算吞吐、内核效率、反量化开销、张量核心利用率和精度。例如 FP8 在现代 GPU 上往往具有非常成熟的硬件支持,而某些 INT4 格式虽然理论上更省显存,但如果对应内核不够高效,最终吞吐不一定更好。所以量化选择应该通过基准测试决定,而不是根据位宽数字大小决定。AWQ 在低比特下保留更多重要权重,比 GPTQ 更适合生成任务;FP8 在 Hopper 架构上有原生支持,精度损失极小。
八、实战调优路径与监控指标
实际部署时,可以先从一个相对保守的配置开始,然后根据压测结果调整。典型调优路径是:固定模型、固定提示词、固定输出长度、测试并发、观察首 Token 延迟和逐 Token 生成时间、调整并发请求数、调整单次调度 Token 工作量。生产系统不能只看每秒生成 Token 数,还必须同时观察首 Token 延迟、逐 Token 生成时间、P99 延迟、排队时间和吞吐量。
关键监控指标包括:KV Cache 利用率、抢占次数、提示 Token 总量、生成 Token 总量、首 Token 延迟、逐 Token 生成时间。通过 Prometheus 采集这些指标,可以支撑自动扩缩容和容量规划。
常见性能问题与对策:P99 延迟高通常是队列堆积,减小并发请求数;吞吐量上不去通常是显存不够,量化加张量并行切分;抢占多说明 KV Cache 不够,减小并发请求数;首 Token 延迟慢说明 Prompt 太长,用分块预填充;逐 Token 生成时间慢说明模型太大,用更小的模型。
九、总结
LLM 推理优化是系统工程,涉及算法、内存管理、调度和模型压缩的协同。vLLM 等开源框架已证明这些技术可以组合实现接近硬件极限的吞吐。随着生成式 AI 业务量飙升,掌握推理加速能力将成为 ML 工程团队的硬性要求。上线前建议在真实负载下压测不同配置,关注推理框架的最新进展,构建成本最优的大模型服务层。优化没有银弹,但有一条被反复验证的路线:先启用推理引擎的内置加速能力,再选择合适的量化精度,最后结合监控指标持续调优。