Prhub

#27478 [Spec] Guard async-assert probes against `None` tensor

原始 PR 作者 hnyls2002 合并时间 2026-06-07 13:14 文件变更 1 提交数 1 评论 3 代码增减 +16 / -6

执行摘要

修复 async probe 对 None 张量的崩溃

STANDALONE speculative decoding 的 draft 模型使用 capture_hidden_mode=NULL,导致 logits_output.hidden_states 合法为 None,但 async probe 未处理该情况,在 #26335 添加 probe 后触发崩溃。

建议合并。修复直击根因,代码简洁,有 CI 验证。可关注后续是否需为其他类似场景添加 None 守卫。

讨论亮点

无 review 评论或讨论。

实现拆解

  1. python/sglang/srt/utils/async_probe.py 中导入 Optional 类型。
  2. 将四个 probe 函数的参数类型从 torch.Tensor 改为 Optional[torch.Tensor]
  3. maybe_detect_nanmaybe_detect_inf 中增加 if tensor is None: return 提前返回。
  4. maybe_detect_oobmaybe_detect_page_aligned 中将 indices is None 条件合并到已有的 numel() == 0 短路判断中,避免在 None 上调用 .numel()
  5. 无测试文件变更,但 CI 触发相关测试验证。
文件 模块 状态 重要度
python/sglang/srt/utils/async_probe.py 工具层 modified 6.94

关键符号

maybe_detect_nan maybe_detect_inf maybe_detect_oob maybe_detect_page_aligned

关键源码片段

python/sglang/srt/utils/async_probe.py core-logic

变更唯一文件,包含所有 probe 函数的 `None` 守卫和类型更新。

"""Async invariant probes — fire torch._assert_async without CPU sync.All probes are gated on SGLANG_ENABLE_ASYNC_ASSERT (default off in prod).
When the gate is on, a violation surfaces as an assertion at the next CUDA
sync point instead of as a silent NaN cascade or illegal-address crash.
"""from typing import Optionalimport torchfrom sglang.srt.environ import envs
​
​
def maybe_detect_nan(tensor: Optional[torch.Tensor], msg: str = ""):
    """Async NaN check — no GPU-CPU sync, error surfaces at next sync point."""
    if not envs.SGLANG_ENABLE_ASYNC_ASSERT.get():
        return
    # A None tensor means there is nothing to probe, e.g. hidden_states on
    # capture_hidden_mode=NULL paths (STANDALONE speculative decoding).
    if tensor is None:
        return
    torch._assert_async(~torch.any(torch.isnan(tensor)), f"NaN detected! {msg}")
​
​
def maybe_detect_inf(tensor: Optional[torch.Tensor], msg: str = ""):
    """Async Inf check — fp16 overflow surfaces as Inf before NaN."""
    if not envs.SGLANG_ENABLE_ASYNC_ASSERT.get():
        return
    if tensor is None:
        return
    torch._assert_async(~torch.any(torch.isinf(tensor)), f"Inf detected! {msg}")
​
​
def maybe_detect_oob(indices: Optional[torch.Tensor], low: int, high: int, msg: str):
    """Async OOB check — no GPU-CPU sync, error surfaces at next sync point."""
    if not envs.SGLANG_ENABLE_ASYNC_ASSERT.get():
        return
    if indices is None or indices.numel() == 0:
        return
    torch._assert_async(
        (indices.min() >= low) & (indices.max() < high),
        f"OOB indices not in [{low}, {high}): {msg}",
    )
​
​
def maybe_detect_page_aligned(
    indices: Optional[torch.Tensor], page_size: int, msg: str
):
    """Async page-alignment check on slot ids."""
    if not envs.SGLANG_ENABLE_ASYNC_ASSERT.get():
        return
    if indices is None or indices.numel() == 0 or page_size <= 1:
        return
    torch._assert_async(
        (indices % page_size == 0).all(),
        f"page-misaligned indices (page_size={page_size}): {msg}",
    )

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

低风险。变更仅在 probe 函数入口添加 None 检查,不影响原有逻辑;CI 已通过 STANDALONE 推测解码测试。由于 GIL 和异步执行,None 检查后 tensor 仍可能变为 None?但实际场景中 tensor 在框架内是稳定的,风险可忽略。

影响范围仅限于启用 SGLANG_ENABLE_ASYNC_ASSERT 且使用 STANDALONE 推测解码的用户。修复后,这些用户不会再因 probe 崩溃而中断引擎。对其他用户无影响。

低风险

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论