
1. 大模型推理加速的底层逻辑与方案选型大模型推理这件事真正落到生产环境里最扎心的往往不是模型效果不够好而是延迟太高、显存吃紧、吞吐上不去。我最早接触推理优化的时候总觉得把模型权重加载进去、跑通前向传播就算完事后来才发现那只是万里长征第一步。一个 70B 级别的模型FP16 精度下光权重就要占掉 140GB 左右的显存单卡根本放不下多卡并行又会带来通信开销推理成本直接起飞。所以推理加速的核心目标其实就三个字省、快、稳——省显存、快响应、稳吞吐。围绕这三个目标业界逐渐沉淀出几条主流技术路线其中最具代表性的就是量化Quantization、投机采样Speculative Sampling和PD 分离Prefill-Decode Disaggregation。这三者并不是互相替代的关系而是分别作用在推理链路的不同环节上量化解决的是“权重和激活占多大空间”的问题投机采样解决的是“每个 token 生成要跑多少次前向”的问题PD 分离解决的是“预填充和解码两个阶段互相拖累”的问题。理解它们各自的位置比死记某个具体算法重要得多。1.1 推理的两个阶段Prefill 与 Decode 的本质差异要搞懂 PD 分离为什么有价值得先明白大模型推理到底分几步。当你给模型一段 prompt它内部其实经历两个截然不同的阶段。Prefill 阶段也叫预填充是把整段输入 prompt 一次性喂进去计算所有 token 的 Key 和 Value存进 KV Cache。这个阶段的特点是计算密集——矩阵乘法规模大GPU 的算力能被充分打满属于典型的 compute-bound。比如你输入 2000 个 token 的 promptPrefill 会并行处理这 2000 个 token耗时相对可控。Decode 阶段也叫解码是自回归地一个 token 一个 token 往外吐。每生成一个新 token都要拿它去和之前所有的 KV 做注意力计算。这个阶段的特点是访存密集——每次只算一个 token矩阵乘法的规模很小GPU 算力大量闲置瓶颈卡在把 KV Cache 从显存里读出来这件事上属于 memory-bound。这两个阶段的资源特性完全相反如果混在同一个 batch 里跑就会出现一种尴尬局面Prefill 的长 prompt 把算力占满Decode 的请求只能干等首 token 延迟TTFT和每 token 延迟TPOT互相打架。PD 分离的思路就是把这两个阶段拆到不同的实例上各跑各的互不干扰。1.2 三条技术路线的定位与协同关系把三条路线放在一张图里看会更清楚。量化是纵向压缩把每个参数、每个激活的位宽降下来直接减少显存占用和访存带宽压力对 Prefill 和 Decode 都有收益。投机采样是横向加速用一个小模型快速草拟多个 token再让大模型一次性验证把原本 N 次串行前向变成 1 次并行验证主要优化 Decode 阶段。PD 分离是结构解耦把两个阶段物理隔离开让 Prefill 实例专心算、Decode 实例专心吐各自按最优 batch 策略调度。实际生产里这三者经常是叠加使用的。我见过的一个典型配置是权重用 INT8 或 INT4 量化Decode 阶段挂一个 1B 左右的草稿模型做投机采样底层用 PD 分离把 Prefill 和 Decode 分到不同 GPU 池。这套组合下来相比朴素 FP16 单机推理吞吐能提升 3 到 5 倍首 token 延迟能压到原来的三分之一左右。当然具体数字跟模型结构、硬件、请求分布都有关系不能一概而论。提示不要一上来就三件套全上。量化是最容易落地、收益最直接的建议先做量化拿到基础收益再根据瓶颈决定要不要上投机采样或 PD 分离。盲目堆技术只会让排查问题的难度指数级上升。2. 量化技术从 FP16 到 INT4 的实操拆解量化是我个人认为性价比最高的一环。它的核心思想说白了就是神经网络权重里大量的数值其实并不需要那么高的精度用更少的比特位去近似表示模型效果掉一点点但显存和带宽省一大截。这里面的门道不少选错了方案可能精度崩得没法用。2.1 量化的基本原理与精度损失来源先讲清楚量化到底在做什么。假设一个权重张量的取值范围是 [-2.5, 2.5]我们要把它量化成 INT8。INT8 能表示 -128 到 127 共 256 个整数。量化的过程就是找一个缩放因子 scale把浮点值映射到整数区间scale (max - min) / (qmax - qmin) q round(x / scale)反量化的时候再乘回去x_hat q * scale。这个x_hat和原始x之间的差就是量化误差。误差来源主要有两个一是舍入误差round 操作本身会丢信息二是截断误差如果取值范围估计不准超出范围的值会被 clip 掉这部分损失往往更致命。所以量化的关键就在于怎么选 scale 和 zero-point。业界主流分两大流派对称量化和非对称量化。对称量化强制零点对齐scale 只由一个绝对值最大的数决定实现简单、计算快适合权重这种近似对称分布的非对称量化允许零点偏移能更好覆盖激活这种分布偏斜的数据但计算多一步。2.2 PTQ 与 QAT两条落地路径怎么选按介入时机分量化又分训练后量化PTQ和量化感知训练QAT。PTQ 是拿训练好的模型直接量化不需要重新训练落地成本极低。它的做法通常是准备一批校准数据几百到几千条就够跑一遍前向统计每层激活的分布据此确定 scale。优点是快缺点是低比特比如 INT4下精度损失可能比较明显。QAT 是在训练阶段就模拟量化误差让模型自己去适应。具体做法是在前向里插入伪量化节点把权重和激活先量化再反量化反向传播时用 STE直通估计器把梯度传过去。这样训练出来的模型对量化误差更鲁棒INT4 甚至更低比特下也能保持不错的精度。代价是要重新训练算力成本高。我的经验是INT8 用 PTQ 基本够用INT4 及以下优先考虑 QAT 或者用 GPTQ/AWQ 这类进阶 PTQ 方法。GPTQ 通过逐层最小化量化误差来求解权重AWQ 则关注激活里那些重要的通道对显著权重做保护。这两个方法在开源社区用得非常多效果也经过大量验证。2.3 实操用 GPTQ 量化一个 7B 模型的完整流程下面这套流程是我实际跑通过的以量化一个 7B 模型为例环境是单张 24GB 显存的卡。第一步准备环境和依赖pip install transformers accelerate auto-gptq optimum第二步准备校准数据。GPTQ 需要一批文本做校准通常从训练集里抽 128 到 512 条就够。数据质量比数量重要最好覆盖模型实际会遇到的领域。from datasets import load_dataset calib load_dataset(wikitext, wikitext-2-raw-v1, splittrain) calib calib.select(range(512))第三步执行量化。这里关键参数是bits量化位宽和group_size分组大小from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig quantize_config BaseQuantizeConfig( bits4, group_size128, desc_actFalse, ) model AutoGPTQForCausalLM.from_pretrained( your-model-path, quantize_configquantize_config, ) model.quantize(calib) model.save_quantized(your-model-4bit)group_size128的意思是每 128 个权重共享一个 scale组越小精度越高但元数据开销越大。desc_act控制是否按激活重要性重排权重开了精度更好但推理稍慢。这两个参数是精度和速度的主要调节旋钮。2.4 量化避坑那些文档里不会写的细节踩过的坑得说几个。第一校准数据分布要和实际推理分布接近。我有一次用纯英文语料校准一个中文模型结果中文任务上精度掉得厉害换成中文校准集后恢复正常。第二注意 KV Cache 的量化。很多人只量化了权重忘了 KV Cache 才是 Decode 阶段显存的大头。KV Cache 量化对精度更敏感建议单独评估别和权重量化一起上。第三量化后的模型要重新测一遍端到端指标不能只看 perplexity因为 perplexity 对生成质量的变化不敏感最好用实际任务的评测集。还有一个容易被忽略的点不同推理框架对量化格式的支持不一样。GPTQ 格式在 vLLM、TGI 里支持较好AWQ 在部分框架里支持更完善。选量化方案前先确认你的推理框架支持哪种格式否则量化完了跑不起来就白干了。3. 投机采样用小模型撬动大模型的解码速度投机采样是我觉得最“聪明”的一个优化。它的洞察很朴素大模型生成一个 token 要跑一次完整前向太贵了但如果有个小模型能快速猜出接下来几个 token大模型只需要一次性验证这几个猜测对不对就能把多次串行前向压缩成一次并行前向。这就像你让实习生先起草一份文件资深员工只需要审一遍改几个字比从头写快得多。3.1 投机采样的数学原理为什么验证能保证无损很多人第一次听说投机采样会担心小模型猜的能准吗猜错了怎么办这里的关键在于投机采样有一套严格的接受-拒绝机制理论上能保证最终输出分布和大模型自己生成完全一致也就是无损加速。具体流程是这样的小模型草稿模型自回归生成 γ 个候选 token记为 x1 到 xγ。然后大模型对这 γ 个 token 做一次并行前向得到每个位置的真实概率分布。对每个候选 token按一个接受概率决定是否采纳接受概率 min(1, p_large(x) / p_draft(x))如果某个位置的候选被拒绝就从修正后的分布里重新采样一个 token并且丢弃后面所有候选。这个机制保证了输出分布严格等于大模型的分布。γ 是投机长度通常取 4 到 8太短收益有限太长拒绝率上升反而浪费。3.2 草稿模型的选型不是越小越好草稿模型的选择直接决定加速比。理想情况下草稿模型要满足两个条件足够快推理延迟远低于大模型和足够准接受率高。这两个条件往往是矛盾的——模型越小越快但越不准。我的经验是草稿模型参数量控制在大模型的 1/10 到 1/20 比较合适。比如 70B 的模型配 3B 到 7B 的草稿模型7B 的模型配 0.5B 到 1B 的草稿模型。同系列的小模型通常是最佳选择因为它们的 tokenizer 和训练数据分布一致接受率天然更高。除了独立草稿模型还有几种变体值得了解。Medusa是在大模型上加多个预测头并行预测多个未来 token不需要单独的草稿模型但需要额外训练。EAGLE则是在特征层面做投机用大模型的隐层特征来预测接受率比独立草稿模型更高。这几个方案各有取舍Medusa 部署简单EAGLE 效果更好但实现复杂。3.3 实操在 vLLM 中启用投机采样vLLM 对投机采样的支持比较成熟配置起来不复杂。假设你有一个 7B 的主模型和一个 0.5B 的草稿模型python -m vllm.entrypoints.openai.api_server \ --model your-7b-model \ --speculative-model your-0.5b-draft \ --num-speculative-tokens 5 \ --tensor-parallel-size 1num-speculative-tokens就是前面说的 γ从 5 开始调观察接受率和实际吞吐。如果接受率低于 60%说明草稿模型和主模型差距太大考虑换一个更匹配的草稿模型或者降低 γ。实测下来在代码生成、翻译这类输出确定性较高的任务上投机采样的加速比能到 2 到 3 倍但在创意写作、开放对话这类输出随机性大的任务上接受率会明显下降加速比可能只有 1.3 到 1.5 倍。所以投机采样不是万能的得看你的业务场景。3.4 投机采样的调优经验与常见误区调优的核心指标是接受率和平均接受长度。接受率低说明草稿模型不给力平均接受长度短说明 γ 设得太大后面的候选基本被拒。我一般会先固定 γ5 跑一批真实请求统计接受率再决定是调 γ 还是换草稿模型。一个常见误区是只看加速比不看显存。草稿模型虽然小但也要占显存而且投机采样会同时加载两个模型显存占用是叠加的。如果你的显存本来就紧张上投机采样可能直接 OOM。另一个误区是在 batch size 很大时用投机采样。当 batch 已经很大GPU 算力被充分利用时投机采样带来的收益会大幅缩水因为瓶颈从访存变成了算力而投机采样本质是拿算力换访存。所以投机采样更适合低并发、低延迟的场景。4. PD 分离把预填充和解码彻底解耦PD 分离是这三个技术里工程复杂度最高的但也是大规模服务场景下收益最明显的。它的核心思想前面提过Prefill 是 compute-boundDecode 是 memory-bound两者混跑会互相干扰。PD 分离就是把它们拆到不同的实例组各自按最优策略调度。4.1 为什么混跑会互相拖累一个具体的量化分析举个具体例子。假设你有一个请求prompt 长度 2000 token要生成 500 token。在混跑模式下这个请求的 Prefill 阶段会占用大量算力导致同一 batch 里其他正在 Decode 的请求被阻塞它们的 TPOT 会突然飙升。反过来当大量 Decode 请求在跑时新来的 Prefill 请求又得排队TTFT 变长。更本质的问题是Prefill 和 Decode 对 batch 的偏好完全不同。Prefill 喜欢大 batch因为算力密集batch 越大 GPU 利用率越高。Decode 喜欢适中的 batch因为访存密集batch 太大反而会让 KV Cache 读取成为瓶颈。混在一起你没法同时满足两者的最优 batch 策略。PD 分离后Prefill 实例可以专心跑大 batch 的预填充Decode 实例专心跑小 batch 的解码各自达到最优。中间通过 KV Cache 的传输把两个阶段连起来——Prefill 算完的 KV Cache 要传给 Decode 实例。4.2 KV Cache 传输PD 分离的关键工程挑战KV Cache 的传输是 PD 分离里最考验工程能力的地方。一个 70B 模型2000 token 的 promptKV Cache 大小大概是2 (K和V) × 80 (层数) × 8 (KV头数) × 128 (头维度) × 2000 (token数) × 2 (FP16字节) ≈ 6.5 GB6.5GB 的数据要在 Prefill 和 Decode 实例之间传输如果走普通网络延迟会非常可观。所以 PD 分离通常要求高带宽互联比如 NVLink、RDMA 或者高速以太网。传输方式也有讲究可以整块传也可以分层流水传——Prefill 算完一层就传一层Decode 那边边收边算重叠传输和计算。我见过的一个优化是按需传输。不是所有 KV Cache 都要立刻传Decode 实例可以先接收最近几层的 KV 开始解码前面的层慢慢传。这样能进一步压低首 token 延迟。当然这需要框架层面的支持不是所有推理引擎都实现了。4.3 实操基于 vLLM 的 PD 分离部署思路vLLM 从较新版本开始支持 disaggregated prefill配置上需要分别启动 Prefill 实例和 Decode 实例并通过一个协调层连接。大致思路如下。Prefill 实例启动python -m vllm.entrypoints.openai.api_server \ --model your-model \ --port 8100 \ --kv-transfer-config {kv_connector:PyNcclConnector,kv_role:kv_producer}Decode 实例启动python -m vllm.entrypoints.openai.api_server \ --model your-model \ --port 8200 \ --kv-transfer-config {kv_connector:PyNcclConnector,kv_role:kv_consumer}kv_producer负责生产 KV Cachekv_consumer负责消费。中间还需要一个代理层根据请求阶段做路由。这套配置对网络要求较高建议在有多卡高速互联的环境里跑。4.4 PD 分离的适用边界与成本权衡PD 分离不是银弹它有明确的适用边界。它最适合的场景是请求量大、prompt 长度差异大、对 TTFT 和 TPOT 都有严格要求。比如在线客服、实时问答这类场景用户既不想等太久才看到第一个字也不想看到字之后半天蹦不出下一个。反过来如果你的请求量很小或者 prompt 都很短PD 分离带来的复杂度可能得不偿失。因为你需要维护两套实例、一套传输链路、一个路由层运维成本不低。而且 Prefill 和 Decode 实例的配比需要根据实际流量动态调整配比失衡会导致一方闲置一方过载。我的建议是先用量化和投机采样把单机性能榨干当单机确实扛不住、且瓶颈明确在 Prefill/Decode 互相干扰时再考虑 PD 分离。它是一个规模化阶段的优化手段不是起步阶段该碰的东西。5. 三套技术的组合实战与效果对比单独讲完三个技术得说说它们组合起来怎么用。这部分是我在实际项目里反复调过的分享一些真实的数据和踩坑记录。5.1 组合策略按瓶颈决定优先级组合的基本原则是先解决最大的瓶颈。我一般按这个顺序排查先看显存够不够不够就上量化显存够了但 Decode 慢上投机采样两者都优化了还是扛不住并发上 PD 分离。一个典型的组合配置是这样的权重 INT4 量化GPTQKV Cache 保持 FP16Decode 阶段挂 0.5B 草稿模型做投机采样底层用 PD 分离。这套配置在一台 8 卡 A100 的机器上跑一个 70B 模型实测能支撑的并发请求数比朴素 FP16 单机方案高出一个数量级。不过要注意量化 投机采样会有交互影响。量化后的主模型输出分布和草稿模型的分布差异可能变大导致接受率下降。我遇到过 INT4 量化后接受率从 75% 掉到 60% 的情况这时候要么换更准的量化方案要么调低 γ。5.2 效果对比不同组合的实测数据下面这张表是我在一个内部测试集上的实测结果模型是 13B 级别硬件是单张 A100 80GB请求分布是 prompt 平均 500 token、生成平均 200 token。数据仅供参考实际会因模型和场景而异。配置方案显存占用TTFT (ms)TPOT (ms)吞吐 (token/s)FP16 基线26 GB32045850INT8 量化15 GB290381100INT4 量化9 GB270351250INT4 投机采样11 GB275182100INT4 投机 PD 分离11 GB × 2180163200从数据能看出几个规律量化主要降显存和 TPOT对 TTFT 改善有限投机采样主要降 TPOT因为 Decode 阶段被加速了PD 分离主要降 TTFT因为 Prefill 不再被 Decode 阻塞。三者叠加TTFT 和 TPOT 都得到了明显改善。5.3 监控与调优上线后要盯哪些指标上线之后不能就不管了得持续监控几个关键指标。接受率是投机采样的命脉低于 60% 就要警惕。KV Cache 命中率反映 PD 分离的传输效率太低说明传输成了瓶颈。GPU 利用率要分 Prefill 和 Decode 分别看如果 Prefill 实例利用率长期偏低说明配比失衡要调整实例数量。还有一个容易被忽略的指标是排队延迟。PD 分离后请求要在 Prefill 和 Decode 之间流转如果路由层调度不当请求可能在某一侧排队。这个延迟不体现在 TTFT 和 TPOT 里但用户能感知到。我一般会在代理层加一个端到端的延迟埋点把排队时间单独统计出来。6. 常见问题排查与避坑速查最后整理一份速查表都是我在实际项目里真金白银踩出来的。问题现象可能原因排查方向解决建议量化后精度暴跌校准数据分布不匹配检查校准集和业务数据分布换用业务相关校准集或改用 AWQ投机采样加速比低草稿模型不匹配统计接受率换同系列草稿模型调低 γPD 分离后 TTFT 反而变高KV Cache 传输慢检查网络带宽和传输方式上 RDMA或改分层流水传输显存 OOMKV Cache 未量化看 KV Cache 占用量化 KV Cache或降低并发吞吐上不去batch 策略不当看 GPU 利用率调整 Prefill/Decode 实例配比输出质量不稳定量化 投机交互对比不同组合的输出降低量化位宽或调整投机参数几个独家避坑技巧。第一量化模型一定要做 A/B 测试用真实业务数据对比量化前后的输出别只看 benchmark。第二投机采样的草稿模型要和主模型用同一个 tokenizer否则 token 对不齐接受率会惨不忍睹。第三PD 分离的实例配比要动态调白天和晚上的流量特征不一样固定配比会浪费资源。第四所有优化都要有回滚方案量化模型和原始模型都留着出问题能快速切回去。我个人在实际操作中的体会是推理加速这件事没有一劳永逸的方案它是一个持续调优的过程。模型在变、流量在变、硬件在变今天的最优配置明天可能就不是了。所以比起记住某个具体参数更重要的是理解每个技术背后的原理和适用边界这样遇到新情况才能自己判断该往哪个方向调。另外别迷信网上的“最佳实践”那些数据都是在特定条件下测出来的你的场景大概率不一样一定要自己动手测。