Prhub

#29218 [Spec] DFlash: support pure-MLA targets with an fp8 KV cache (Kimi-K2.x-NVFP4)

原始 PR 作者 thanhhao98 合并时间 2026-07-08 10:52 文件变更 3 提交数 7 评论 13 代码增减 +96 / -8

执行摘要

修复 DFlash 在纯 MLA fp8 KV 目标上的两个崩溃

PR body 指出,DFlash 在 pure-MLA 目标(如 Kimi-K2.x-NVFP4)上使用 fp8 KV cache 时,verify 阶段崩溃,服务器无法进入就绪状态。因此需要修复两个崩溃点,以支持这类模型。

该 PR 值得精读,特别是两个设计决策:

1) 通过 dtype 隔离解决 fa4 注意力后端与 fp8 KV cache 的不兼容;
2) 通过初始化时计算的标志位,避免在热点路径中使用 hasattr 检查。这些可复用于其他推测解码场景。

讨论亮点
  • nvpohanh 担心 dtype 覆盖范围:ns 认为无条件将 draft KV cache 设为 bf16 可能破坏未来需要使用 fp8 KV cache 的 draft 后端(如 flashinfer_trtllm)。作者在后续提交中添加了 speculative_draft_attention_backend == "fa4" 条件,将覆盖限制在 fa4 后端。
  • kpham-sgl 要求使用缓存的属性:sgl 要求将下游 forward_batch_generation 中的局部变量 need_mamba_verify_commit 替换为 self._need_mamba_verify_commit,以保持一致性。已处理。
  • kpham-sgl 确认 dtype 不同:sgl 询问目标与 draft 的 kv_cache_dtype 是否不同(fp8 vs bf16),thanhhao98 确认 draft 拥有独立的 KV 池,因此可以不同。

实现拆解

  1. 添加 Mamba verify-commit 守卫dflash_worker_v2.py):在 DFlashWorkerV2.__init__ 中计算 self._need_mamba_verify_commit,检查目标模型的 mambaish_config 是否为 None 以及注意力后端是否提供 update_mamba_state_after_mtp_verify 方法。在 _update_target_mamba_state_after_verify 开头根据该标志提前返回。同时将 forward_batch_generation 中原本的局部 hasattr 检查替换为引用缓存的 self._need_mamba_verify_commit,避免每次检查的开销并确保一致性。

  2. fa4 draft KV cache dtype 解耦model_runner.py):在 configure_kv_cache_dtype 方法末尾添加条件判断:若当前为 draft worker、算法是 DFlash、draft 注意力后端为 fa4、且 kv_cache_dtype 与模型 dtype 不同,则将 kv_cache_dtype 覆盖为 self.dtype(bf16)。fa4 要求 Q 与 K 具有相同的 dtype,无法直接读取目标 fp8 KV cache,因此让 draft 使用独立的 bf16 KV cache 池,目标保持不变。该条件特别限定 fa4,避免影响未来支持 fp8 的 draft 后端。

  3. 新增夜间测试test/registered/quant/test_kimi_k26_nvfp4_dflash.py):注册为 nightly-8-gpu-b200 套件,在 8×B200 tp=8 上启动 Kimi-K2.6-NVFP4 目标与 Kimi-K2.6-DFlash draft,运行 gsm8k 准确率测试(baseline 0.92,200 样本)以及多 batch size 性能测试(bs=1/8/16),并设置 speculative accept length 阈值 2.0。该测试使用 trtllm_mla verify 后端,不依赖 flashinfer 版本。

  4. 日志与清理:添加 fa4 KV cache 覆盖的日志输出,根据 review 反馈移除 AI 生成的注释,并统一使用 self._need_mamba_verify_commit

文件 模块 状态 重要度
test/registered/quant/test_kimi_k26_nvfp4_dflash.py 测试套件 added 6.58
python/sglang/srt/model_executor/model_runner.py 模型运行器 modified 6.56
python/sglang/srt/speculative/dflash_worker_v2.py 推测解码器 modified 6.39

关键符号

configure_kv_cache_dtype DFlashWorkerV2.__init__ _update_target_mamba_state_after_verify forward_batch_generation test_kimi_k26_nvfp4_dflash

关键源码片段

test/registered/quant/test_kimi_k26_nvfp4_dflash.py test-coverage

新增夜间测试,验证 DFlash 在 Kimi-K2.6-NVFP4 上的准确率和性能,确保修复不被回归。

# test/registered/quant/test_kimi_k26_nvfp4_dflash.py
# Kimi-K2.6 NVFP4 (pure-MLA, fp8 KV) with DFlash speculative decoding on 8x B200, tp=8.import unittest
from sglang.test.accuracy_test_runner import AccuracyTestParams
from sglang.test.ci.ci_register import register_cuda_ci
from sglang.test.performance_test_runner import PerformanceTestParams
from sglang.test.run_combined_tests import run_combined_tests
from sglang.test.test_utils import ModelLaunchSettingsregister_cuda_ci(est_time=3600, suite="nightly-8-gpu-b200", nightly=True)MODEL_PATH = "nvidia/Kimi-K2.6-NVFP4"
DRAFT_MODEL_PATH = "nvidia/Kimi-K2.6-DFlash"# trtllm_mla verify only; cuteDSL fold verify depends on the flashinfer version.
EXTRA_ARGS = [
    "--trust-remote-code",
    "--quantization=modelopt_fp4",
    "--moe-runner-backend=flashinfer_trtllm",
    "--fp4-gemm-backend=flashinfer_cutlass",
    "--attention-backend=trtllm_mla",
    "--kv-cache-dtype=fp8_e4m3",
    "--mem-fraction-static=0.85",
    "--max-running-requests=16",
    "--speculative-algorithm=DFLASH",
    f"--speculative-draft-model-path={DRAFT_MODEL_PATH}",
    "--speculative-num-draft-tokens=8",
    "--speculative-draft-attention-backend=fa4",
    "--speculative-draft-model-quantization=unquant",
    "--speculative-draft-window-size=4096",
]
​
​
class TestKimiK26Nvfp4Dflash(unittest.TestCase):
    """Kimi-K2.6 NVFP4 (pure-MLA, fp8 KV) with DFlash speculative decoding on 8x B200 (tp=8)."""
