大模型推理优化实战:量化、批处理与框架选型指南 1. 从跑得动到跑得快推理优化到底在解决什么问题很多人第一次把大模型跑起来的时候注意力全在能不能出结果上——模型权重下载完、环境配好、一行命令敲下去屏幕上开始一个字一个字往外蹦那一刻的成就感确实很足。但真正把它放到业务场景里问题立刻就变了响应太慢、显存吃紧、并发一上来就崩、单次调用成本高得离谱。这时候你才会意识到推理优化不是锦上添花的技巧而是决定这套系统能不能真正用起来的分水岭。我见过太多团队卡在这个阶段。模型明明已经部署成功了Demo 演示也没问题可一旦要支撑真实流量就发现单张卡只能扛个位数并发延迟动辄十几秒用户等不了老板也等不了。于是开始到处找加速方案看到别人说量化好就上量化看到别人说 vLLM 快就换 vLLM结果改了一圈效果时好时坏根本说不清到底哪一步起了作用。这个训练营想解决的就是这个问题。它面向的不是从没接触过大模型的纯小白而是那些已经把模型跑起来、但被性能问题卡住的开发者、算法工程师和技术负责人。核心目标很明确让你搞清楚推理链路上每一个环节在消耗什么、瓶颈在哪里、有哪些成熟的优化手段、每种手段的适用边界和代价是什么。学完之后你不只是会抄几个配置而是能针对自己的硬件和业务场景独立设计出一套合理的优化方案。在展开具体内容之前先把推理优化这个词拆开看。它其实包含三个互相拉扯的目标延迟Latency、吞吐Throughput、成本Cost。延迟是单个请求从发出到收到完整回复的时间用户最直观的感受吞吐是单位时间内系统能处理的请求数量直接决定你的服务能力成本则是每处理一个 token 或每个请求所消耗的算力资源折算成的钱。这三者往往互相矛盾——想降低延迟可能会牺牲吞吐想提高吞吐单请求延迟可能上升想压成本又可能两头都受影响。推理优化的本质就是在这三者之间找到适合你业务的那个平衡点而不是盲目追求某一个指标的最优。举个具体的例子。如果你做的是实时对话产品用户盯着屏幕等回复那延迟就是第一优先级哪怕吞吐低一点、成本高一点也得忍如果你做的是离线批量处理比如给几百万条历史数据打标签那吞吐和成本才是关键单条延迟高到几十秒都无所谓。这两种场景下最优的优化策略可能完全相反。所以训练营里反复强调的一件事就是先明确你的场景约束再谈优化手段脱离场景谈哪个方案最好是没有意义的。2. 推理性能的账本算力、显存、带宽到底谁在拖后腿要优化先得会算账。大模型推理的性能瓶颈绝大多数情况下逃不出三个地方计算、显存容量、显存带宽。搞清楚你的瓶颈在哪一个优化才有方向否则就是瞎调。2.1 用两阶段视角理解推理的计算特征大模型的推理过程分成两个阶段这两个阶段的性能特征截然不同理解它们是所有优化的基础。第一个阶段叫Prefill预填充也就是模型处理你输入的整段 prompt 的过程。这个阶段所有输入 token 是并行计算的矩阵乘法的规模很大GPU 的计算单元能被充分喂饱所以它是计算密集型的。你输入的 prompt 越长这个阶段耗时越久而且耗时大致和 prompt 长度成正比。第二个阶段叫Decode解码也就是模型一个 token 一个 token 往外生成的过程。每生成一个 token都要把前面所有 token 的 KV 缓存读一遍然后做一次前向计算。问题在于单次只生成一个 token计算量很小但需要读取的 KV 缓存却随着序列变长而线性增长。这时候 GPU 的算力根本用不满大部分时间都花在从显存里搬数据上所以它是显存带宽密集型的。这个区别极其关键。很多人优化了半天没效果就是因为搞错了瓶颈明明卡在 Decode 阶段的显存带宽上却去优化计算效率自然没用。反过来如果你的场景是长 prompt、短输出比如文档问答那 Prefill 阶段的计算才是大头优化方向又不一样。2.2 显存容量的硬约束模型权重、KV 缓存、激活值显存是很多人第一个撞上的墙。一张卡就那么多显存模型权重、KV 缓存、中间激活值都要抢这块地。模型权重是最刚性的部分。一个 7B 参数的模型如果用 FP16 存储光权重就要占大约 14GB70B 的模型 FP16 下要 140GB 左右单张消费级卡根本放不下。这就是为什么量化如此重要——把权重从 FP16 压到 INT8 或 INT4显存占用直接砍半甚至砍到四分之一很多原本跑不动的模型就能跑起来了。KV 缓存是第二个大头也是最容易被低估的。它的大小和批大小、序列长度、层数、注意力头数、头维度都成正比。序列越长、并发越高KV 缓存膨胀得越厉害。实际部署中经常出现的情况是模型权重加载完还剩不少显存你以为能开大 batch结果跑起来没几个请求就 OOM 了罪魁祸首就是 KV 缓存。这也是后面要讲的 PagedAttention 这类技术要解决的核心问题。中间激活值相对小一些但在大 batch 或长序列下也不能忽略。它的大小和批大小、序列长度、隐藏层维度相关通常在几十 MB 到几 GB 之间波动。2.3 显存带宽Decode 阶段真正的隐形杀手前面说了 Decode 阶段是带宽密集型的这里展开讲讲为什么。假设你有一个 7B 的 FP16 模型权重约 14GB。每生成一个 token理论上都要把这 14GB 权重完整读一遍简化理解实际有缓存和复用。如果一张卡的显存带宽是 1TB/s 左右那读一遍权重就要 14ms 左右。也就是说光是把权重读进来每个 token 就要花十几毫秒这还没算 KV 缓存和其他开销。生成 100 个 token就是 1.4 秒起步。这就是为什么单请求的生成速度有个物理上限再怎么优化计算也突破不了带宽这道墙。理解了这一点很多优化手段的原理就清楚了量化之所以能加速 Decode不只是因为省显存更因为 INT8/INT4 的数据量更小读取同样多的权重需要的带宽更少所以每个 token 的生成时间能明显缩短。同理批处理之所以能提升吞吐是因为多个请求可以共享同一次权重读取把带宽利用率拉满。下面这张表把三个瓶颈的特征和典型应对手段梳理一下方便对照自己的场景判断瓶颈类型典型表现主要出现在常用应对手段计算受限GPU 利用率高算力打满Prefill 阶段、短序列算子融合、更快的注意力实现、张量并行显存容量受限加载模型或开大 batch 时 OOM大模型、长序列、高并发量化、KV 缓存优化、模型并行显存带宽受限GPU 利用率低生成速度上不去Decode 阶段量化、批处理、投机解码提示判断瓶颈最直接的办法是用 profiling 工具看 GPU 利用率和显存带宽占用。如果算力利用率长期低于 30% 而带宽接近打满基本可以确定是带宽瓶颈优先考虑量化和批处理。3. 量化用精度换性能但账要算清楚量化是推理优化里性价比最高的手段之一也是训练营里重点实操的内容。它的核心思想很简单用更低的数值精度来存储和计算减少显存占用和带宽消耗。但具体怎么做、做到什么程度、会损失多少精度里面的门道不少。3.1 FP16、INT8、INT4 的取舍逻辑先理清几种常见精度的区别。FP16 是半精度浮点也是目前大多数模型推理的默认精度数值范围够用、精度损失可忽略。INT8 是 8 位整数显存占用直接减半带宽需求也减半理论上 Decode 速度能提升接近一倍。INT4 更激进显存再砍一半但精度损失开始变得明显需要更精细的处理。量化的关键难点在于浮点数转成整数会丢失信息怎么把损失控制到最小。最朴素的做法是直接对权重做线性映射但这样效果往往不好。实践中更常用的是分组量化——把权重按通道或按块分组每组单独计算缩放因子和零点这样能更好地适应权重的分布差异。分组越细精度保留越好但元数据开销也越大需要权衡。还有一个重要区分权重量化和激活量化。只量化权重相对简单因为权重是静态的可以离线处理好激活值是动态的每个输入都不一样量化起来难度大得多对精度的影响也更敏感。所以很多方案只做权重量化W8A16、W4A16激活值仍用 FP16这样能在保证精度的同时拿到大部分显存和带宽收益。3.2 主流量化方案的实测对比训练营里会带着大家实际跑几种主流方案这里先给个预期。GPTQ 是训练后量化里比较成熟的一种支持 4bit 和 8bit对显存敏感的场景很友好缺点是量化过程本身需要一些时间而且对某些模型结构支持不够好。AWQ 是另一种训练后量化方法它的思路是识别出对输出影响大的重要权重并加以保护实测下来在 4bit 下精度保留通常比朴素 GPTQ 更好是目前比较推荐的方案之一。GGUF 格式则更多用于 CPU 或混合推理场景量化粒度选择丰富从 2bit 到 8bit 都有适合资源受限的环境。需要提醒的是量化不是无损的也不是所有模型都适合激进量化。有些模型在 4bit 下表现依然稳健有些模型掉点就很明显。所以量化之后一定要做评测用你自己的业务数据跑一遍对比量化前后的输出质量而不是只看困惑度这种通用指标。我踩过的坑就是某个模型 4bit 量化后通用评测看着还行但一到具体的结构化抽取任务上就开始胡言乱语最后只能退回 8bit。3.3 量化实操中的精度验证方法量化做完怎么验证我的经验是分三层。第一层是通用能力快速筛查用一些标准评测集跑一遍看有没有明显掉点这一步主要是排除量化过程本身出错的情况。第二层是业务数据对比拿一批真实输入分别用原始模型和量化模型跑人工或自动对比输出差异重点看关键信息有没有丢失、格式有没有跑偏。第三层是边界情况测试专门挑那些容易出问题的输入比如超长文本、特殊符号、多轮对话看量化模型会不会崩。这三层做完你才能对量化方案是否可用有个靠谱的判断。别嫌麻烦量化上线后出问题再回滚代价比这大得多。4. 批处理与调度把 GPU 喂饱的艺术如果说量化是省着用那批处理就是用满它。GPU 最怕的就是闲着而单请求推理恰恰让 GPU 大量时间处于等待状态。批处理的核心思路是把多个请求攒到一起共享同一次计算和权重读取从而把吞吐拉上去。4.1 静态批处理为什么在真实场景里不好用最朴素的批处理是静态批处理攒够 N 个请求一起送进模型等全部生成完再一起返回。听起来简单但真实场景里问题很大。首先是请求长度参差不齐。有的请求输入几十个 token有的几千个有的输出一句话就结束有的要生成上千 token。静态批处理要么按最长的来 padding浪费大量计算要么就得等所有请求都凑齐且长度接近调度延迟高得离谱。其次是请求到达时间不确定你没法保证同一批请求能同时到齐等待凑批的时间可能比推理本身还长。最后是一个请求卡住整批都受影响用户体验很差。所以静态批处理基本只适合离线批量任务在线服务里很少直接用。4.2 连续批处理让每个请求独立进退连续批处理Continuous Batching是现在在线推理的主流方案vLLM、TensorRT-LLM 这些框架都支持。它的核心改进是不再等整批请求全部完成而是以 token 为粒度调度。某个请求生成完了就立刻退出批次空出来的位置马上让新到达的请求补上。这样 GPU 始终有活干利用率大幅提升同时新请求也不用等前面所有请求都结束才能开始。这个机制带来的吞吐提升非常可观实测中相比静态批处理经常能有好几倍的差距。而且它对请求长度差异的容忍度很高长短请求混在一起也不会互相拖累太多。不过连续批处理也有代价调度逻辑更复杂对 KV 缓存的管理要求更高因为批次里的请求随时在变缓存要能动态分配和回收。这就引出了下一节要讲的 PagedAttention。4.3 PagedAttention 与 KV 缓存的分页管理KV 缓存的管理是连续批处理的关键难点。传统做法是给每个请求预分配一块连续的显存按最大可能长度来分。问题是大部分请求根本用不到那么长预分配的空间大量浪费而且显存碎片化严重想开大 batch 也开不起来。有研究指出传统方案下 KV 缓存的实际利用率可能只有两三成剩下的全浪费了。PagedAttention 借鉴了操作系统虚拟内存分页的思路把 KV 缓存切成固定大小的块block按需分配不要求连续。每个请求维护一张块表记录自己的缓存分散在哪些块里。这样一来显存利用率大幅提升碎片问题也缓解了能支撑的并发数明显增加。同时因为块是固定大小的内存分配和回收都很快非常适合连续批处理这种动态场景。实测下来开启 PagedAttention 后同样的显存能支撑的并发请求数经常能翻倍甚至更多这对成本敏感的业务来说是实打实的收益。4.4 调度策略对延迟和吞吐的实际影响批处理不是越大越好。批次越大吞吐越高但单个请求的延迟也会上升因为要等更久才能轮到、计算资源被更多请求分摊。所以调度策略要在延迟和吞吐之间做权衡。常见的做法是设置一个最大批大小和最大等待时间攒批时如果达到最大批大小就立即执行或者等待时间超过阈值也执行避免请求无限期等待。这两个参数需要根据你的业务延迟要求来调。实时对话场景下等待时间要设得很短宁可批次小一点离线场景下可以设长一点把批次攒大。还有一个技巧是优先级调度给不同请求打不同优先级重要的请求优先处理。这在混合负载场景下很有用比如同时有实时请求和后台任务时保证实时请求的体验。5. 推理框架选型别被最快的宣传带偏市面上的推理框架不少vLLM、TensorRT-LLM、SGLang、llama.cpp 各有侧重。选型的时候最忌讳的就是只看别人benchmark里的最快因为那些数据往往是在特定硬件、特定模型、特定负载下测出来的换个场景可能完全不一样。5.1 vLLM、TensorRT-LLM、SGLang 的定位差异vLLM 是目前社区最活跃、上手最友好的方案之一PagedAttention 和连续批处理都是它的招牌能力对 HuggingFace 模型的支持很好改造成本低。它的优势是通用性强、生态好、文档全适合大多数团队作为默认选择。缺点是极致性能上可能不如专门优化的方案。TensorRT-LLM 是偏底层的方案需要把模型编译成 TensorRT 引擎过程相对繁琐对模型改动也更敏感。但换来的是极致的性能尤其在特定硬件上经过充分调优后延迟和吞吐都能做到很好。适合对性能有极致要求、且愿意投入工程成本的团队。SGLang 在结构化生成和复杂调度上有独特优势比如需要约束输出格式、做前缀共享的场景它的 RadixAttention 能显著提升缓存复用率。如果你的业务涉及大量共享前缀的请求比如固定的系统提示词值得重点考虑。llama.cpp 则主打轻量和 CPU/混合推理量化支持丰富适合资源受限或边缘部署的场景。它的性能当然比不上 GPU 方案但在没有 GPU 或者想低成本跑起来的时候非常实用。5.2 选型时真正该看的几个指标选框架别只看吞吐数字我建议重点看这几个方面首 token 延迟TTFT和每 token 延迟TPOT要分开看。TTFT 决定用户多久能看到第一个字TPOT 决定后续生成的速度。不同框架在这两个指标上的表现可能差异很大要结合你的场景判断哪个更重要。显存效率直接关系到你的硬件成本。同样的卡能跑多大的模型、支撑多少并发这是真金白银的差别。对量化的支持程度也很关键。有些框架对某些量化格式支持好有些则有限制选之前要确认清楚。社区活跃度和文档质量决定了你遇到问题能不能快速找到答案。一个再快但没人维护的框架长期来看是负担。和现有技术栈的兼容性也不能忽略。如果你的服务已经有一套成熟的部署体系选一个能平滑接入的框架比推倒重来划算得多。5.3 从零搭一套推理服务的完整链路训练营里会带着大家从零搭一套完整的推理服务这里把链路梳理一下让你有个全局认识。第一步是环境准备包括驱动、CUDA、Python 环境、框架安装。这一步看似简单实则坑最多版本不匹配导致的各种报错能折腾很久。建议用容器化方案把环境固化下来避免在我机器上能跑的问题。第二步是模型准备包括下载权重、格式转换、量化处理。如果要用量化这一步就要把量化做好并验证精度。第三步是服务配置设置批大小、最大序列长度、显存占用比例、调度参数等。这些参数直接决定性能表现需要根据实测反复调整。第四步是接口封装把推理服务包装成 HTTP 或 gRPC 接口加上鉴权、限流、日志、监控。这一步是把能跑变成能对外服务的关键。第五步是压测调优用真实或模拟的负载压测找出瓶颈针对性优化。这一步往往要迭代好几轮。第六步是上线监控持续观察延迟、吞吐、错误率、显存占用等指标及时发现和解决问题。6. 那些只有踩过才知道的坑理论讲再多不如把实际踩过的坑摆出来。这部分是训练营里最受欢迎的内容因为都是真金白银换来的经验。6.1 显存明明够却 OOM 的几种原因最常见的一种情况是模型加载完看着还剩不少显存一跑就 OOM。原因通常有几个。一是KV 缓存没算够前面说过它随序列长度和并发增长很容易被低估。二是显存碎片反复分配释放之后虽然总空闲显存够但没有一块连续的大空间能满足需求。三是框架的显存预分配策略有些框架会一次性占掉很大比例显存留给其他操作的空间就少了。四是中间激活值在特定输入下暴涨比如遇到超长序列时。排查这类问题建议先把最大序列长度和批大小调小确认能稳定运行后再逐步往上加找到真正的上限。同时用工具监控显存的实际使用曲线看是哪个环节在涨。6.2 量化后效果变差的排查思路量化后效果变差先别急着否定量化按顺序排查。首先确认量化过程本身有没有出错比如校准数据是否合适、分组配置是否合理。然后对比不同量化位宽4bit 不行就试 8bit看是不是位宽太低导致的。接着检查是不是特定任务受影响有些任务对精度敏感有些则无所谓可能只需要对敏感任务用高精度。最后考虑混合方案比如关键层用高精度、其他层用低精度。我遇到过一个案例模型量化后通用对话没问题但一到数学计算就出错。后来发现是量化影响了数值敏感的注意力计算最后对那几层单独保留高精度才解决。6.3 并发上不去、延迟忽高忽低的定位方法并发上不去、延迟不稳定通常和调度、缓存、资源竞争有关。先看是不是批处理没生效如果框架配置不对请求可能还是一个个串行处理的。再看KV 缓存是不是频繁换入换出如果显存不够导致缓存被反复驱逐性能会剧烈波动。还要看是不是有长请求拖累短请求一个超长生成任务占着资源不放会让其他请求排队。定位这类问题压测工具和监控指标是必须的。记录每个请求的 TTFT、TPOT、总耗时看分布而不是只看平均值往往能发现被平均掩盖的问题。6.4 长上下文场景下的特殊处理长上下文是现在的热点但也是性能杀手。序列一长Prefill 计算量暴涨KV 缓存也膨胀得厉害。针对这种场景有几个思路一是用更高效的注意力实现比如 FlashAttention 这类能显著降低长序列的显存和计算开销二是做前缀缓存如果多个请求共享相同的前缀比如系统提示词可以缓存这部分的计算结果避免重复计算三是考虑上下文压缩或检索增强不是所有场景都需要把全部上下文塞进去用检索的方式只取相关部分能大幅降低序列长度。7. 从训练营到生产把优化落到你的业务里学完这些技术最终要落到自己的业务上。这里给几条实操建议。先建立基线再谈优化。别一上来就堆技术先用最简单的配置把服务跑起来测出基线性能记录延迟、吞吐、显存占用。有了基线后面每做一项优化都能量化对比知道到底有没有用。一次只改一个变量。优化手段之间会互相影响同时改好几个出了问题根本不知道是哪个导致的。改一个、测一个、记录一个稳扎稳打。性能优化没有终点只有平衡。你的业务在变、流量在变、模型在变今天的最优配置明天可能就不适用了。建立一套持续监控和调优的机制比一次性调好更重要。别忽略成本和可维护性。有时候为了榨出最后一点性能引入的复杂度会让后续维护成本飙升得不偿失。够用就好把精力留给真正影响业务的地方。训练营的价值不在于教会你几个命令而在于帮你建立起一套分析问题、定位瓶颈、选择方案、验证效果的完整方法论。这套方法论才是你在面对任何新模型、新硬件、新场景时都能用得上的东西。