资讯动态

大模型推理提速300%:推测解码原理与生产落地指南

发布时间:2026/10/14 23:53:43 来源:尧图企业网站定制
只要部署过大模型推理服务的人一说起“慢”这个字八成都有点条件反射。用户那边发来一句话服务端吭哧半天才吐出第一个字后面虽然流畅些也跟老式打字机似的一个token一个token地往外蹦。我在某数据业务项目里维护过一个十几B参数规模的对话模型第一批功能上线不到一周业务方的反馈就很直接这聊天体验不行一句话平均要等两三秒才出来。后来我花了一段时间把推测解码Speculative Decoding搬上生产环境端到端吞吐提了两倍多长输出场景下甚至接近三倍——也就是标题里说的那个300%。这篇文章就把这套方案的原理和落地过程展开聊一聊重点是哪些环节容易踩坑、为什么有的机器上提速不明显、以及怎么一步步调到理想的加速比。1. 为什么大模型推理这么慢自回归解码的宿命1.1 大模型天生只能一个token一个token地生成想理解推测解码先得搞清楚常规的大模型推理为什么慢。很多人都知道大模型是“逐字生成”的但这个逐字到底有多严格可能没细想过。Transformer架构的大模型本质上是一个自回归模型autoregressive model。它的意思是模型在生成第n个token时必须把前n-1个token全部作为输入然后预测下一个token是什么生成完第n个token之后再把它拼到输入里去预测第n1个token。整个过程中没有任何“并行吐字”的可能因为后面的每一个字都严格依赖前面已经生成的字。拿“今天天气真好”这句话来说模型的实际生成路径是输入“开始符”预测出“今”输入“开始符、今”预测出“天”输入“开始符、今天”预测出“天”第二个天输入“开始符、今天天”预测出“气”……一路串行下去一个7B参数的模型在消费级GPU上大概每秒能生成20到40个token哪怕放在更高级的GPU上单用户场景通常也就是一秒钟几十个token。用户感知就是“卡”尤其流式输出的时候如果每秒只有十几个token体验几乎没法看。人读中文大约每秒5到8个字但大模型输出的字速往往比这个还慢用户等得不耐烦是非常正常的。1.2 真正的瓶颈不是算力而是显存带宽很多人一开始以为大模型慢是因为“计算量太大”这个印象需要纠正。在生成阶段decode阶段大模型真正的时间开销大头不是计算而是“从显存里读权重”。拿7B模型举例。70亿参数按FP16精度算每个参数占2字节那么全部权重大约是14GB。生成一个token理论上需要的计算量大概是2 × 参数量 × token数也就是大约14 GFLOPs。这个计算量对GPU来说真的不算什么一张普通的GPU轻松可以跑出几TFLOPs甚至几十TFLOPs的算力。真正的问题在于你每生成一个token都需要把这14GB权重从显存里完整读一遍算完得到一个小结果然后再读下一遍。显存的读取带宽是几百GB/s到几TB/s14GB读一次就需要几十毫秒。于是整个生成过程的时间几乎全耗在“搬运权重”上了计算单元反而是闲着的。业界管这种状态叫“访存受限”memory-bound。打个比方仓库里有一堆14吨的货你的任务是一次只挑出一件很小的小零件一个token的计算量但每次都必须把整堆14吨货先从仓库搬出来看完再搬回去。装货卸货的时间远远大于挑零件的时间效率当然低。想通这一点就明白为什么单纯堆算力解决不了单用户延迟问题。你必须想办法减少“每生成一个token就读取一次全部权重”的次数这才是加速的关键。1.3 提高吞吐和降低单条延迟是两码事顺带说一个很容易混淆的概念吞吐throughput和单用户延迟latency不是一回事。很多团队喜欢用增大batch size的方式提高吞吐同一时间处理更多请求。这个做法是有效的GPU利用率上去了整体吞吐数据也好看。但单个用户拿到第一个token的时间、以及后续每个token之间的间隔ITLinter-token latency并不会因为并发变高而变快。反而批太大时单个请求在GPU队列里等的时间更长用户感知可能更差。推测解码解决的是另一个层面的问题它让“多生成几个token”在一次模型前向里完成直接降低每个token的平均成本和延迟这才是用户能真正感知到的“快”。2. 推测解码的核心思想小模型打草稿大模型做终审2.1 一个很朴素的灵感既然目标模型每生成一个token都要读一遍权重那我们能不能让它“一次多验证几个token”常规自回归做不到因为你不知道接下来的token是什么。但如果先找一个小模型快速猜一串token出来再让大模型一次性“审批”这串token呢这就是推测解码Speculative Decoding的核心思路用一个又小又快的草稿模型draft model先生成一段候选序列比如6个token然后目标模型把这整个序列一次性读进去进行一次前向同时算出每个位置的真实预测分布再逐个判断“猜得对不对”。猜对的部分直接采用相当于一次前向白拿了几个token猜错的地方用目标模型给出的token顶上然后丢弃后面所有候选重新开启下一轮循环。这个思路其实在早年有一些类似概念但真正在LLM上落地并引起广泛关注是这两年的事。它最优雅的地方在于它不是“近似加速”而是严格的数学等价——最终输出的概率分布和直接用目标模型逐token生成是完全一致的。2.2 接受/拒绝机制为什么输出分布不变这一步很多人容易看迷糊但它恰恰是推测解码的“立身之本”。假设目标模型是q草稿模型是p。草稿模型按自己的分布p生成了候选token t1、t2、t3……并且在每个位置也保留了p(token)的具体数值。目标模型做一次前向在同样的位置得到了自己的分布q。接下来不是简单地问“草稿猜的是不是q里概率最大的那个”而是按照“拒绝采样”rejection sampling的规则逐位置判断对第i个token计算接受概率 r min(1, q(t_i)/p(t_i))以r的概率接受草稿token t_i让它作为最终生成的token然后继续检查下一个位置如果被拒绝则不能直接取q中概率最大的token而是需要从修正后的分布 q(x) ∝ max(0, q(x) - p(x)) 中采一个token作为当前输出然后这之后的候选token全部作废重新让草稿模型从当前位置继续猜这个规则看起来有点绕但它的意义非常明确经过这样处理后的最终生成分布和直接用目标模型q做原生采样在数学上是严格一致的。当年我第一次看到这个证明时也觉得神奇。其实可以反过来理解拒绝采样的本质就是“当草稿分布和目标分布在某个token上不一致时用目标分布修正结果”。草稿分布低估了目标分布中概率较高的token这些token会被更大概率接受草稿分布高估了的token则会被拒绝并重新采样。两边一抵消最终分布还是q。如果用的是greedy解码每次取argmax规则更简单目标模型在每个位置上算出的最高概率token如果正好等于草稿token就接受否则就停下来把目标模型认为最可能的token作为真正输出。所以完全不用担心“草稿模型猜错了导致生成质量变差”——因为每一步都有目标模型这个“终审裁判”错的token会被拦下来最终质量不打折扣。2.3 为什么目标模型一次能同时验证多个token这里需要展开一个关键点为什么目标模型把草稿序列一次性吃进去就能同时得到所有位置的输出分布核心在于Transformer的结构。训练阶段模型本来就是一整个序列一起输入的并在每个位置都输出下一个token的预测这种训练方式叫teacher forcing。推理时如果你已经有一个完整的候选序列同样可以直接把它作为输入送进去走一次前向得到序列中每个位置上的logits——这和训练时看到完整句子的结构是一样的。一次前向里虽然输入序列变长了但真正省钱的地方在于权重只需要从显存读一次而不是七次。注意力部分虽然要多计算候选位置对应的注意力分数但这些额外计算相比权重访存的开销要小得多。对比“用目标模型逐token生成6个token要跑6次前向”一次前向验证6个token的开销大概只有1次前向的1.x倍这就实现了加速。可以把目标模型想象成一位有经验的审核员。逐token生成模式好比每提交一两个字就审一次审完一个才能提交下一个推测解码模式下小模型先交上六七个字审核员一次性批下来大部分字直接通过只有不合格的才返工重写。审核员的工作次数从七次变成一次速度自然上去了。2.4 加速比由什么决定理论上推测解码能带来的加速比主要取决于三个变量草稿模型的接受率acceptance rate猜得越准加速越明显草稿长度number of speculative tokens一次猜多少个越长潜在收益越大但太长时后半段命中率会严重下降反而浪费计算草稿模型的生成成本草稿模型本身的耗时越小越好如果草稿模型跑太慢就把前面的收益全吃光了理想情况下如果目标模型一次前向耗时T草稿模型生成γ个token耗时t平均接受率为α那么生成一个目标token的平均耗时大约就是 (T t) / (γ·α 修正项)。接受率越高、草稿越便宜吞吐越高。这也是为什么实测中2-3倍加速很常见但很少能到10倍——收益被接受率和草稿成本卡住了。3. 生产环境落地从选模型到调参的完整实操3.1 草稿模型怎么选词表一致是铁律选草稿模型我踩的第一个坑就是词表。草稿模型需要和目标模型共享同一个tokenizer/词表vocabulary否则它猜出的token ID在目标模型那边根本对不上。你也许可以做一层ID映射但映射之后概率分布大概率也对不上接受率会惨不忍睹。如果你用的是同一个基座的模型家族通常可以直接用同词表的小参数版本作为草稿模型。比如目标模型是某个系列里7B规模的版本那么同系列的0.5B到2B版本往往就是很好的草稿模型。我在某内部项目里用的就是某个基座模型套件里的小参数版词表天然一致部署成本最低。如果没有同词表小模型有两个选择自己用目标模型的checkpoint在大量通用语料上蒸馏一个小草稿模型强制让它训练成“最懂目标模型的小模型”在推理框架中开启无草稿模型的方案比如用历史生成的文本作为候选有的框架支持N-gram投机但效果通常不如专门的小模型还有一个容易被忽略的点草稿模型虽然小但它在批量场景下也占显存。如果目标模型已经把显存占得比较满草稿模型可能会挤占KV Cache的空间反而降低整体吞吐。第4章我会专门说这个矛盾。3.2 部署配置实操以主流的开源推理框架为例目前主流开源推理框架里vLLM和TensorRT-LLM都已支持推测解码。我这里以vLLM的实践为主因为它在社区用得最广、配置也最直观但思路是通用的。假设你已经有目标模型路径比如 /models/xxx-7B和草稿模型/models/xxx-1B启用推测解码只需要在启动引擎时多做两件事指定草稿模型draft_modelxxx-1B指定投机长度num_speculative_tokens6这个具体数值需要实测调优一个我实际用过的启动命令大概长这样具体版本可能有差异仅供参考python -m vllm.entrypoints.openai.api_server \ --model /models/xxx-7B \ --draft_model /models/xxx-1B \ --num_speculative_tokens 6 \ --max-model-len 8192 \ --gpu-memory-utilization 0.85 \ --swap-space 0注意如果草稿模型和目标模型词表一致部分推理框架可以在显存上做优化两套模型的embedding表可以复用显著降低显存压力。如果不一致可能会退回做ID映射性能会有折损。另外vLLM还支持“动态投机长度”配置不同版本的叫法可能不同思路是根据当前接受的token个数动态调整下一次草稿长度。比如这次接受了5个下一次就试试猜8个这次只接受了1个就缩减到3个。这样能避免固定长度在后半段盲目浪费计算。我自己的经验是动态方案在混合长短输出的业务场景里通常比固定6-8个token更稳定。3.3 实测数据与调参心得我在某内部测试环境里做过一组对比目标是7B模型草稿是同基座1B模型硬件是单张80GB显存的GPU场景是单请求流式输出800token原生自回归解码大约27 token/s平均生成延迟约30s固定投机长度6大约61 token/s吞吐提升约2.26倍固定投机长度12大约69 token/s但接受率从0.62掉到0.38部分请求延迟抖动变大动态投机长度平均70 token/sP99延迟比固定长度更好这里有个反直觉的点投机长度不是越长越好。换成8到12个token时模型后半段命中率下降多余的前向计算变成了浪费甚至可能比6个token更慢。所以“先试6、再试8、最后看P99”是我建议的调参路径。temperature的影响也很关键。我把temperature从默认的0.7调高到1.0接受率直接降了约15个百分点整体加速比从2.2降到1.7左右反过来用greedy解码temperature0时有些测试集上接受率能到0.7以上加速比更接近3倍。原因不难理解温度越低分布越集中小草稿模型和大模型的概率分布更容易“想到一块儿去”温度越高采样随机性变大小模型就很难猜中目标模型的随机选择。所以在生产里如果你的业务允许低温度比如客服问答、结构化抽取推测解码的收益会非常明显如果必须用高温度做创意写作收益会打折扣但通常也还有1.5倍以上。还要留意停止条件不要因为推测解码就放松对stop strings和EOS token的判断。目标模型验证时如果发现草稿序列里包含了EOS必须立刻停止整段生成而不是继续往后猜。这块处理不好会出现“用户都看到结束符号了还在生成”的怪异表现。主流框架会在内部处理但如果你自己是手写流水线一定要单独加分支。4. 常见问题与排查技巧实录4.1 加速比达不到预期先查接受率这是我在生产中最常被问到的问题“明明开了推测解码为什么线上没快多少”第一步永远是看草稿token接受率。如果服务端能导出token级别的日志或者推理框架提供了统计接口把接受率拉出来接受率在0.5到0.6以上通常收益明显低于0.3可能草稿模型选得不对或者投机长度过长接受率正常但加速不明显可能是草稿模型本身延迟太高或者和目标模型共享GPU导致互相抢占我调试过一个案例接受率有0.55但端到端只快了1.2倍。最后定位到问题草稿模型在CPU/GPU之间的数据传输开销太大草稿每次生成要500ms。解决办法是换了一块能容纳下草稿模型的GPU把草稿生成也放到GPU上延迟从500ms降到40ms整体加速立刻来到2倍以上。这个经验说明草稿模型“快”不只是参数量小执行延迟本身也要压下来。4.2 显存不够草稿模型和KV Cache打架怎么办前面说过草稿模型也占显存而KV Cache又要占显存两者天然冲突。实际生产中尤其当目标模型规模比较大比如70B量级批次又比较高时显存非常紧张。这时候有几个出路把草稿模型压缩到极致。选更小的参数版本甚至直接量化如INT8、INT4。草稿模型的精度对接受率影响很小因为它只负责猜候选真正的输出校准靠目标模型兜底所以量化草稿模型是一个几乎无损的操作降低max-model-len或gpu-memory-utilization给草稿模型留出空间如果服务是多副本部署可以让部分副本开推测解码、部分副本不开按请求类型路由——长输出请求走加速副本短请求走原生副本显存利用率最合理我自己的偏好是优先量化草稿模型。比如1B模型量化后大约0.5到0.8GB显存通常在可控范围内。4.3 输出很短时没有收益别硬上推测解码的收益来自“一次前向级联多个token”。如果你的典型请求只输出几个token比如标题生成、短分类草稿模型还没猜够候选目标模型就要停了加速比很难体现甚至可能更慢。这种情况下我的建议是不要硬上推测解码。你可以用规则或者小模型先把第一批候选做出来或者干脆保持原生解码只有当输出长度较长比如几十到几百token的业务场景才值得引入推测解码。判断标准很粗暴输出长度大于5到10倍的投机长度收益才有可能显现。4.4 大批次在线推理还会遇到什么坑最后说一个容易被忽略的点使用动态批处理continuous batching的框架时一个batch里可能有多个请求都在被推测解码加速这时候调度器需要让它们执行“验证步骤”时对齐、互相等待处理不好会拖慢整体吞吐。在vLLM中这类问题框架基本已经处理了但如果你是基于TensorRT-LLM或自研推理引擎做二次开发需要特别注意投机解码和batching逻辑之间的交互。实测中如果batch size特别大比如并发了几十个请求推测解码的加速倍数通常会比单请求场景低一些因为GPU已经基本吃饱了草稿模型的额外计算和验证计算开始“抢资源”。但即便如此只要接受率正常总吞吐依然会优于不使用推测解码。这其实引出一个结论推测解码在“单用户延迟敏感”场景如对话、流式输出里的价值比在“纯吞吐场景”里更高。因为纯吞吐场景你本就可以用大batch吃满GPU但延迟这事batch拉不起来只能靠算法层面的思路来降。4.5 常见问题速查表现象可能原因排查/解决方向开了推测解码反而更慢草稿模型延迟太高 / 投机长度过大缩短投机长度量化草稿模型把草稿模型放GPU输出质量波动不规范的拒绝采样实现 / 未处理EOS检查是否用无偏接受规则检查EOS与停止条件加速比随时间不稳定请求长度分布变化 / 批大小波动使用动态投机长度按请求类型分流显存OOM草稿模型占用显存量化草稿模型降低缓存比例高temperature时加速比骤降采样随机性太高命中率低降低temperature改用greedy接受更低的加速词表不一致导致乱输出草稿模型tokenizer不同强制使用同词表草稿模型做好ID映射并验证5. 一些经验体会最后说点个人的体会。推测解码是我近两年在生产里用过“性价比”最高的推理优化手段之一——它不需要重训目标模型不改变输出分布接入框架后改改配置就能跑。但它确实不是一个银弹它对场景、模型、参数都敏感。我的建议是先从接受率入手用数据说话不要迷信固定数值草稿模型能小则小能量化则量化优先在长输出、延迟敏感的业务里用短输出任务就别勉强了。我在几个项目里反复调了几轮之后现在反而更喜欢先跑一个简单的离线benchmark用业务里最典型的500条样本量出原生解码和推测解码的P50/P99延迟、接受率曲线再决定上不上、怎么上。这套流程下来基本不会再被“为什么没提速”这类问题打回票。希望这些经验能让你少踩几个坑。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