​
    def test_kimi_k26_nvfp4_dflash(self):
        variants = [
            ModelLaunchSettings(
                MODEL_PATH, tp_size=8, extra_args=EXTRA_ARGS, variant="TP8+DFLASH",
            ),
        ]
        run_combined_tests(
            models=variants,
            test_name="Kimi-K2.6-NVFP4 DFlash",
            accuracy_params=AccuracyTestParams(
                dataset="gsm8k", baseline_accuracy=0.92, num_examples=200, api="completion",
            ),
            performance_params=PerformanceTestParams(
                batch_sizes=[1, 8, 16],
                spec_accept_length_threshold=2.0,
                profile_dir="performance_profiles_kimi_k26_nvfp4_dflash",
            ),
        )
​
​
if __name__ == "__main__":
    unittest.main()
python/sglang/srt/model_executor/model_runner.py data-contract

核心修复之一,在配置 KV cache dtype 时为 fa4 draft 独立分配 bf16 KV 池,避免类型不匹配。

# python/sglang/srt/model_executor/model_runner.py ( 片段:configure_kv_cache_dtype)# 在解析完 kv_cache_dtype 之后,添加以下逻辑:# DFLASH: fa4 draft attention 不能读取目标 fp8 KV ( 需要 K.dtype == Q.dtype),
# 因此为 fa4 draft 分配它自己的计算 dtype KV 缓存。fp8 兼容的后端保持目标 dtype。
if (
    self.is_draft_worker
    and self.spec_algorithm.is_dflash()
    and self.server_args.speculative_draft_attention_backend == "fa4"
    and self.kv_cache_dtype != self.dtype
):
    logger.info(
        "DFLASH fa4 draft: 将 KV cache dtype 从 %s 覆盖为 %s "
        "(fa4 需要 K.dtype == Q.dtype; 无法读取目标量化 KV)。",
        self.kv_cache_dtype,
        self.dtype,
    )
    self.kv_cache_dtype = self.dtype
python/sglang/srt/speculative/dflash_worker_v2.py core-logic

核心修复之一,添加 Mamba verify-commit 守卫,防止无 Mamba 的纯 MLA 模型崩溃。

# python/sglang/srt/speculative/dflash_worker_v2.py ( 片段 )# 在 __init__ 中,添加计算 Mamba verify-commit 守卫的自缓存标志:
self._need_mamba_verify_commit = (
    self.model_runner.mambaish_config is not None
    and hasattr(
        self.model_runner.attn_backend, "update_mamba_state_after_mtp_verify"
    )
)# 在 _update_target_mamba_state_after_verify 开头使用该标志快速返回:
def _update_target_mamba_state_after_verify(self, batch, seq_lens_pre_verify, commit_lens):
    if not self._need_mamba_verify_commit:
        return
    # ... 其余逻辑# 在 forward_batch_generation 中,原本的局部变量替换为 self._need_mamba_verify_commit:
seq_lens_pre_verify = (
    batch.seq_lens.clone() if self._need_mamba_verify_commit else None
)
# ...
if self._need_mamba_verify_commit:
    self._update_target_mamba_state_after_verify(...)

评论区精华

draft KV cache dtype 覆盖范围过大 设计

nvpohanh 担心无条件将 draft KV cache dtype 覆盖为 bf16 会破坏未来需要使用 fp8 KV 的 draft 后端(如 flashinfer_trtllm)。

结论:添加条件限制,仅对 fa4 后端执行覆盖(scoped to fa4)。 · 已解决

下游使用缓存的 mamba-commit 标志 style

kpham-sgl 要求将 forward_batch_generation 中的局部变量 need_mamba_verify_commit 替换为 self._need_mamba_verify_commit。

结论:已替换,使用缓存的类属性。 · 已解决

风险与影响

  • model_runner.py 中的 dtype 覆盖:仅在严格条件(is_draft_worker && is_dflash && fa4 && dtype 不匹配)下触发,影响范围有限;但若未来引入其他需要不同 dtype 的 draft 后端却未相应更新条件,可能导致错误,当前风险低。
  • dflash_worker_v2.py 中的守卫:如果 mambaish_config 为 None 但注意力后端意外具有 update_mamba_state_after_mtp_verify 方法,会错误跳过提交,但此类模型不存在,风险小。
  • 测试影响:新增测试仅在 nightly 流水线运行,不影响常规 CI。
  • 用户:使用 DFlash 推测解码并在 B200 上推理 Kimi-K2.x-NVFP4 系列模型的用户现在可以正常运行;其他用户无影响。
  • 系统:draft 和 target 使用独立的 KV cache 池和 dtype,增加少量内存消耗(draft 使用 bf16 而非 fp8),但 draft KV 池一般较小,影响可忽略。
  • 团队:新增 nightly 测试确保回归发现。
后端依赖 dtype 覆盖条件

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论