部署投机解码时最容易踩的一个坑,是拿离线 benchmark 的接受率 × 步长算出理论加速比,然后跟线上 TPOT 一比,发现差了 30% 甚至更多。这事我遇到过两次,两个模型的接受率分别为 0.72 和 0.68,推算应该拿到 2.4 倍左右,实际上线只有 1.6 倍。问题不在推理引擎实现,而在推导加速比的那个公式少算了好几项。
先用性能模型把账摊开
把大模型单次 decode 的耗时归一化为 1,一轮投机的近似耗时是 1 + ρK,其中 ρ 是草稿单步与大模型单步的耗时比,K 是每次草拟的 token 数。这一轮的期望产出是 αK 个 token,α 为接受率。于是单位 token 相对耗时为:
(1 + ρK) / (αK)
加速条件就很直接了:只有 αK > 1 + ρK 才有正收益。以 ρ=0.2、α=0.6 为例,K=1 时相对耗时 2.0,投产就是纯亏;K=4 时刚好 1.0,也就是打平。K=4、α=0.4 时是 1.5,反向减速 50%。
讨论 σ(接受率)之前,先看一件被反复忽略的事:收益完全不来源于接受率本身;实际看的是单位 token 耗时的分母 αK 能不能跑赢验证的固定开销。这让投机解码变成了一个逐利用率的问题,而不是逐接受率的问题。
偏差一:ρ 是个活动靶
到处引用的 ρ ≈ 0.1 来自小模型与大模型参数差 10 倍左右的理想配置,比如 7B 配 72B。但生产环境的部署方式会把 ρ 推高:大模型跑多卡张量并行、小模型单卡跑,或者大模型仍在跑大 batch,小模型也跟着被 batch 拖慢。这时 ρ 变成 0.3 甚至更高,同样的 α 和 K,相对耗时立刻滑过 1.0。
阿里 InfoQ 那篇 RTP-LLM 的文章给了一组更接近真实的数量:小模型单次 decode 7ms,大模型单次 decode 并同时打 5 个 token 的分 18ms。按这组数,每轮 5×7+18=53ms,平均接受 3 个 token 时每 token 17.66ms,加速比 1.02;接受 4 个时才到 1.35。换句话说,接受 3 和接受 4 只差一个 token,收益差了 30 多个百分点,这条曲线在低步长处是抖的。你按验收率估算时填的 ρ,必须是你线上的栈实测出来的那个数。
同一组接受率数字在不同的部署形态下不具可比性。对外汇报加速比时,ρ 和 K 要和 α 写在一起,否则下一个人复现不出你的结果。
偏差二:验证预算不为零,回退也有成本
在性能模型里,验证只花 1 个单位时间。推理引擎的真实实现还得额外扣几笔:
- 回退时 KV Cache 的修正。分歧点之后草稿写入的 KV 项需要清理,缓存指针要按接受前缀重新对齐。这件事在多并发批里尤其不好处理,也是很多线上故障的来源。
- 候选拼接与批内重排。多请求的草稿步被取消后要整理 block,碎片越多这笔账越糟。
- 验证时的额外长序列打分。大模型一次打 K+1 个位置,在 prefill 倾向的负载上 compute 还不完全是白送的,通常会增加几毫秒量级的成本,具体取决于序列长度。
- 流式输出的解耦开销。本想让输出流与下一轮投机错开,避免队头阻塞,但解耦本身就有 token 已经接受、却还没有发下去的窗口。
上面每一项单独看都是小头,加在一起正好填掉常见报告里的 20%–40% 缺口。
偏差三:采样参数让 α 搬家
离线的 0.7–0.8 是在接近贪心的设定下测的。线上如果开着较高的 temperature 或 top_p,接受率会明显往下掉,那份资料也直接写了这一点,确定性解码更利于投机加速。于是一个更棘手的运维问题出现了:同一条推理服务里,写作类请求用高温度、抽取类请求用低温度,两组请求接受率分布完全不同,再拼进同一个 batcher 里,整批速度被低接受率的那组拖住。
按这种模型,K 并不是越大越好。接受率高时加大 K 才划算,接受率低时 K 取 3 就已经在临界点附近了。所以 num_speculative_tokens 更像是 tunning 参数,而不是一个寻优问题。
实际交付前最少做的几项
- 分层观测,不要只看全局 α。 把接受率按任务类型分开:摘要、结构化续写这类模式复用强的请求 α 高,开放式生成多语言请求 α 低,混合后平均值没有指导意义。
- 扫一遍 K 取 1/2/3/5/7。 在真实的请求分布下扫一遍并记录单位 token 相对耗时和 TPOT。别看论文里的理论曲线,它假设 ρ 不变,实际加 K 往往会让草案侧的显存压力上升,影响 ρ。
- 将验证吞吐与链长度分开。 定一个接受率的 go/no-go 阈值,再给合批后预估的填充浪费留一个归零开关。宁可先关掉,让一部分请求走普通 decode。
- 盯住有回退请求的比例。 在总体拒绝率之外,还有一个单独指标:发生回退且回退长度几乎等于 K 的请求占比。这类请求每个都是在为草稿多付的费用,严重时一小部分请求能吃掉相当一部分延迟优惠。
一句话判断标准
不要在代码里写 猜测速度 ≈ (1+αK)/(1+…) 然后把关。用来跟线上产品对齐的口径只有一个:接受率是高是低要结合每 token 的实际耗时来看;在你们自己的流量和引擎配置下,单位 token 相对耗时 < 1.0 才是加速的前提,而那个 1.0 只有装在这套栈上才有意义。
转载请注明出处: 皮哈皮阿
本文的链接地址: https://blog.phpat.com/ai-dev/644.html
微信或手机浏览器扫一扫,随时随地随心阅读与分享
-
上下文工程:从 Prompt 到 Context 的工程化实践
客服 Agent 答错时,团队第一反应是换模型。把那次请求的上下文打印出来才发现,模型看到的是一份过期政策、两份互相矛盾的条款,还有一长串无关日志。上下文工程要解决的,就是这类问题。
2026/10/06
-
RAG 的下一站:Agentic Retrieval
用户问“我们去年买的套餐现在还能退吗”,经典 RAG 检索出一段通用退款政策就结束了。可这个问题至少要拆成订单时间、地区、套餐版本三件事。Agentic Retrieval 要解决的,就是这种“一次检索不够用”的场景。
2026/10/12
-
约束解码让 JSON 不再崩,但它会改坏推理
约束解码让 JSON 解析失败率归零,工程师可以删掉一堆重试和修复代码。但它会挤占模型的推理预算:强制格式在部分任务上带来10%以上的准确率下降。文章梳理 OpenAI、Anthropic、Gemini 和其他自托管引擎的现状,以及 schema 设计、两阶段模式与编译缓存几个实操要点。
2026/10/22
-
Agent 上下文压缩:四层策略与失败代价
把 Claude Code 的四段分层与 Hermes Agent 的双阈值压缩系统并排看重:200K 窗口下的 50%/85%、legacy 与 lean 尾部的实测差池、未处理到的摘要模型窗口溢出,以及工具对配对边界为什么是能不能跑的问题。
2026/10/23
-
推理模型输出被截断后怎么接回去
推理模型遇到输出截断,重试整条请求代价高;续写也有隐藏门槛。从识别边界、提示回灌到 prefill 与成本判断,聊聊工程上怎么做才不算亏。
2026/10/25
-
推理模型的并行思维链采样怎么用才不亏
并行思维链采样的成本不是白花的。结合推理模型测试时计算的几条实证结论,梳理best-of-N、束搜索、自洽性投票和自我修订在什么场景下划算、什么场景下只是在烧钱。
2026/10/26
京公网安备11011402053654 
@muffin:链接已更新,分类图像功能...
AI网址导航模版图标库更换指南
作者大大,图标库邀请链接失效了,麻烦更新...
AI网址导航模版图标库更换指南
太好看了,快点更新!
友情链接
@戴墨镜的刘备:哈喽,路过点赞。
vue.js组件之手写签名板vue-signature-simple
太好看了,快点更新!太棒了!👍真的很赞!
vue.js组件之手写签名板vue-signature-simple
你写得非常清晰明了,让我很容易理解你的观...
Emlog插件RSS订阅器发布