SGLang 集成 DSpark 推测解码:置信度驱动的可变长度验证

LMSYS:Blog(Chatbot Arena 团队)·2026-07-06 00:00·49天前·SGLang Team
AI 导读

SGLang 团队将 DSpark 推测解码算法集成到开源推理引擎中。该算法采用半自回归块起草器一次生成一组 token,并利用置信度头与顺序温度缩放(STS)为每个请求动态分配可变验证长度,从而在高负载下裁剪无效验证成本。SGLang 支持密集模型(如 Qwen3)和稀疏模型(如 DeepSeek-V4),通过全 CUDA 图处理不规则的每请求验证长度。提供三种验证模式:static(全长)、compact(生产路径)和 cap-accept(接受上限测量)。还引入了零开销调度、基于离线成本表的在线调度器、融合 Triton 核等优化。在 H200 上使用 DeepSeek-V4-Flash 的测试中,DSpark 在整个并发扫描范围内比 MTP 和非推测基线实现了更优的吞吐量-延迟权衡。

LMSYS:Blog(Chatbot Arena 团队)
精选
63AI 编辑部评分,满分 100

SGLang 集成 DSpark 推测解码:置信度驱动的可变长度验证

2026-07-06 00:00· 49天前· SGLang Team
AI 导读

SGLang 团队将 DSpark 推测解码算法集成到开源推理引擎中。该算法采用半自回归块起草器一次生成一组 token,并利用置信度头与顺序温度缩放(STS)为每个请求动态分配可变验证长度,从而在高负载下裁剪无效验证成本。SGLang 支持密集模型(如 Qwen3)和稀疏模型(如 DeepSeek-V4),通过全 CUDA 图处理不规则的每请求验证长度。提供三种验证模式:static(全长)、compact(生产路径)和 cap-accept(接受上限测量)。还引入了零开销调度、基于离线成本表的在线调度器、融合 Triton 核等优化。在 H200 上使用 DeepSeek-V4-Flash 的测试中,DSpark 在整个并发扫描范围内比 MTP 和非推测基线实现了更优的吞吐量-延迟权衡。

推荐理由

DSpark 这版推测解码的工程落地比论文本身更有看头——SGLang 用 ragged CUDA Graph 和动态调度把 trimm 掉的计算按字节级回收,383 tok/s 的单请求速度对部署方是即时可用的性能增益。

正文 · AI 翻译

推测解码通过增加计算量来减少解码步数,但这种权衡会随着负载增加而恶化:在批次大小为 B、推测 token 数为 K 的情况下,目标模型每步需验证 B * K 个 token,超过某个临界点后,其成本将超过收益。DSpark 从两端入手——采用半自回归块级草稿模型(每次草稿前向生成整个块,因此接受率保持较高水平),以及基于草稿模型自身置信度的、每个请求可变的验证长度,从而停止验证那些工作负载不太可能接受的 token。该算法及其收益均来自 DSpark 论文。

