
聊到大模型推理优化很多人第一反应是上vLLM就完事了4bit量化拉满速度肯定快。但真正跑到生产环境里你会发现事情没那么简单显存莫名其妙涨、并发一高速度就崩、量化之后效果漂移严重。过去一年我把大部分精力都耗在了LLM推理侧的优化上从最开始加载一个70B模型要等半天到后来把百路并发压到稳定服务中间的坑踩了不少今天这篇就当作一份技术原理解析总览把我自己验证过的东西一次性梳理清楚。这篇内容适合做模型部署的工程师、正在研究推理框架的技术人也适合想搞明白大模型跑起来为什么这么贵的算法同学。读完之后你至少能弄清楚推理优化的瓶颈到底在哪、KV Cache为什么是基石、Continuous Batching和PagedAttention解决了什么问题、量化该不该用、以及我实测下来从基线到30倍吞吐提升到底做了哪几步。1. 推理瓶颈拆解延迟与吞吐先解决哪一个1.1 推理优化到底在优化什么先说一个最常见的误区。很多人以为推理优化就是把首token速度追上去让模型回复得更快。实际上工程上真正在意的是两个指标单请求延迟和系统吞吐。延迟是用户体验吞吐是成本两者在一定条件下是矛盾的。首token延迟TTFT从发送请求到看到第一个token的时间影响交互感。单token延迟TPOT生成每个token的耗时决定打字机的速度。吞吐量Tokens/s整机每秒能生成的token数直接挂钩部署成本。并发能力单卡或单集群能同时服务的请求数。你可以把推理服务想象成一家餐厅出第一道菜的速度是TTFT上菜节奏是TPOT一天能接待多少桌客人是吞吐能同时开几桌是并发。一家盈利能力强的餐厅看的不是每道菜多快而是翻台率和每桌客人都满意。推理服务也一样单条请求再快如果整机只能服务三个人那成本会高到不可接受。我的经验是项目初期先定清楚核心诉求。如果做内部工具、Copilot页面那延迟优先如果做开放的API服务、SaaS产品那吞吐优先延迟只要控制在可接受范围就行。别一上来就两个都要那只会让你在优化方向上反复横跳。1.2 两个阶段瓶颈完全不同大模型推理不是一个均匀的过程它天然分成两个阶段预填充Prefill和解码Decode。预填充阶段你抛给它一句完整的prompt模型把所有输入token并行处理生成第一个输出token。这个阶段是计算密集型的重点在矩阵乘法GPU的算力在这里是主要消耗品。解码阶段模型逐token生成输出。每一步都依赖前一步的结果没法并行每一步其实都在做一次完整的前向传播但只产生一个token。这个阶段是访存密集型的它的瓶颈不在计算而在把模型权重和KV Cache从显存搬到缓存里这个过程。拿一个7B模型举例FP16精度下权重就有约14GB。而每生成一个token只需要取其中很少的参数参与计算大部分时间都花在搬运数据上。所以decode阶段的优化核心是减少访存量而不是堆算力。我在项目里见过有人为了让单token生成更快把模型从8卡张量并行改成16卡结果速度几乎没变化——因为通信开销反而拖了后腿方向就反了。1.3 推理优化技术栈全景如果把推理优化画成一个金字塔从顶层到底层大概是这个结构框架层vLLM、TensorRT-LLM、SGLang、LMDeploy、TGI等决定了调度策略和显存管理方式。算子层FlashAttention、cuDNN、CUTLASS、Triton等决定单步计算效率和显存占用。模型层量化、量化感知训练、GQA/MQA结构改动、投机解码、MoE等决定模型本身的计算与访存特性。硬件层GPU型号、多卡互联拓扑、显存大小、PCIe/NVLink带宽、CPU offload等。我之前有一段时期认为框架选好了就不用再管底层了后来被现实打脸。同一个模型在vLLM和TensorRT-LLM上的性能差距能到20%以上具体哪个更好还跟你的batch大小、序列长度分布强相关。所以这篇总览会从存储器、调度、算子、模型等多个维度串起来讲而不是只推荐某一种工具。2. 底层机制解密KV Cache、PagedAttention与投机解码2.1 KV Cache的显存占用到底有多夸张KV Cache是推理优化绕不开的基石。它的作用一句话就能说清把已经算过的历史token对应的Key和Value缓存下来避免每生成一个新token就把历史全部重新计算一遍。问题在于这个缓存非常吃显存。计算公式是总显存占用 2K和V两个矩阵 × 层数 × 注意力头数 × 每个头的维度 × 序列长度 × 并发数 × 字节数当模型结构确定后前几个因子是固定的真正随运行状态变化的是序列长度和并发数。以7B模型、40层、32个注意力头、每个头128维来算每个token的KV Cache在所有层加起来大约是 2×40×32×128 327,680个数FP16下就是655KB。看起来不多但一个4096长度的请求就要约2.6GB10个并发请求就是26GB比模型权重本身还大。这还不是最夸张的。换到70B级别模型KV Cache的膨胀会更吓人。所以很多团队的显存规划里KV Cache才是大头模型权重反而只占了一部分。做容量规划时必须把这个算清楚不然上线第一天就OOM。2.2 PagedAttention和Continuous Batching是怎么把吞吐拉起来的要说清PagedAttention得先回顾旧时代的做法。早期的推理框架包括我最早用的几个采用的是静态Batching一批请求一次性加载整批做完才能释放再换下一批。这样做的缺陷非常明显批内请求按最长的那个padding短序列被浪费了。一个慢请求卡住整批都在等它。显存按最大序列长度预留实际用不到那么多造成浪费。后来出现了Continuous Batching打破了整进整出的模式。它在迭代级别做调度每个step它都会根据当前请求的执行状态决定谁能加入batch、谁的batch slot该腾出来。就像食堂打饭不再是凑齐一桌才开饭而是来一个人就补一个位置翻台率自然就上来了。PagedAttention则借鉴了操作系统的虚拟内存分页思想。把连续的KV Cache逻辑上看作一个整体但物理上可以存在不连续的页里按需分配不再预分配整块显存。这样既能避免显存碎片又能让KV Cache的空间利用率大幅提升。vLLM是这套方案的代表实现后来很多框架也做了类似的机制。我在一个内部项目里做过对比同样的8卡A800、同样的72B模型开启Continuous Batching后吞吐量比原来的静态批处理提升了约3倍显存占用还降了30%左右。这属于最值得优先做的优化几乎没有成本换框架就能白拿。2.3 投机解码用一个快嘴替大模型打草稿自回归生成是串行过程每一步都要等上一步结束GPU的算力在decode阶段其实是闲着大半的。投机解码Speculative Decoding的想法很巧妙先让一个小模型一口气草稿生成一批token再让大模型一次校验。校验是并行的如果草稿中大部分token都被采纳那么理想情况下能把解码速度提升到接近批量推理的倍数。这里有个关键参数叫接受率即草稿token被目标模型认可的比例。如果接受率太低草稿被频繁拒绝反而浪费了算力。需要说明的是投机解码对实现细节非常敏感草稿模型和主模型的分布越接近收益越高反之则可能没有任何效果甚至负优化。我踩过的坑是试图用同一个模型的低量化版本当草稿模型结果因为分布漂移太大接受率不到0.5速度没提升反而降了。后来换成专门蒸馏出来的小模型配合ngram采样才把有效速度拉起来约1.8倍。这里面的调参空间不小建议先走默认参数再根据实际命中率调整草稿长度。2.4 前缀缓存与结构化场景的额外红利除了上面三大件还有一个简单但容易被忽略的优化前缀缓存Prefix Caching。它的本质是如果两个请求的开头若干token完全一样这些token对应的KV Cache可以直接复用。这个在真实场景里命中率非常高。做AI助手或者Copilot时每个请求都带一长段system prompt这些是完全相同的前缀多轮对话时历史消息也会被反复计算其实完全可以复用。我的做法是把前缀缓存显存预留开到一个合适的比例实测大概能省掉30%-50%的prefill计算量尤其在长提示词场景下收益明显。如果你的场景里存在大量重复上下文建议打开框架的前缀缓存开关这属于性价比极高的一行配置。3. 实操调优实录从Baseline到30倍吞吐提升3.1 部署环境与基线数据理论讲再多最终还是得跑起来说话。我以一次真实的调优经历为例把过程和数据都贴出来。这次用的是目前比较典型的软硬件组合硬件8卡A100 80GNVLink互联框架vLLM 0.5.4模型Qwen2.5-72B-Instruct量化AWQ 4bit推理精度FP16权重FP16计算测试工具内部压测脚本模拟多路请求没有对比就没有伤害先记录基线。关闭所有额外优化batch size固定为1连续发64个请求统计平均指标指标基线值单请求TTFT约1.8s单请求TPOT约112ms/token平均吞吐约9 tokens/s显存占用73GB接近打满这个数据放到生产环境是没法看的。单请求还好一旦并发上来显存直接不够用更别提服务稳定性。接下来我按顺序做了四轮优化每一轮都单独验证确保知道是哪个改动带来的收益。3.2 优化一打开连续批处理吞吐直接翻倍第一件事是把vLLM里的连续批处理能力用起来同时开启greedy decoding下的预分配优化。严格来说这不是什么奇招它只是把框架的默认优势发挥出来。改动后的数据非常直接同样64个请求、同样的显存吞吐量从9 tokens/s涨到28 tokens/s左右提升了2倍不止。TTFT因为批处理排队稍微涨到2.1s但TPOT没有明显恶化整体可接受。这一步的教训是在你费劲搞量化、改算子之前先把框架自身的能力榨干。很多人插上vLLM就以为自动吃到Continuous Batching红利其实框架的默认配置往往偏保守显存预分配策略、max_num_seqs、max_num_batched_tokens这些参数都会显著影响实际收益需要根据场景调。3.3 优化二KV Cache量化把显存抠出来换并发基线里显存已经73GB打满了想提升并发就得先省显存。KV Cache精度从FP16降到FP8是我认为最稳的一步。因为KV Cache在推理过程中是重复写入、重复读取的对精度不如权重敏感FP8的量化误差在多数任务里可以忽略。实际操作中我在vLLM里开了kv_cache_dtypefp8_e4m3并调整了KV Cache的预留比例。显存占用立刻从73GB降到62GB左右释放出的空间足够把max_num_seqs调大。这一轮单看速度没有提升但把并发能力从6路提升到了12路整机吞吐量从28涨到51 tokens/s。你说显存不着急我显存才用了一半我劝你还是早点把KV Cache量化打开。KV Cache省下来的空间不仅可以提高并发还能降低max_model_len不够用的风险。很多OOM事故都是长序列请求进来后把预留的Cache空间挤爆引起的。3.4 优化三开前缀缓存打掉重复计算的浪费前面说过生成场景里大量重复前缀是极常见的。这次压测的请求里每个人都带着一段2K长度的system prompt。这个重复的上下文没开缓存之前每个新请求进来都要完整跑一遍prefill。打开前缀缓存后请求在prefill阶段的耗时明显下降TTFT从2.1s降到0.9s左右。这部分的收益和prompt复用率强相关如果你们的场景全是独立问题、几乎无共享前缀这一步效果就会打折扣。但原则上我建议始终开启因为它几乎没有副作用。这里有个细节前缀缓存命中依赖token完全一致所以system prompt末尾如果带有时间戳或随机ID等动态内容缓存就会失效。我见过好几个团队因为这个原因报缓存没用排查之后发现是动态内容把前缀切断了。3.5 优化四张量并行与批大小联合调优最后一步是把所有参数联合调整。基线是8卡张量并行但之前max_num_seqs只设了6远没有发挥出多卡的威力。随着显存释放我把max_num_seqs逐步提高到16、24、32并同步观察TPOT变化。注意TPOT不会因为batch变大而无限制恶化因为只要显存不爆GPU计算单元大多数时候仍在等待访存batch大了反而能把带宽占满。最终在max_num_seqs24、启用FP8 KV Cache、前缀缓存开启、连续批处理开启的情况下收敛到比较满意的状态指标优化后对比基线TTFT0.9s降幅50%TPOT78ms/token降幅30%平均吞吐276 tokens/s提升约30倍显存占用68GB基本打满但稳定从9 tokens/s到276 tokens/s30倍就是这么来的。每一轮单独来看都不是爆炸性的但组合起来就是量级的差距。3.6 这一轮的调优心得一次只改一个变量。我在这轮里严格遵循了先开框架能力、再省显存、再降冗余计算、最后批量调参的顺序任何一个步骤出了问题都能立刻定位。每一步必须重测完整指标别只看单个TTFT或TPOT。有些参数优化了延迟却压低了吞吐权衡要靠全局数据。把优化清单化和数据化。我习惯用表格记录每一轮的参数和结果一个月后回看比任何文档都有说服力。4. 避坑指南与排查思路那些文档里不写的经验4.1 显存OOM排查思路OOM是推理服务最常见的事故。我的排查顺序是这样的先看权重占多少、KV Cache预留占多少。用nvidia-smi和框架的metrics对不上时优先信框架的统计接口nvidia-smi显示的是整体显存包括CUDA context、激活值、临时缓冲区等容易误导。查max_model_len和并发请求的序列长度分布。最大长度*并发数往往就是KV Cache的上限一旦某个请求很极限就会立刻触发OOM。查框架的显存预留比例。vLLM里的gpu_memory_utilization默认0.9如果又开了大量额外bufferOOM概率会很高。解决方式也直接降低max_model_len、收紧并发上限、开启KV Cache量化、或者换更大的GPU。4.2 偶发的TPOT飙高问题有一次压测时发现平均TPOT正常但每过几个请求就出现一次300ms以上的尖峰。排查发现是有长序列请求进入时KV Cache需要重新分配页触发显存整理和内存拷贝。PagedAttention虽然减轻了碎片化但极端情况下仍会有分配开销。最终解决方法是调整框架的调度参数限制了超长请求的批内比例并对请求按长度分组调度。尖峰频率大幅下降。基本思路是不要让长短悬殊的请求坐到同一班车里会互相拖累。4.3 量化后效果不如预期很多团队为了省显存直接上INT4量化结果发现任务效果下降明显。这个问题的根因通常是校准集和真实数据分布不一致。AWQ、GPTQ这类方法需要一小批有代表性的数据做校准校准集选不好量化后的模型权重就偏了。我的做法是至少准备一份和线上业务同分布的prompt集合长度、风格、任务类型都要覆盖。量化的取舍要结合显存、吞吐、精度三个维度来做不要在没评估的情况下为了省显存直接压到INT4。4.4 常见问题速查表我整理了一份实战中高频问题与排查办法方便直接作为参考手册症状常见原因排查方向常用解法显存OOMKV Cache预留不足或并发过高检查显存分布与max_num_seqs调低并发、量化KV Cache、限制最大长度吞吐低未开启连续批处理查看框架调度配置开启Continuous Batching、增大batch上限TTFT过长重复前缀没走缓存检查前缀缓存命中率开启Prefix Caching、移除前缀尾部动态内容TPOT偶发飙高长短序列混批观察尖峰对应请求长度按长度分组、限制超长请求比例量化后质量下降校准集偏差对比量化前后效果指标重做校准、换量化位宽、改用KV量化多卡吞吐不增长通信开销超过算力观察GPU利用率与通信耗时尝试单卡或更小并行度、改用更长batch这六条几乎覆盖了我大部分线上问题的排查路径抄作业应该能解决掉80%的坑。做LLM推理优化这段时间我最大的体会是这个领域的优化空间永远比想象中大但前提是你得先把原理吃透。很多人从网上复制一段配置就跑到线上出问题了连日志都看不懂那是最难受的。如果你刚开始接触这个领域我建议别着急上各种高大上的框架组合先从KV Cache的显存计算开始先理解清楚你模型的显存分布、访问特性和两个阶段的瓶颈差异再谈优化。最后分享一个我养成的习惯为每一次调优建立一份checklist记录环境、参数、改动点、前后指标对比。看起来麻烦但当你遇到生产环境性能回退时这份清单就是最快帮你缩小范围的工具。推理优化没有一劳永逸换成新模型、新硬件甚至新的平均请求长度后原来最优的参数都可能需要重新调这个心理准备得有。