执行摘要
- 一句话:默认启用 spec v2 推测解码
- 推荐动作:该 PR 值得仔细阅读,特别是
server_args.py 中默认逻辑的设计和测试用例的配套调整。展示了如何将一个实验性特性平稳切换为默认,同时保留回退路径。对于使用推测解码的开发者,应了解新的默认行为和降级条件。推荐关注后续是否有针对 topk>1 支持的 PR。
功能与动机
该 PR 旨在将实验性的 spec v2 重叠调度方案设置为默认行为,简化用户配置并释放推测解码的潜在加速收益。此前 spec v2 需要通过环境变量 SGLANG_ENABLE_SPEC_V2=True 手动启用,此次变更使其成为默认,并自动处理不兼容场景的回退。PR 标题和标签表明其专注于 speculative decoding 和 deepseek 模型。
实现拆解
- 修改服务参数逻辑(
python/sglang/srt/server_args.py):在 _handle_speculative_decoding 方法中,反转默认逻辑。之前默认 spec v1;现在默认启用 spec v2。当 speculative_eagle_topk > 1 或 SGLANG_ENABLE_SPEC_V2 为 False 时自动降级为 spec v1。移除了原先对 topk>1 的硬性 ValueError。同时移除 _handle_model_specific_adjustments 中为 MiMoV2 和 Step3p5 模型强制启用 spec v2 的代码,因为这些模型现在已默认启用。
- 更改环境变量默认值(
python/sglang/srt/environ.py):将 SGLANG_ENABLE_SPEC_V2 的默认值从 False 改为 True。
- 清理测试用例中的显式 env override(多个测试文件):移除那些只在启动服务器时通过
envs.SGLANG_ENABLE_SPEC_V2.override(True) 启用 spec v2 的测试,因为现在默认已启用。受影响文件包括 test_dsa_models_mtp.py、test_qwen3_next_models_mtp.py、test_deepseek_v32_cp_single_node.py、test_deepseek_v32_fp4_mtp_4gpu.py 等。
- 为依赖 spec v1 的测试添加显式禁用(
test/deepep_large.py、test/adaptive_speculative.py):对于不兼容 spec v2 的后端(如 deepgemm 和自适应推测),使用 with envs.SGLANG_ENABLE_SPEC_V2.override(False) 确保测试在 spec v1 下运行。
- 新增 Qwen3.5 FP4 测试(
test/registered/4-gpu-models/test_qwen35_models.py):添加 TestQwen35FP4 和 TestQwen35FP4MTP 测试类,覆盖标准推理和 MTP(多 token 预测)路径,默认使用 spec v2。
关键文件:
python/sglang/srt/server_args.py(模块 服务配置;类别 source;类型 core-logic;符号 _handle_speculative_decoding, _handle_model_specific_adjustments): 核心配置文件,修改了推测解码默认行为逻辑,移除冗余自动启用代码,调整重叠调度条件。
python/sglang/srt/environ.py(模块 环境配置;类别 source;类型 configuration;符号 SGLANG_ENABLE_SPEC_V2): 修改环境变量 SGLANG_ENABLE_SPEC_V2 的默认值,从 False 改为 True,是默认行为切换的关键。
test/registered/4-gpu-models/test_qwen35_models.py(模块 模型测试;类别 test;类型 test-coverage;符号 TestQwen35FP4, TestQwen35FP4MTP, TestQwen35FP4MTPV2, test_gsm8k): 新增 Qwen3.5-397B-A17B-NVFP4 模型的 MTP 测试,验证 spec v2 默认下的推理功能。
test/registered/8-gpu-models/test_dsa_models_mtp.py(模块 模型测试;类别 test;类型 test-coverage): 移除显式的 spec v2 override,测试现在依赖默认值,是清理测试的关键文件。
test/registered/ep/test_deepep_large.py(模块 模型测试;类别 test;类型 test-coverage): 为 deepgemm 后端显式禁用 spec v2,展示不兼容场景的处理。
test/registered/spec/eagle/test_adaptive_speculative.py(模块 模型测试;类别 test;类型 test-coverage): 自适应推测暂时不兼容 spec v2,此处显式禁用,保留 spec v1 测试覆盖。
关键符号:server_args.py:_handle_speculative_decoding, server_args.py:_handle_model_specific_adjustments, test_qwen35_models.py:TestQwen35FP4.test_gsm8k, test_qwen35_models.py:TestQwen35FP4MTP.setUpClass, test_qwen35_models.py:TestQwen35FP4MTP.test_gsm8k
关键源码片段
python/sglang/srt/server_args.py
核心配置文件,修改了推测解码默认行为逻辑,移除冗余自动启用代码,调整重叠调度条件。
# 在 _handle_speculative_decoding 方法中,核心逻辑如下
if self.speculative_algorithm in ("EAGLE", "EAGLE3", "STANDALONE"):
if self.speculative_algorithm == "STANDALONE" and self.enable_dp_attention:
raise ValueError(
"Currently standalone speculative decoding does not support dp attention."
)
if self.max_running_requests is None:
self.max_running_requests = 48
logger.warning(
"Max running requests is reset to 48 for speculative decoding. "
"You can override this by explicitly setting --max-running-requests."
)
spec_v1_reason = None
# topk > 1 时 spec v2 不支持,自动降级
if (
self.speculative_eagle_topk is not None
and self.speculative_eagle_topk > 1
and not self.disable_overlap_schedule
):
self.disable_overlap_schedule = True
spec_v1_reason = "spec v2 currently only supports topk = 1"
# 用户显式关闭了 spec v2 环境变量
elif (
not envs.SGLANG_ENABLE_SPEC_V2.get()
and not self.disable_overlap_schedule
):
self.disable_overlap_schedule = True
spec_v1_reason = "SGLANG_ENABLE_SPEC_V2=False"
if self.disable_overlap_schedule:
logger.warning(
"Spec v1 is used for eagle/eagle3/standalone speculative decoding because %s.",
spec_v1_reason or "overlap schedule is disabled",
)
else:
# 默认启用 spec v2
logger.warning(
"Spec v2 is enabled by default for eagle/eagle3/standalone speculative decoding."
)
test/registered/4-gpu-models/test_qwen35_models.py
新增 Qwen3.5-397B-A17B-NVFP4 模型的 MTP 测试,验证 spec v2 默认下的推理功能。
# TestQwen35FP4MTP 类:测试 spec v2 默认下的 MTP 推理
class TestQwen35FP4MTP(ReasoningTokenUsageMixin, CustomTestCase):
reasoning_parser_name = "qwen3"
@classmethod
def setUpClass(cls):
cls.model = QWEN35_FP4_MODEL # "nvidia/Qwen3.5-397B-A17B-NVFP4"
cls.base_url = DEFAULT_URL_FOR_TEST
cls.init_reasoning_token_verifier()
# 启动服务器时未显式设置 SGLANG_ENABLE_SPEC_V2,依赖默认 True
cls.process = popen_launch_server(
cls.model,
cls.base_url,
timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH,
other_args=[
"--tp-size", "4",
"--speculative-algorithm", "NEXTN",
"--speculative-num-steps", "3",
"--speculative-eagle-topk", "1",
"--speculative-num-draft-tokens", "4",
# ... 其他参数省略
],
)
@classmethod
def tearDownClass(cls):
kill_process_tree(cls.process.pid)
def test_gsm8k(self):
args = SimpleNamespace(
model=self.model,
eval_name="gsm8k",
num_examples=200,
max_tokens=16000,
temperature=0.6,
# ...
)
metrics = run_eval(args)
print(f"{metrics=}")
评论区精华
未发现公开的 review 讨论。该 PR 由作者 Qiaolin-Yu 自行审批合并,无 review 评论。
风险与影响
关联脉络
- PR #22416 [Apple Silicon] [MLX] MLX decode partial overlap scheduling for generation (async eval): 同样涉及重叠调度,但针对 MLX 后端,与本 PR 无直接代码耦合,共享重叠调度概念。
参与讨论