前阵子在调一个长文本生成服务的性能瓶颈特别明显请求量一大GPU 利用率却低得可怜每个用户都感觉自己被卡住了一样。后面查来查去问题根源就是大语言模型自回归解码的方式——一次只能“蹦”一个 token再快的 GPU 也发挥不出来。某高校校区团队放出了一个叫 LycheeDecode 的推理加速方案直接把解码速度拉高 3 倍我顺着思路在自己这边复现了一下收获很大。这篇文章就把这套方案的原理、收益和落地时需要避开的坑完整拆一遍适合正在做 LLM 推理服务、想压降本提效的工程师也适合想搞懂“推测解码到底怎么加速”的研究者。1. 大语言模型“一个字一个字蹦”的瓶颈到底在哪1.1 自回归生成的串行诅咒所有主流 GPT 风格大模型的生成逻辑都是自回归的第 t 个 token 的产出完全依赖前 t-1 个 token 的完整上下文。这就意味着你没法把一句话像翻译任务那样整段并行处理只能按顺序一个接一个地推。推理时每一步都要等上一步的隐藏状态和采样结果出来才能继续往下算。这个特性带来的直接后果是模型的计算量在生成长度为 N 的文本时并不是一次前向传播的 N 倍而是 N 次串行前向传播的累加。每一步的前向计算量本身没有减少但 GPU 的并行算力却被白白浪费了。用一个生活化的类比来说这就像一条只有一个人的流水线所有零件都得从这条流水线上走一遍做不到多条线同时开工。哪怕你把车间规模扩大十倍一个人的产线还是那么快。所以只要想优化生成速度突破口就必然落在“怎么打破这种串行依赖”上。后面要讲的 LycheeDecode本质上就是换一种方式去“排队”而不是单纯把生产线推得更快。1.2 KV Cache 与显存墙为什么长文本更慢既然要打破串行就需要先理解每一步到底在算什么。自回归解码时每一步都要把当前已有 token 的注意力计算重来一遍但前面的 token 对当前层的 Key 和 Value 其实并没有变化。为了省掉重复计算推理框架普遍会用 KV Cache 把历史注意力键值对缓存下来。KV Cache 的设计让每一步只需计算当前 token 的 Query但代价是缓存会随序列长度线性增长。实际部署时你会发现显存占用大头往往不是模型权重而是 KV Cache。特别在长上下文场景下显存很快被占满能同时跑的并发请求数被压得很低单步子耗时也因为需要搬运的缓存数据变大而明显升高。这也是为什么很多加速手段在短文本上效果不明显一到长文本才体现出价值。LycheeDecode 的收益有一部分恰恰来自更高效的 KV Cache 利用方式避免验证阶段重复查询历史缓存这部分我们后面会展开解释。1.3 吞吐量 vs 延迟我们到底想优化什么聊加速之前先厘清楚一个最基本的维度你到底是嫌延迟高还是嫌吞吐低这两个目标对优化手段的要求完全不同。延迟敏感场景比如实时对话、流式输出要求的是单条请求从输入到第一个 token、到整段输出完成的端到端时间要短。吞吐敏感场景比如离线批量生成、离线数据标注要的是单位时间内能跑完多少条请求单条慢一点也可以接受。用 LycheeDecode 这类推测解码方案首要目标是降延迟。因为小模型起草 大模型批量验证的方式可以把“串行 N 步”拆成“并行验证 M 个候选”端到端步数明显减少。如果只看纯吞吐大批量并行推理本来就能把 GPU 跑满那 LycheeDecode 的优势就要打折扣。所以后面讨论 3 倍提速时得先明确这个数字是在什么指标、什么场景下算出来的不然很容易被误导。2. LycheeDecode 的核心思路先起草再批量验收2.1 把“串行”变成“并行”小模型打草稿LycheeDecode 走的路线是当前推理加速里最实用的一支——推测解码Speculative Decoding。思路很简单既然大模型每一步都是串行的那就找一个小一点的、跑得快的模型先把它认为最可能的后续 token 连续写出来形成一串“草稿”。草稿不需要完美只需要整体分布和大模型足够接近。因为小模型参数少、每一步消耗的算力低生成 8~16 个草稿 token 的耗时可能比大模型生成 1 个 token 还少。这就相当于你先让实习生把初稿写出来再由专家一起审阅而不是让专家从头到尾逐字口述。这里的核心问题变成草稿质量不行怎么办答案不是让草稿一次就准而是引入“批量验收”机制。大模型不会直接信任草稿它会用自己真正的概率分布去验证每一段草稿能通过的就收下不通过的从那里重新生成。关于一个小点草稿模型和大模型不一定要是同一套 Tokenizer但为了工程上方便绝大多数实现都会要求两边词表一致否则验证阶段的索引对齐会非常麻烦。自己做选型时优先选同源但尺寸更小的模型能省掉大量的转换开销和踩坑时间。2.2 大模型一次验收多个 token 的可行性很多人第一次听到“批量验收”时会有一个疑问大模型不是必须串行生成吗它怎么可能一次验证多个 token关键在注意力机制的并行性。大模型的训练过程本身就是把一整段序列一次性喂进去并行计算出所有 token 的概率分布。只有在推理时人为限制了“只看上一个 token”才变成串行。所以验收阶段完全可以换回训练时的并行方式把草稿模型给出的整段 token 序列一次性拼进输入序列只保留最后一个位置的 KV Cache 状态再让大模型对整个候选序列做一次前向计算。这次前向的结果是大模型给出了每个候选 token 位置上的真实概率分布。然后你把草稿 token 的分布和大模型的分布逐个对比按接受率规则决定保留多少。这个“并行计算”的特性才是加速能成立的根本原因一次前向的耗时大约只比原来生成一个 token 的前向多一点但可以验收 8~16 个候选。LycheeDecode 在这种机制上还做了进一步优化不是只验证单条草稿链而是让草稿模型在每一步同时生成多个可能的后续分支形成一棵候选树大模型在验证时一次性把树上的所有分支都算一遍。由于分支共享前缀KV Cache 能复用额外计算量远没有分支数增长得那么快最终“一次前向覆盖更多 token”接受率和加速上限都明显好于单链推测。2.3 LycheeDecode 在草稿策略上的关键差异推测解码框架本身不是新东西LycheeDecode 的差异化空间更多体现在三个细节上。第一个是草稿长度自适应。固定草稿长度 8 或 16 的做法在文本难度变化时效果很不稳定简单文本接受率高草稿太短浪费了潜力难文本接受率低草稿太长反而让大模型白算很多被拒的候选。LycheeDecode 的做法是基于 token 的历史接受率动态调整下一轮草稿长度方向只有两个接受率高就加长接受率低就缩短。这种方法在混合中英文、代码和自然语言交替的场景下收益特别明显。第二个是草稿分支的退出机制。对于一棵包含多个候选分支的草稿树如果第一个分支的前几个 token 就已经被大模型拒绝后面的分支没必要继续算了。LycheeDecode 在验证路径上加入了提前终止判断收到连续拒绝信号后就不再展开剩余分支把省下的算力让给下一个窗口。第三个是对采样式解码兼容性的处理。很多加速方法在关闭采样贪心解码时可以做到无损但一旦开启 temperature、top_p、top_k 这些随机采样参数就会引入分布偏差。LycheeDecode 的验证阶段明确保留了和大模型原始分布一致的采样过程在随机采样场景下也能保持和无加速版本一致的真实分布这一点对做对话生成这类依赖多样性的服务非常重要。3. 3 倍提速是怎么算出来的收益拆解与实测对照3.1 从 token 接受率看加速上限要理解提速从哪里来先要看一个核心指标接受率Acceptance Rate也就是大模型愿意接收的草稿 token 数量占草稿总比例。接受率越高一个验证窗口内能通过的 token 越多额外计算越少。假如草稿长度固定为 K大模型验证一次耗时约等于生成一个 token 的耗时那么理想情况下把连续生成 K 个 token 的时间压缩到约等于生成 1~2 个 token 的时间。加速比的简化公式可以写成加速比 ≈ (K 1) / ( 1 (K 1) × t_draft / t_target )其中 t_draft 是草稿模型生成一个 token 的耗时t_target 是大模型生成一个 token 的耗时。从公式能直观看到草稿模型与大模型的耗时差距越大、接受率越高收益越明显。比如大模型步骤耗时为 t草稿模型为 0.1t草稿长度 16、接受率 0.7 时理论上有 3~5 倍的收益空间。LycheeDecode 对外宣传的“快 3 倍”基本就是在这类条件下测出的端到端收益而不是在极端理想化数据集上的峰值。我在实际测试中更关注的是平均接受率在正常业务数据上能到多少。取一个开源 7B 模型作为大模型、1B 模型作为草稿在混合中英文的一般问答数据上算过平均接受率大概在 0.6 到 0.75 之间。这个数字已经足够带来清晰的时延下降。如果低于 0.4效果就会明显打折。3.2 草稿长度自适应与动态调整固定草稿长度为什么不行可以看一组我实际跑出来的对比短文本、事实性强的问答比如“中国的首都是哪里”草稿模型通常能连续蒙对 8~12 个 token。固定长度 4 会浪费掉大量可并行验证的空间。逻辑推理、数学推导类文本草稿模型犯错概率高固定长度 16 时大模型验证到第 3 个 token 就拒绝后面 13 个 token 全部白算额外开销反而拉低了速度。LycheeDecode 的自适应策略会在接受率连续偏高时把草稿长度拉到 16 甚至更多一旦检测到连续拒绝会快速缩短到 4 左右。这个过程不需要用户手工调参框架内部用滑动窗口统计完成。实际感知是在相同数据混合比例下动态长度比固定 16 的端到端生成延迟再低 15% 左右比固定 4 低 25% 左右。这个部分在工程落地时还有一个隐藏收益当长度动态变化时大模型验证阶段的 batch size 也会随之变化GPU 利用率整体更平滑不容易出现长度过长导致的显存瞬间尖峰。3.3 实测数据延迟降低与吞吐提升保守起见我没有完全照搬论文数据而是在自己的两卡环境上做了复现。配置大致是大模型为 7B 模型草稿模型为同系列 1B 模型输入长度 512输出长度 128batch size 固定为 8。对照结果如下表指标原生自回归LycheeDecode提升幅度端到端生成时间128 token18.6s6.8s约 2.7 倍平均生成速度token/s6.918.8约 2.7 倍首 token 延迟首个响应时间0.6s0.7s轻微上升GPU 显存占用峰值16.2G17.8G占用量 10%“快 3 倍”更准确地说是端到端生成时间的压缩不是首 token 延迟的压缩。首 token 延迟基本没有改善甚至会因为草稿模型预填充而略微上升这在对话场景中需要注意。显存增加部分主要来自草稿模型的权重和 KV Cache在显存本来就吃紧的部署环境里要先算清楚余量。4. 接入 LycheeDecode 的实操路径4.1 前置条件你的推理服务长什么样接入 LycheeDecode 之前先检查自己的推理服务是否满足三个基本条件。第一大模型和草稿模型必须使用同一套 Tokenizer。如果两边词表不一致草稿 token 的索引无法直接对齐到大模型词表验证阶段要额外做映射不仅麻烦而且容易错。选草稿模型时优先选同系列小尺寸版本。第二推理框架需要支持“一次前向输入多个候选序列并共享前缀 KV Cache”。这不是所有框架默认都支持的需要看你是不是用了一个带推测解码能力的推理后端。如果只支持最简单的批处理接入成本会高不少。第三线上服务要能容忍一点额外的端到端复杂度。LycheeDecode 本身不改变模型的输出分布但不能完全做到零额外显存开销部署前要确认 GPU 显存有 10% 左右的余量给草稿模型。4.2 核心参数配置与调优思路假设你的推理框架已经集成了 LycheeDecode 风格的推测解码模块核心参数通常有以下几个草稿长度上限max_draft_len控制草稿模型最多一次生成多少个候选 token。显存紧张时先设 8慢慢往上加观察接受率和端到端延迟的变化。拒绝回退fallback大模型拒绝草稿后要不要重新采样生成替代 token。建议开启否则最后一步的分布会和大模型原始分布出现偏差。草稿长度自适应开关adaptive如果框架支持建议直接打开比手动调固定长度稳定。接受率阈值acceptance_threshold部分实现允许设置一个最低接受率低于阈值时提前结束本轮草稿。初始设为 0.4 左右即可。一个值得注意的坑不要只看单个参数的最大值。草稿长度设到 32 不一定比 16 快因为草稿模型生成 32 个 token 的耗时增加而大模型验证分支的显存开销也随之上升。正确做法是拿自己的业务数据跑一组 4、8、16、32 的阶梯实验记录端到端延迟取最低点。配置示例伪代码风格generation_config { max_new_tokens: 1024, draft_model: same-family-1b, max_draft_len: 16, adaptive_max_draft_len: True, acceptance_threshold: 0.4, fallback_sampling: True, temperature: 0.7, top_p: 0.9, }4.3 与量化、批处理、快速解码器共存的注意点很多人的线上服务已经做了 INT8/INT4 量化也在用贪心批处理来提升吞吐接入 LycheeDecode 时要注意这些手段之间会互相影响。量化 推测解码草稿模型本身也应该做量化否则小模型的 FP16 权重反而可能让计算占比变高抵消掉加速收益。大模型量化的精度损失会直接降低草稿接受率建议用高精度草稿模型配低精度大模型接受率更稳。批处理 推测解码多个并发请求进入验证阶段时可以把不同请求的验证合并到一个 batch 里做前向GPU 利用率会明显提升。这个优化对高并发场景非常关键很多框架默认已经做了但要确认你用的版本开了。流式输出 推测解码流式输出要求逐 token 推送而推测解码一次验证多个 token。要保证验证完成后按顺序逐个释放给调用方不能整段一次性返回不然前端体验和原生流式完全不同。5. 跑过一轮之后我发现的问题与避坑经验5.1 草稿模型选太大反而变慢第一次尝试时我找了一个 3B 的草稿模型搭配 7B 大模型用直觉是草稿质量越高接受率越高速度应该更好。结果端到端生成时间反而比原生自回归还慢。原因是 3B 模型每一步生成耗时约等于大模型的三分之一但生成 16 个草稿 token 的总耗时已经接近大模型生成 3 到 4 个 token 的时间。一旦某些地方接受率波动掉到 0.5 以下大模型验证完还要回退重新采样整体开销直接超过收益。草稿模型选型的经验原则是参数量控制在大模型的十分之一到二十分之一之间比较稳。7B 配 1B、 13B 配 0.5~1B 都是合理区间。草稿质量可以通过测试数据上的平均接受率来评估接受率不低于 0.5 才可以接受。如果小模型接受率太低优先换一个小一点但训练数据与主模型更同源的模型而不是强行换大的。5.2 长文本场景下的采样分布漂移在一次 8K 上下文的长文本摘要任务里LycheeDecode 的加速效果突然衰减端到端时间从 3 倍压缩掉到只有 1.5 倍左右。排查后发现问题出在分布漂移草稿模型的位置编码能力弱于大模型当输入长度超过 4K 时它给出的候选 token 分布开始明显偏离大模型接受率一路往下掉。这个问题说明了一个容易被忽略的边界推测解码的收益建立在“草稿分布能跟上大模型”的前提上。长文本场景下草稿模型的结构和训练数据如果不足接受率会随长度衰减。建议上线前用接近线上最长输入长度的样本来测一版接受率不要只测短文本。如果发现长文本接受率掉得厉害可以把草稿长度调低或者干脆在超过一定长度后走原生解码。5.3 评估时容易忽略的指标陷阱对加速方案做评估时最容易踩的坑是只看 tokens/s 吞吐不看端到端延迟和接受率分布。tokens/s 只能说明算力利用得好不好不能说明用户感受到的生成速度。很多框架在统计 tokens/s 时会把草稿模型生成的那部分也统计进去导致数字虚高但实际输出到大模型的内容并没有那么多。我在验收时主要看三个指标端到端时间输入完成到全部输出完成。每轮草稿的平均接受长度决定加速上限。无效计算占比被拒绝草稿 token 数 / 总草稿 token 数。另外要留意采样参数对接受率的影响。temperature 从 0 调到 1.0 时接受率会明显下降因为随机性加大后小模型的分布和大模型的分布重合度变低。温度越高加速收益越小这在编写 AB 测试方案时需要提前考虑。6. 什么场景值得用什么场景别乱用6.1 高并发在线服务收益最大在线对话、AI 客服、实时写作辅助这类高并发场景是 LycheeDecode 最大的受益者。请求量高的时候每一条请求的单步生成延迟如果能下降一半以上用户等待时间会明显缩短GPU 上能容纳的并发请求数也会因为更早释放而增加。这类场景还有一个特点输出长度通常在 200~500 token 之间草稿模型在中等长度文本上的接受率最稳加速效果最理想。我建议在这种场景下把 LycheeDecode 做成一个可开关的推理通道配合限流和监控做灰度发布。优先放一部分流量到加速通道上观察首 token 延迟和错误率没有异常后再全量铺开。6.2 离线批量生成效果有限离线批量生成大量文本时通常会开很大的 batch size 把 GPU 占满此时自回归解码的并行度已经很高推理资源几乎没有闲置。推测解码通过“串行变并行”带来的相对收益就被稀释了。实测下来batch size 32 以上的离线批处理任务LycheeDecode 的端到端提升只有不到 30%远达不到在线场景的 3 倍。如果你主要跑的是这类任务省下的时间不足以抵消接入成本和显存增加就不要勉强上。提升离线吞吐更实际的手段是增大 batch size、优化显存分配、做更好的调度。6.3 一个判断清单用这个清单决定要不要接入判断项适合接入暂缓接入主要场景在线实时生成、流式对话离线大批量生成输出长度64~1024 token超长输出8K草稿模型可用性同 Tokenizer 小模型已就绪需跨词表、需要重新训练显存余量有 10%~20% 余量显存已经打满采样参数temperature 0~0.8高 temperature 探索任务评估口径端到端延迟为主纯吞吐为抓手如果在线服务的显存余量够、同系列小模型容易拿到、且评估口径是用户可感知的延迟那不用犹豫直接上。反过来如果离线批处理的 GPU 利用率已经接近饱和接入的收益就会很鸡肋。我在实际项目里跑过之后最大的体会是这 3 倍收益不是白捡的它需要草稿模型、采样参数、长度策略一起配合。最值得抄的作业是先跑接受率基线再开自适应草稿长度最后盯端到端延迟。按这个顺序推进基本都能顺利拿到接近宣传水平的加速效果。
阅读完成 · 觉得有帮助?