SGLang 现已支持在稠密模型和稀疏模型(例如 Qwen3 和 DeepSeek-V4)上运行 DSpark。本文介绍的是集成工作(sgl-project/sglang#30261)。我们在一个开源推理引擎上复现了论文中收益的形态——即单用户加速比,以及验证预算随负载增加而缩减的趋势——并描述了将这种调度策略转化为实际运行时间所需的工程实现:在参差不齐、按请求独立验证的场景下使用完整的 CUDA 图(因此修剪后的批次实际重放的是一个更小的图,而非填充后的图);一种具有重叠感知能力的推测路径,可将调度器隐藏在前向计算之后;一个成本表分析器,使调度器能够在线调整每个请求的验证预算;以及用于观测接受率上限的可观测性,否则修剪操作会掩盖这一上限。由于硬件、推理引擎和流量模式均与论文不同,我们复现的是其机制和曲线趋势,而非精确到个位数的数值;下文所有“更快”的表述,均是与我们自己的对照组(除推测配置外完全相同)对比得出的。

相较于 MTP 和无推测解码的加速效果

图 1. 总吞吐量(y 轴)与单用户解码速度(x 轴)的关系;每条曲线对应从批次大小 1 到 256 的并发度扫描,每种方案一条曲线。越靠右上方表示性能越好。

在整个并发度扫描范围内,DSpark 实现了最佳的吞吐量/延迟权衡,在图 1 示例中明显优于 MTP 和无推测解码的基线。三种方案均使用 DeepSeek-V4-Flash 在 H200 上运行,采用 DP-attention 分布在四个 rank 上,除推测配置外完全相同——包括无推测解码基线、MTP(EAGLE 风格基线,取 1-1-2 和 3-1-4 配置中每个批次大小的最佳结果)以及 DSpark。

在 SGLang 中采用 DSpark

DSpark 算法源自该论文,其实现位于三个草稿侧组件中:

  • 块草稿器——一条密集线(例如 Qwen3)和一条稀疏线(例如 DeepSeek-V4);一次前向传播生成一个 gamma token 块,通过一个轻量级顺序头(马尔可夫或 RNN)使每一步都依赖前一个 token,因此该块是半自回归的。
  • 置信度头——为每个草稿 token 评分,评估其通过验证的概率;整个块的乘积即为该块的存活概率。
  • 顺序温度缩放(STS)——对这些分数进行校准,使得存活率能够真实反映调度器所预算的接受率。

围绕这些核心组件,SGLang 增加了服务支持层:

  • 置信度调度器——在每一步将每个块的存活概率转换为每个请求的验证预算。
  • 单请求非对齐验证——在一个批次内,每个请求的验证长度可变(静态/紧凑/上限接受)。
  • 完整 CUDA 图——针对非对齐、可变长度的验证过程进行捕获。
  • 可观测性——修剪操作下的接受上限及其他指标。
  • 增量 SPS 成本表——一个离线分析的步时模型,由调度器在线读取。
  • 数据并行注意力——与其他并行维度一同支持。
  • 零开销调度——集成到 SGLang 的重叠调度器中,几乎无需为 DSpark 添加特殊处理逻辑。
  • 性能优化——融合的 Triton 内核以及分片的块草稿器矩阵乘法。

验证模式

三种验证模式是本文后续讨论的核心轴。静态模式在每一步验证整个草稿块(基线方案)。紧凑模式仅验证调度器选定的每个请求窗口——即生产路径。上限接受模式验证整个块,但仅提交到该窗口为止:输出结果与紧凑模式相同,同时能揭示完整验证本应接受的内容——这是我们衡量修剪操作下接受上限的方式。

在完整 CUDA 图下的非对齐验证

按请求划分的窗口无法适配固定形状的 CUDA 图:在一个批次中,一个请求验证两个 token,另一个请求验证六个 token,此时不存在单一的查询长度,而将所有请求填充至完整块宽度只会把裁剪部分重新填充回来。因此,我们保持批次的不规整性,并根据总 token 数量对图进行键控——将变长请求前端打包到一个紧凑缓冲区中,并向上取整到最近的已捕获层级。当预算缩减时,打包后的总 token 数会降至更小的层级,DSpark 会重放一个真正更轻量的图(更少的注意力与 MLP 行,而非掩码后的全宽度前向传播);在 DP 注意力机制下,各 rank 共享同一个层级(即任一 rank 所需的最大层级),并同步降级。

打包后的缓冲区是一种 cu_seqlens 风格的变长输入,因此紧凑验证复用了后端已有的注意力核——在 DeepSeek-V4 上,使用的是模型自身的稀疏 MLA 路径(flash_mla),无需新核;每个受支持的后端只需在图重放时根据打包布局重建其变长元数据。

图 2. 将每个请求验证长度可变的批次适配到已捕获的 CUDA 图中。固定形状的图会将每个请求填充至完整块宽度(N x W);不规整路径则将已调度的 token 前端打包,仅将总 token 数向上取整至最近的已捕获层级,从而为相同的已接受 token 计算远更少的填充单元。

可观测性

裁剪机制限制了上限:紧凑模式仅验证一个块的前几个位置——即调度器的窗口——因此,完整块验证在该步骤本应接受多少个 token 这一信息永远无法被观测到;而缺少这一信息,就无法区分良好的裁剪与有损的裁剪。上限接受运行可以恢复这一信息:它验证完整块,但仅提交至窗口范围,因此它提交的内容与紧凑模式完全相同,同时暴露了上限。我们还提供每个请求的置信度与校准指标(例如 ECE),用于事后分析。

估算裁剪下的上限

一种专为生产运行或其他不希望额外伴随运行的场景设计的块接受估计器,可直接在紧凑型运行内部恢复估计的截断上限。该估计器利用未来步骤中目标 token 及其对数概率,并假设修剪轨迹与未修剪轨迹中锚定 token 的属性相似性,从而计算反事实尾部的估计区间。

动态调度与固定调度的初步对比

置信度调度器是首个基础版本,我们将其视为一个端到端机制可行的证明,而非高度调优的结果。我们在两个接受率不同的示例工作负载上,将紧凑型(每步 SPS-argmax 预算)与无修剪型(通过相同不规则路径运行的静态全块调度)进行了对比。

图 3. 紧凑型(动态修剪)与无修剪型(全块)对比,在 DP4 下批次从 1 到 256,基于两个接受率不同的示例。越靠右上方表示效果越好。

动态预算的优势主要体现在大批次场景。在批次大小为 1 时,目标验证不会因 token 增多而显著变慢,因此修剪节省的时间很少,两种方案表现相当。随着并发度增加、吞吐量开始趋于平稳,修剪缩短了步骤时间,紧凑型方案开始领先。在接受率较低的示例上,差距更大且更早出现——接受率越低意味着需要修剪的尾部越长,这与成本模型的预测完全一致。

每个面板都是一个干净的紧凑型与无修剪型 A/B 对比(面板内设置完全相同),但两个示例并非严格意义上的单变量对比:除了接受率之外,它们在设置上也有细微差异(提示词格式和每轮运行次数),因此我们观察的是跨面板的趋势,而非面板间的绝对数值。

这些预算的有效性也取决于其背后的成本表。我们当前的 SPS(及校准)拟合是初步近似,可能尚未完全考虑步骤成本随上下文长度变化的情况——因此调度器最终确定的精确工作点很可能还有改进空间,我们在此展示的是机制本身,而非调优后的具体数值。

混合流量下的逐请求差异化处理

同质化扫描掩盖了置信度调度的真正意义。如果批次中的两个请求中一个的可预测性远高于另一个,它们就不应该获得相同的验证窗口。混合流量才是这一机制真正发挥作用的地方。

图4. 按工作负载划分的预算(左)与每步验证长度分布(右)。

举例来说,我们按接受难度混合了三种工作负载:gsm8k(高)、arena-hard(中)和poetry(低)。窗口随难度收缩——分别为5.24、3.78、2.91个token——而对上限(即区块未经修剪时能接受的长度)的利用率仍然很高(0.88–0.97)。调度器是在为每个请求单独确定大小,而不是应用一个批次平均值。右侧面板逐步展示了这一过程:约55%的gsm8k步骤填满了完整的六个窗口,而约80%的poetry步骤只使用了三个或更少的窗口。

性能优化与零开销调度(ZOS)

两种工程手段将调度转化为实际时间:降低每一步的成本,以及将调度器隐藏在前向传播之后。两者结合,在DeepSeek-V4-Pro上,TP=8,B300,接受长度约5、批次大小为1时,达到了383.7 tok/s的速度。

我们将一系列微操作集群重写为融合的Triton内核,例如紧凑型散射、SWA页面索引、验证长度top-k调度以及不规则窗口打包。区块草稿器的采样路径被整合到融合内核中,其矩阵乘法也进行了分片。在一个示例性能分析中,目标验证之外的操作耗时减少了1.7毫秒,而验证本身耗时7.3毫秒。

DSpark直接嵌入SGLang的零开销(重叠)调度器,几乎无需特殊处理,仅增加了本文提出的两步回溯置信度中继。这其中很少有DSpark特有的管道。SGLang的spec-v2运行时已经实现了在独立流上,将下一步的调度与当前前向传播重叠执行;DSpark作为一等公民工作节点加入:前向传播输出以异步future形式返回,跨迭代顺序由运行时的设备端屏障控制,而设备端页表则意味着无需每步进行主机同步。置信度中继使用相同的通道,读取两步之前的数据。解码循环随后运行,不再有每步气泡——比关闭调度器时紧凑约1.5倍。

图 5. 批大小为 1 时的解码,重叠调度器关闭(上)与开启(下)。开启后,run_batch 迭代之间或一个步骤内的块草稿生成与目标验证阶段之间不再有空泡。

对成本表进行性能分析

图 6. 加性成本模型——原始数据与拟合结果(a)及吞吐量(b)——以及预测步时与实测步时(c)。

我们将调度器对步时 T(bs, K) 的估计——其中 K 为批次额外的验证 token 数——表示为一个加性模型:T(bs, K) = bias + alpha(bs) + theta(M),M = bs + K,其中 alpha(bs) 是请求扩展下限(草稿通过加上部分注意力),不受裁剪影响;theta(M) 是目标的验证 token 成本,也是裁剪能回收的唯一项。调度器的 argmax 在预期接受 token 数与实际边际成本之间进行权衡,因此裁剪空间仅在 theta 较大时才会显现。图 6(c) 验证了该模型对实时服务器的预测效果。

后续计划

DSpark 目前已集成在 SGLang 中;我们在 sgl-project/sglang#30344 跟踪路线图。后续计划包括:

  • 成本模型与调度——一个更强、日益在线/自适应的成本模型,以及对动态调度器的进一步改进。
  • 模型覆盖——更多稠密和稀疏模型。
  • 并行化——更广泛地覆盖各种并行模式和服务拓扑。
  • 可观测性——将块接受率估计器和跨检查点的置信度校准等指标投入生产化。
  • 鲁棒性——强化全 CUDA 图路径,并进行更广泛的压力/回归测试。

感谢 DSpark 的作者们,以及感谢深度求索提供的算法和模型。

附录:复现

以下所有命令均在预构建镜像(docker pull lmsysorg/sglang:dev-dspark)内运行,或从 sgl-project/sglang#30261 的源代码构建,锁定在提交 692c5f7d。

图 1、图 3 和图 6——前沿服务器(DeepSeek-V4-Flash,H200,DP4)。启动 DSpark 分支:

SGLANG_ENABLE_METRICS_DEVICE_TIMER=1 \
python3 -m sglang.launch_server \
  --model-path deepseek-ai/DeepSeek-V4-Flash-DSpark \
  --speculative-algorithm DSPARK \
  --tp 4 --dp-size 4 --enable-dp-attention --enable-dp-lm-head \
  --moe-a2a-backend none --moe-runner-backend flashinfer_mxfp4 --disable-flashinfer-autotune \
  --swa-full-tokens-ratio 0.1 --chunked-prefill-size 1024 \
  --mem-fraction-static 0.8 --cuda-graph-max-bs 192 --max-running-requests 1024 \
  --disable-radix-cache --trust-remote-code --host 0.0.0.0 --port 30000

其中 `--disable-radix-cache` 是为了避免基准测试脚本命中缓存。其他分支仅改变推测配置:非推测模式(non-spec)去掉 `--speculative-*` 参数,加载 `--model-path deepseek-ai/DeepSeek-V4-Flash`;MTP 使用相同目标模型,搭配 `--speculative-algorithm EAGLE --speculative-num-steps {1,3} --speculative-eagle-topk 1 --speculative-num-draft-tokens {2,4}`(取每批次大小中两者的最佳值);DSpark 紧凑模式或静态模式设置 `SGLANG_RAGGED_VERIFY_MODE=compact|static`;使用 SPS 表执行紧凑模式时,添加 `--speculative-dspark-sps-table-path sps_table.json`;图 3 的 no-trim 分支为 `SGLANG_RAGGED_VERIFY_MODE=compact` 且不加载 SPS 表(即全窗口下的不规则路径)。使用固定提示词驱动任意分支,并在不同批次大小下进行扫描:

python3 -m sglang.benchmark.one_batch_server \
  --model None --base-url http://127.0.0.1:30000 \
  --batch-size 1 8 16 32 64 96 128 160 192 256 --output-len 1024 --temperature 0.7 \
  --fixed-prompt-file frontier_prompt.txt --fixed-prompt-apply-chat-template --show-report

固定提示词在此处(frontier_prompt.txt),由 16 道拼接的 GSM8K 问题组成,以确保生成内容为真实文本。用户可基于自身数据测试,因为不同数据集的推测解码接受长度各不相同。

图 6 的成本表来自性能分析运行:以 `SGLANG_DSPARK_ENABLE_SPS_RECORD=1 SGLANG_SIMULATE_ACC_LEN=1.0` 启动紧凑模式,然后通过 `python3 -m sglang.benchmark.dspark_sps_profiler all` 拟合加性模型(在输入长度为 512 时,扫描批次大小 × 验证比例网格)。

图 4——混合流量。服务器配置与图 1 相同,`--mem-fraction-static 0.7`,块大小为 6;通过 `SGLANG_RAGGED_VERIFY_MODE` 运行所有三种模式(静态/紧凑/接受上限),并驱动包含 gsm8k + arena-hard + poetry 的混合请求集,以非流式完成时间吞吐量进行测量。

图 5——零开销(DeepSeek-V4-Pro,B300,TP8)。

SGLANG_RAGGED_VERIFY_MODE=compact SGLANG_DSV4_FP4_EXPERTS=1 SGLANG_TORCH_PROFILER_DIR=./trace \
python3 -m sglang.launch_server \
  --model-path deepseek-ai/DeepSeek-V4-Pro-DSpark --speculative-algorithm DSPARK \
  --tp 8 --moe-runner-backend flashinfer_mxfp4 --disable-flashinfer-autotune \
  --mem-fraction-static 0.82 --chunked-prefill-size 4096 --cuda-graph-max-bs 4 \
  --trust-remote-code --host 127.0.0.1 --port 30000

捕获批次大小为 1 的解码轨迹,然后读取仅 GPU 的通道:

python3 -m sglang.benchmark.one_batch_server \
  --model None --base-url http://127.0.0.1:30000 \
  --batch-size 1 --input-len 256 --output-len 256 \
  --profile --profile-activities GPU --profile-steps 20

来源:LMSYS:Blog(Chatbot Arena 团队)· lmsys.org