
1. 大模型推理加速的底层逻辑与方案选型大模型推理这件事真正落到生产环境里最扎心的往往不是模型效果而是成本和延迟。一个 70B 级别的模型如果按 FP16 精度部署光权重就要吃掉 140GB 显存单卡根本放不下多卡并行又带来通信开销。更别提在线服务场景下用户等三秒就开始不耐烦吞吐量上不去GPU 利用率还低得可怜。所以推理加速不是锦上添花而是能不能把服务跑起来、跑得起的生死线。我接触过的加速手段大致分三个层次模型层面的压缩、解码策略层面的优化、系统架构层面的拆分。量化属于第一层直接砍掉权重的数值精度把显存和带宽压力降下来投机采样属于第二层用一个小模型去“猜”大模型的输出猜对了就一次验证多个 token把串行解码变成近似并行PD 分离属于第三层把预填充和解码两个阶段拆到不同硬件上跑各自用最适合的资源配比。这三者不是互斥的实际生产里经常是组合拳。先说量化为什么是第一优先级。大模型推理的瓶颈在解码阶段几乎完全是显存带宽不是算力。每生成一个 token都要把整个模型的权重从显存读一遍算力单元大部分时间在等数据。量化把 FP16 的 2 字节压到 INT8 的 1 字节甚至 INT4 的 0.5 字节带宽需求直接减半或降到四分之一解码速度自然就上去了。而且显存占用降低后同样的卡能塞下更大的模型或者更长的上下文这对成本敏感的场景太关键了。但量化不是无脑压精度。我见过太多人一上来就上 INT4结果模型输出开始胡言乱语尤其是数学推理和代码生成任务掉点非常明显。这里面的核心矛盾是权重的数值分布不均匀少数几个离群值outlier撑起了很大的动态范围如果直接均匀量化大部分正常权重就被压到很小的区间里精度损失严重。所以主流的量化方案都在解决离群值问题比如 GPTQ 用二阶信息做逐层误差补偿AWQ 则通过激活感知的方式保护重要通道。选哪个取决于你的模型结构、任务类型和硬件支持。投机采样的思路则完全不同。它不改变模型本身而是改变解码的“节奏”。标准自回归解码是一个 token 一个 token 往外蹦每个 token 都要跑一次完整的前向。投机采样引入一个草稿模型draft model通常是同系列的小模型或者经过蒸馏的轻量模型让它连续生成 K 个候选 token然后大模型一次性对这 K 个 token 做并行验证。如果草稿猜得准一次前向就能确认多个 token等效于把解码步数除以一个大于 1 的系数。这个系数就是接受率接受率越高加速越明显。PD 分离则是从系统层面动刀。预填充阶段prefill是计算密集型的要处理整个输入序列的注意力算力吃满解码阶段decode是访存密集型的每次只处理一个新 token但要把权重全读一遍。这两个阶段的资源特性完全相反如果混在同一批 GPU 上跑就会出现“预填充来了解码卡顿解码跑着预填充排队”的互相干扰。PD 分离把预填充和解码拆到不同的实例甚至不同的机器上预填充用高算力卡解码用高带宽卡各自独立扩缩容整体吞吐和尾延迟都能明显改善。这三项技术组合起来基本覆盖了当前大模型推理加速的主流路径。下面我按实际落地的顺序把每一块拆开讲透包括参数怎么选、坑在哪里、怎么验证效果。2. 量化技术从 FP16 到 INT4 的精度与速度权衡2.1 量化到底在量化什么量化的本质是用低比特整数去近似浮点数。以 INT8 为例把一个 FP16 的权重张量映射到 [-127, 127] 的整数区间需要一个缩放因子 scale。反量化的时候用整数乘以 scale 还原。听起来简单但问题在于一个张量里权重的最大值和最小值差距可能非常大如果按全局最大值定 scale大部分权重就被压缩到很窄的整数范围里量化误差大得离谱。所以实际方案都是分组量化group-wise quantization。把权重按通道或者按块分组每组独立算 scale。组越小精度越高但 scale 的存储开销也越大。常见的 group size 是 128 或 64这是一个经验和显存的平衡点。我实测下来group size 从 128 降到 64困惑度perplexity能改善 0.1 到 0.3但显存多占几个百分点值不值得看你的显存余量。另一个关键概念是对称量化 vs 非对称量化。对称量化把零点固定在 0只存 scale适合权重分布近似对称的情况非对称量化额外存一个 zero-point能更好地处理分布偏移但计算稍复杂。权重通常用对称量化就够了激活值因为经过非线性层后分布偏移明显往往需要非对称。2.2 GPTQ、AWQ、GGUF 怎么选目前工程上最常用的几套量化方案我列个表对比一下实际使用感受方案比特支持核心思路优点缺点适用场景GPTQ4/3/2 bit逐层二阶误差补偿生态成熟vLLM/TGI 原生支持量化耗时较长对校准集敏感服务端 GPU 部署AWQ4 bit激活感知保护重要通道精度保持好推理快主要支持 4bit灵活性低对精度要求高的在线服务GGUF2-8 bit多种量化类型混合CPU/GPU 混合推理友好GPU 纯推理效率不如前两者本地部署、边缘设备bitsandbytes8/4 bit训练时在线量化无需离线校准即插即用推理速度一般精度略逊微调场景、快速验证选型的时候我一般这么判断如果是纯 GPU 服务端优先 GPTQ 或 AWQvLLM 对这两个支持最好加载即用。如果要在消费级显卡或者 CPU 上跑GGUF 是唯一选择llama.cpp 生态完善。如果只是临时验证或者要做 QLoRA 微调bitsandbytes 最省事。这里有个容易踩的坑不同量化方案对模型结构的适配不一样。比如某些 MoE 模型专家层的权重分布和稠密层差异很大直接套用统一的 group size 会导致专家路由失效。我遇到过 GLM 系列量化后某些专家几乎不被激活的情况后来把专家层的 group size 单独调小才恢复。所以量化完一定要做任务级评测不能只看困惑度。2.3 实操用 GPTQ 量化一个 7B 模型下面是我常用的 GPTQ 量化流程基于 AutoGPTQ 库。先装依赖pip install auto-gptq optimum transformers然后写量化脚本。核心参数就几个bits选 4group_size选 128desc_act建议开启按激活重要性排序精度更好但稍慢校准集用模型对应的领域数据一般 128 到 256 条就够。from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig from transformers import AutoTokenizer import json model_id Qwen/Qwen2.5-7B-Instruct out_dir ./qwen2.5-7b-gptq-int4 quantize_config BaseQuantizeConfig( bits4, group_size128, desc_actTrue, damp_percent0.01, ) tokenizer AutoTokenizer.from_pretrained(model_id) model AutoGPTQForCausalLM.from_pretrained(model_id, quantize_config) # 校准集从领域数据里抽 256 条长度覆盖典型输入 calib [] with open(calib_data.jsonl) as f: for line in f: calib.append(json.loads(line)) if len(calib) 256: break examples [ tokenizer(t[text], return_tensorspt, max_length2048, truncationTrue) for t in calib ] model.quantize(examples) model.save_quantized(out_dir) tokenizer.save_pretrained(out_dir)量化一个 7B 模型单张 A100 大概跑 20 到 40 分钟取决于校准集大小和序列长度。量化完的模型体积从约 14GB 降到约 4GB显存占用大幅下降。注意校准集的质量直接决定量化后的精度。我试过用通用语料做校准结果在代码任务上掉点明显换成代码和指令混合的校准集后代码通过率基本追平 FP16。校准集一定要贴近你的实际业务分布。2.4 量化后的验证与调优量化完不能直接上线必须做三层验证。第一层是困惑度对比在 WikiText 或者领域语料上算INT4 相比 FP16 的困惑度上升控制在 5% 以内算合格。第二层是任务指标比如数学题准确率、代码通过率、指令遵循率这些才是真正影响用户体验的。第三层是长尾 case 人工抽检量化最容易在长上下文和复杂推理上出问题自动指标不一定能暴露。如果掉点严重有几个调优方向把 group size 从 128 降到 64开启 desc_act换 AWQ 试试或者对敏感层比如第一层和最后一层保持 FP16 不量化。我一般会保留 embedding 层和 lm_head 层为 FP16这两层对输出质量影响大量化收益却很小。3. 投机采样用小模型撬动大模型的解码效率3.1 投机采样的数学原理投机采样能成立靠的是一个很优雅的数学性质如果草稿模型和验证模型采样自同一分布那么经过接受-拒绝校正后的输出分布和直接用大模型采样的分布完全一致。也就是说投机采样是无损的不会改变模型的输出质量只是改变了生成的方式。具体流程是这样的草稿模型先自回归生成 K 个 token记为 x1 到 xK同时记录每个位置的草稿概率 q(xi)。大模型对这 K 个 token 做一次并行前向得到每个位置的真实概率 p(xi)。然后从前往后逐个判断对第 i 个 token以 min(1, p(xi)/q(xi)) 的概率接受它。一旦某个 token 被拒绝就从修正后的分布里重新采样一个 token 作为该位置的输出并丢弃后面所有草稿 token。如果 K 个全部接受就再从大模型采样一个额外的 token。这个机制保证了输出分布严格等于大模型的分布。接受率越高平均每次前向确认的 token 数越多加速比越大。理论上加速比的上限是 K1实际中接受率能到 0.7 到 0.9 就很不错了。3.2 草稿模型的选择与训练草稿模型的选择直接决定接受率。最省事的做法是用同系列的小模型比如用 Qwen2.5-0.5B 给 Qwen2.5-7B 做草稿因为同系列模型的 tokenizer 和训练数据分布接近接受率天然较高。我实测 Qwen 系列同门搭配接受率能到 0.8 左右。如果没有合适的小模型可以自己蒸馏一个。方法是让大模型在领域数据上生成输出然后拿这些输出微调一个小模型让它模仿大模型的输出分布。这个过程叫蒸馏草稿模型效果比直接用通用小模型好很多尤其是垂直领域。蒸馏数据量不用太大几万条高质量样本就够训练成本很低。还有一个进阶玩法是Medusa 式的多头草稿。不单独搞一个草稿模型而是在大模型最后一层加几个额外的预测头每个头预测未来第 2、3、4 个 token。这样草稿和验证共享主干省了草稿模型的前向开销但需要额外训练预测头。EAGLE 方案更进一步用特征层面的自回归来预测接受率更高但实现复杂度也上去了。3.3 参数调优K 值、温度与接受率投机采样最关键的参数是草稿长度 K。K 太小加速有限K 太大草稿模型自己跑 K 步的开销就上来了而且后面几个 token 的接受率会快速衰减。经验值是 K 取 4 到 8具体要看接受率曲线。我一般会先跑一组测试统计不同位置的接受率找到接受率跌破 0.5 的位置把 K 设在那里。温度参数也有影响。温度越高采样越随机草稿和验证的分布差异越大接受率越低。所以高温场景下投机采样的收益会打折扣。如果业务必须用高温可以考虑动态 K温度高时减小 K温度低时增大 K。还有一个容易被忽略的点是批处理下的投机采样。单请求场景下投机采样很香但批量推理时不同请求的接受率不一样有的请求一次接受 8 个有的只接受 1 个导致 batch 内长度不齐GPU 利用率反而下降。vLLM 对这种情况做了专门的调度优化但实际吞吐提升不如单请求明显。所以投机采样更适合低并发、低延迟的在线场景高吞吐场景要谨慎评估。3.4 实操在 vLLM 里开启投机采样vLLM 对投机采样的支持比较完善配置也简单。以 Qwen2.5-7B 搭配 0.5B 草稿模型为例vllm serve Qwen/Qwen2.5-7B-Instruct \ --speculative-model Qwen/Qwen2.5-0.5B-Instruct \ --num-speculative-tokens 5 \ --speculative-draft-tensor-parallel-size 1 \ --tensor-parallel-size 1 \ --gpu-memory-utilization 0.9num-speculative-tokens就是 K 值先设 5 跑一轮看日志里的接受率。vLLM 会输出类似spec_decode_acceptance_rate的指标如果低于 0.6说明草稿模型和主模型不够匹配考虑换草稿或者蒸馏一个。注意草稿模型和主模型的 tokenizer 必须完全一致否则 token 对不齐接受率会崩。同系列模型一般没问题跨系列一定要先验证 tokenizer 的 vocab 是否一致。实测下来Qwen2.5-7B 配 0.5B 草稿K5在代码生成任务上接受率约 0.78端到端延迟降低约 1.8 倍吞吐提升约 1.5 倍。数学推理任务接受率略低约 0.7因为推理步骤的 token 分布更分散。4. PD 分离把预填充和解码拆到最合适的硬件上4.1 为什么预填充和解码要分开要理解 PD 分离先得看清预填充和解码的资源特性差异。预填充阶段要处理整个输入序列假设输入 2048 个 token注意力计算的复杂度是 O(n²)算力吃满属于计算密集型。解码阶段每次只处理 1 个 token注意力只和 KV Cache 做交互计算量很小但要把整个模型的权重读一遍属于访存密集型。如果两者混跑在同一张卡上会出现严重的资源错配。预填充任务来了算力被占满正在解码的请求被迫排队尾延迟飙升解码任务跑着算力大量闲置预填充又进不来。更麻烦的是预填充和解码对 KV Cache 的显存需求也不一样混在一起很难做精细化的显存管理。PD 分离的核心思想就是让专业的卡干专业的事。预填充实例用高算力卡比如算力强但显存带宽一般的卡解码实例用高带宽卡比如 HBM 带宽大的卡两边独立扩缩容。预填充实例处理完输入后把 KV Cache 传给解码实例解码实例只管一个 token 一个 token 地往外吐。4.2 KV Cache 传输PD 分离的最大工程挑战PD 分离听起来美好但落地时最大的拦路虎是KV Cache 的传输。一个 70B 模型输入 2048 tokenKV Cache 大小大概是 2K和V× 层数 × 头数 × 头维度 × 序列长度 × 精度字节数。粗算下来FP16 精度下每 1000 token 的 KV Cache 约 1GB 到 2GB。如果预填充和解码在不同机器上这 1GB 多的数据要通过网络传过去传输时间可能比预填充本身还长。所以 PD 分离的架构设计核心就是怎么把 KV Cache 高效地搬过去。目前主流方案有几种一是用高速互联比如 NVLink 或者高速 RDMA 网络把传输延迟压到毫秒级二是做分层传输先传解码马上要用的部分后面的异步传三是压缩 KV Cache比如量化到 INT8 甚至 INT4传输量直接减半或降到四分之一。我实测过 KV Cache INT8 量化对传输的影响传输时间能减少约 45%而解码质量几乎无损因为 KV Cache 的数值分布相对温和量化误差比权重量化小得多。这个优化在 PD 分离场景下性价比极高。4.3 调度策略什么时候该分离什么时候不该PD 分离不是万能的。它的收益在长输入、短输出的场景下最明显因为预填充占比高分离后预填充可以专心跑算力解码不被拖累。反过来如果输入很短、输出很长预填充占比低分离带来的传输开销可能抵消收益。我一般用预填充解码时间比来判断。如果预填充时间占总时间的 30% 以上PD 分离值得上低于 20%收益有限。这个比例可以通过压测得到输入长度、输出长度、模型大小都会影响。另一个考量是集群规模。PD 分离需要至少两组实例小规模部署比如单机 8 卡拆开反而增加复杂度不如用 chunked prefill 这种轻量方案。chunked prefill 把长输入切成小块和解码任务交替调度也能缓解资源错配实现简单得多。只有到了多机多卡、需要精细化成本控制的规模PD 分离的收益才真正体现出来。4.4 实操用 vLLM 的 disaggregated 模式搭一套vLLM 从 0.6 版本开始支持 PD 分离配置分两端。预填充端vllm serve Qwen/Qwen2.5-7B-Instruct \ --kv-transfer-config {kv_connector:PyNcclConnector,kv_role:kv_producer,kv_rank:0,kv_parallel_size:2} \ --tensor-parallel-size 1 \ --port 8100解码端vllm serve Qwen/Qwen2.5-7B-Instruct \ --kv-transfer-config {kv_connector:PyNcclConnector,kv_role:kv_consumer,kv_rank:1,kv_parallel_size:2} \ --tensor-parallel-size 1 \ --port 8200两端通过 NCCL 做 KV Cache 传输需要保证网络互通。启动后用一个统一的代理层做请求分发预填充端处理完输入后把 KV 传给解码端。注意PD 分离对网络稳定性要求很高NCCL 传输一旦抖动解码端就会卡住。生产环境建议用专用网络并且做好超时重试和降级预案。我遇到过网络抖动导致解码端等待超时的情况后来加了本地缓存兜底才稳住。实测在 2048 输入、256 输出的场景下PD 分离相比混跑尾延迟P99降低约 40%吞吐提升约 25%。输入越长收益越明显。5. 三项技术的组合与常见问题排查5.1 组合使用的顺序与注意事项量化、投机采样、PD 分离可以叠加但叠加顺序有讲究。我的建议是先量化再投机采样最后 PD 分离。原因很简单量化降低显存和带宽压力是后面两项的基础投机采样依赖草稿模型量化后草稿模型也更轻草稿开销更小PD 分离是架构层面的改动放在最后做前面两项的收益已经能通过压测量化出来便于判断 PD 分离是否值得。组合时有个坑要注意量化后的模型和草稿模型的精度要匹配。如果主模型是 INT4草稿模型是 FP16两者的输出分布差异会变大接受率下降。我一般让草稿模型也用相同的量化方案或者干脆草稿模型保持 FP16 但选更小的尺寸用尺寸差异换精度差异。5.2 常见问题速查表问题现象可能原因排查方向解决方法量化后输出重复、胡言乱语group size 过大或校准集不匹配检查困惑度和任务指标减小 group size换领域校准集投机采样接受率低于 0.5草稿模型与主模型分布差异大对比 tokenizer 和训练数据换同系列草稿或蒸馏草稿模型PD 分离后延迟反而升高KV Cache 传输开销过大测量传输时间和预填充时间比开启 KV 量化或改用 chunked prefill批量推理吞吐不升反降投机采样导致 batch 内长度不齐看 GPU 利用率和 batch 完成时间降低 K 值或关闭投机采样量化模型加载报错量化方案与推理框架不兼容检查框架版本和量化格式换框架支持的量化格式如 GPTQ 转 AWQ长上下文质量下降明显KV Cache 量化误差累积对比不同长度下的输出质量KV Cache 保持 FP16只量化权重5.3 我踩过的几个坑第一个坑是量化校准集用了训练集。当时图省事直接拿训练数据做校准结果模型在训练分布上表现很好一到真实用户输入就崩。后来才明白校准集要贴近推理时的输入分布不是训练分布。训练数据往往有固定模板真实输入更杂乱两者分布差异很大。第二个坑是投机采样的 K 值设太大。一开始想着 K 越大加速越多直接设了 10结果草稿模型自己跑 10 步的开销比省下来的还多端到端反而变慢。后来做了接受率曲线发现第 6 个 token 之后接受率就跌破 0.4 了K 设 5 才是最优。第三个坑是PD 分离没做降级预案。有一次网络抖动KV 传输卡住解码端一直等整个服务雪崩。后来加了超时机制传输超时就回退到本地预填充虽然慢一点但服务不挂。生产环境一定要考虑部分失败的情况不能假设所有组件永远正常。5.4 效果验证怎么量化加速收益加速效果不能只看单点指标要建立一套完整的评测体系。我一般从四个维度看首 token 延迟TTFT、每 token 延迟TPOT、吞吐量tokens/s、显存占用。这四个指标在不同技术下的表现不一样量化主要改善显存和 TPOT投机采样主要改善 TPOTPD 分离主要改善 TTFT 和尾延迟。压测的时候要注意固定输入输出长度分布否则不同技术的对比没有意义。我一般用三组典型分布短输入短输出128/128、长输入短输出2048/128、短输入长输出128/2048分别对应问答、摘要、创作三类场景。每组跑 1000 个请求统计 P50、P95、P99 延迟和平均吞吐。还有一点加速技术的收益会随并发变化。低并发下投机采样收益大高并发下量化收益更稳定。所以压测要覆盖不同并发档位找到每种技术的适用区间而不是只看一个数字。6. 一些实际部署中的经验补充量化这块我现在基本固定用 AWQ 做 4bit 服务端部署GPTQ 作为备选。AWQ 的精度保持确实更好尤其是在指令遵循和代码任务上掉点比 GPTQ 小。但 AWQ 对模型结构的适配需要额外注意有些新模型出来 AWQ 支持会滞后这时候 GPTQ 的生态优势就体现出来了。GGUF 我主要用在本地开发和边缘设备服务端不用。投机采样我现在只在低并发在线场景开比如客服机器人、代码补全这种对延迟敏感但 QPS 不高的业务。高并发场景下batch 内长度不齐的问题太严重收益不稳定。如果一定要在高并发下用我会把 K 设小一点比如 3牺牲一点加速换稳定性。PD 分离我建议规模到了再上。单机 8 卡以内chunked prefill 基本够用实现简单运维成本低。到了多机多卡、需要独立扩缩容的时候PD 分离的价值才真正体现。而且 PD 分离对网络要求高如果机房网络条件一般收益可能被传输开销吃掉。最后分享一个判断要不要上某项技术的简单方法先压测看瓶颈在哪。如果显存不够上量化如果解码慢但显存有余上投机采样如果预填充和解码互相干扰上 PD 分离。不要为了用技术而用技术每一项都有它的适用边界。我见过太多团队一上来就全套上结果复杂度爆炸收益却没多少最后还得回退。技术选型永远是先定位瓶颈再对症下药。