Prhub

#35918 [DeepSeek V4] Add W4A4 MegaMoE server flag

原始 PR 作者 Fridge003 合并时间 2026-08-22 09:44 文件变更 15 提交数 2 评论 4 代码增减 +147 / -87

执行摘要

新增 W4A4 MegaMoE 统一 server flag,替代两个 SGLang 环境变量

PR body 明确指出:DeepSeek V4 W4A4 MegaMoE 目前要求用户手动设置两个 SGLang 特有的环境变量(SGLANG_OPT_DEEPGEMM_MEGA_MOE_USE_FP4_ACTSSGLANG_OPT_DEEPGEMM_MEGA_MOE_USE_MXF4_KIND),需要暴露为单一 server 参数并用 DeepGEMM 原生环境变量配置。其深层动机是消除两层配置割裂:DG_USE_* 是 DeepGEMM 的原生开关,SGLang 不应让用户同时面对 SGLang 抽象变量与底层厂商变量;同时这也是 SRT 同期“环境变量 → CLI flag”迁移方向的一部分(与 #35905-#35910 配置重构系列同频)。

值得精读。这是一个典型的“配置入口收敛”PR,样本价值在于三处:一是 handler 抽取到 arg_groups 与同期 config bags 重构的协同方式;二是“运行时环境变量转发 → 启动期 flag 注入”的端到端迁移路径(含 mega_moe.py 运行时读取点的同步收敛);三是文档数据契约(_playground.jsx 的 derive/apply、三个模型 snippet、模板)与代码变更的强联动。对计划新增或收敛 server flag 的开发者有直接参考价值,无需精读 kernel 实现。

讨论亮点

两个 review 评论均为作者 Fridge003 的合入前自审:

  1. flag 命名精确化:在 .claude/skills/cookbook-add-model/templates/config.jsx.tmpl 的 diff 上要求 “Please rename this flag to --enable-w4a4-mxfp4-megamoe”。结论:已采纳,全仓库(server_args.py、三个模型 snippet、Playground、模板、测试)统一使用新名。mxfp4 精确描述了该路径的量化格式(E2M1 FP4 激活 + MXF4 mainloop),与 SRT 已有的 flashinfer_mxfp4_moe_precision 命名风格一致。
  2. handler 归属重构:在 server_args.py 上要求 “Please move _handle_w4a4_megamoe_env and _handle_moe_runner_backend_alias to a newly created mega_moe_hook.py under arg_groups”。结论:已采纳,新增 arg_groups/mega_moe_hook.py_run_resolution_pipeline 中改为调用 handle_mega_moe(self)。这与 #35906 引入的 arg_groups 声明式处理模式(overrides.pyspeculative_hook.py)一致。

实现拆解

  1. 新增钩子文件 python/sglang/srt/arg_groups/mega_moe_hook.py:将原先内联在 ServerArgs 类中的 handle_moe_runner_backend_alias 迁移出来,并新增 handle_w4a4_mxfp4_megamoe_env 与统一入口 handle_mega_moe。前者负责把 --moe-runner-backend megamoe 归一化为 moe_a2a_backend = megamoe;后者在 flag 启用时直接执行 os.environ["DG_USE_FP4_ACTS"] = "1"os.environ["DG_USE_MXF4_KIND"] = "1"。抽取的动因是保持 _run_resolution_pipeline 的 dispatcher 风格。
  2. server_args.py 接入新 flag:新增字段 enable_w4a4_mxfp4_megamoe(类型 A[bool, ...],归入 NS("exec.moe"),默认 False),并在 _run_resolution_pipeline 顶部(_resolved_overrides = [] 之后、dummy-model 边界之前)改为调用 handle_mega_moe(self),同时删除类内原 _handle_moe_runner_backend_alias 方法。提前到 dummy 边界之前是为了让所有进程(包括 dummy 模型路径)在 fork 前就完成环境变量注入。
  3. mega_moe.py 移除运行时转发层:删除 _apply_mega_moe_dg_env 函数与 _MEGA_MOE_DG_ENV_APPLIED 全局标记;_get_mega_moe_symm_buffer 不再调用转发函数;_run_mega_routeduse_fp4_acts 由读取 envs.SGLANG_...USE_FP4_ACTS 改为 os.getenv("DG_USE_FP4_ACTS") == "1",直接消费 DeepGEMM 原生变量。
  4. environ.py 完成 deprecation:从 Envs 类中删除两个 EnvBool 字段(不再有运行时读取),并在 _DEPRECATED_ENVS 中新增两条 warning-only 条目,告警文案提示改用 --enable-w4a4-mxfp4-megamoeSGLANG_OPT_DEEPGEMM_MEGA_MOE_NUM_MAX_TOKENS_PER_RANK 保留为环境变量(数值调优类入口未迁移)。
  5. 文档、模板与测试联动:三个模型 snippet(deepseek-v4.jsxkimi-k3.jsxqwen3.8.jsx)的 w4a4 选项从 env 数组改为 flags: ["--enable-w4a4-mxfp4-megamoe"]_playground.jsxderiveFromBase 改从 flag 推导 mmQuantapply 增加 quant flag 的 strip/insert 逻辑;.claude/skills/cookbook-add-model/templates/config.jsx.tmpl 模板同步,docs/scripts/check_cookbook_configs.mjs 新增校验;B200 与 CP 两个 E2E 测试的 launch 命令改用新 flag;test_server_args.pytest_environ.py 新增回归测试。
文件 模块 状态 重要度
python/sglang/srt/arg_groups/mega_moe_hook.py 配置钩子 added 8.02
python/sglang/srt/server_args.py 服务参数 modified 6.61
python/sglang/srt/layers/moe/mega_moe.py 专家路由 modified 6.59
python/sglang/srt/environ.py 环境变量 modified 5.49
docs/src/snippets/_playground.jsx 交互组件 modified 6.18
test/registered/unit/server_args/test_server_args.py 参数测试 modified 5.28
test/registered/unit/test_environ.py 环境测试 modified 4.8
.claude/skills/cookbook-add-model/templates/config.jsx.tmpl 文档模板 modified 3.34

关键符号

handle_mega_moe handle_moe_runner_backend_alias handle_w4a4_mxfp4_megamoe_env _apply_mega_moe_dg_env _run_resolution_pipeline

关键源码片段

python/sglang/srt/arg_groups/mega_moe_hook.py core-logic

新增的 Mega-MoE 配置钩子文件,集中承载 runner backend 别名归一化与 W4A4 环境变量注入,是本次配置迁移的核心入口。

# python/sglang/srt/arg_groups/mega_moe_hook.py
# 新增的 Mega-MoE 配置钩子:把原先内联在 ServerArgs 类里的两个 handler
# 抽取出来,保持 _run_resolution_pipeline 的 dispatcher 风格单一职责。from __future__ import annotationsimport logging
import os
from typing import TYPE_CHECKINGif TYPE_CHECKING:
    from sglang.srt.server_args import ServerArgslogger = logging.getLogger(__name__)
​
​
def handle_mega_moe(server_args: ServerArgs) -> None:
    # 统一入口:先归一化 runner backend 别名,再按需注入 DeepGEMM 原生变量
    handle_moe_runner_backend_alias(server_args)
    handle_w4a4_mxfp4_megamoe_env(server_args)
​
​
def handle_moe_runner_backend_alias(server_args: ServerArgs) -> None:
    # --moe-runner-backend megamoe 是 --moe-a2a-backend megamoe 的别名;
    # 归一化后后续逻辑只需读取 moe_a2a_backend 一个字段
    if server_args.moe_runner_backend != "megamoe":
        return
​
    if server_args.moe_a2a_backend not in ("none", "megamoe"):
        logger.warning(
            "--moe-runner-backend megamoe is an alias for "
            "--moe-a2a-backend megamoe; overriding "
            "--moe-a2a-backend %s.",
            server_args.moe_a2a_backend,
        )
    server_args.moe_runner_backend = "auto"
    server_args.moe_a2a_backend = "megamoe"
​
​
def handle_w4a4_mxfp4_megamoe_env(server_args: ServerArgs) -> None:
    # 唯一入口:flag 启用时把 DeepGEMM 原生开关写入进程环境,
    # 后续 fork 出的各 scheduler 进程都会继承这两个变量
    if not server_args.enable_w4a4_mxfp4_megamoe:
        return
​
    os.environ["DG_USE_FP4_ACTS"] = "1"
    os.environ["DG_USE_MXF4_KIND"] = "1"
python/sglang/srt/layers/moe/mega_moe.py core-logic

删除 `_apply_mega_moe_dg_env` 转发层与 `_MEGA_MOE_DG_ENV_APPLIED` 全局标记,`use_fp4_acts` 改为直接读取 DeepGEMM 原生变量,是运行时行为收敛的关键。

# python/sglang/srt/layers/moe/mega_moe.py(关键分支节选)
# 旧实现里 use_fp4_acts 由 SGLANG_OPT_DEEPGEMM_MEGA_MOE_USE_FP4_ACTS 读取,
# 再经 _apply_mega_moe_dg_env() 转发成 DG_USE_FP4_ACTS;本 PR 删除转发层,
# 直接以 DeepGEMM 原生变量为准——该变量唯一的写入入口是
# arg_groups/mega_moe_hook.py 的 handle_w4a4_mxfp4_megamoe_env。def _get_mega_moe_symm_buffer(
    group,
    num_experts: int,
    num_max_tokens_per_rank: int,
    num_topk: int,
    hidden: int,
    intermediate_hidden: int,
) -> SymmBuffer:
    # 移除了 _apply_mega_moe_dg_env() 调用:环境变量已在 ServerArgs
    # 解析期写入进程环境,这里不再需要惰性转发
    import deep_gemm
​
    key = (
        id(group),
        num_max_tokens_per_rank,
        num_experts,
        num_topk,
        hidden,
        intermediate_hidden,
    )
    buf = _MEGA_MOE_SYMM_BUFFER.get(key)
    if buf is None:
        buf = deep_gemm.get_symm_buffer_for_mega_moe(
            group,
            num_experts,
            num_max_tokens_per_rank,
            num_topk,
            hidden,
            intermediate_hidden,
            use_fp8_dispatch=True,
            activation="swiglu",
        )
        _MEGA_MOE_SYMM_BUFFER[key] = buf
    return buf# 在 _run_mega_routed 内部:
use_fp4_acts = os.getenv("DG_USE_FP4_ACTS") == "1"
if use_fp4_acts:
    # FP4 路径走 DeepGEMM 的 mega_moe_pre_dispatch,处理 E2M1 packing 变体;
    # jit 实现只发射 FP8
    deep_gemm.mega_moe_pre_dispatch(
        hidden_states,
        topk_ids_in,
        topk_weights_in,
        buf.x,
        buf.x_sf,
        buf.topk_idx,
        buf.topk_weights,
        num_tokens=num_tokens,
        group_size=32,
        use_fp4_acts=True,
    )
else:
    # FP8 路径走 sglang 内置的 mega_moe_pre_dispatch(jit 实现)
    mega_moe_pre_dispatch(
        hidden_states,
        topk_ids_in,
        topk_weights_in,
        buf.x,
        buf.x_sf,
        buf.topk_idx,
        buf.topk_weights,
        quant_group_size=32,
    )
python/sglang/srt/environ.py core-logic

从 `Envs` 中删除两个旧变量定义并在 `_DEPRECATED_ENVS` 中登记 warning-only 条目,决定旧配置的兼容行为。

# python/sglang/srt/environ.py(_DEPRECATED_ENVS 节选)
# 两个旧变量已从 Envs 类中移除(不再有运行时读取),只保留 warning-only
# deprecation 条目:用户仍设置旧变量时得到告警,并被引导改用新 server flag。
_DEPRECATED_ENVS = {
    # ... 其他条目 ...
    "SGLANG_OPT_DEEPGEMM_MEGA_MOE_USE_FP4_ACTS": _DeprecatedEnv(
        note="Please use '--enable-w4a4-mxfp4-megamoe' instead."
    ),
    "SGLANG_OPT_DEEPGEMM_MEGA_MOE_USE_MXF4_KIND": _DeprecatedEnv(
        note="Please use '--enable-w4a4-mxfp4-megamoe' instead."
    ),
    # ... 其他条目 ...
}
​
​
def _handle_deprecated_envs():
    # 对每个旧变量执行 deprecation 处理:仅告警、不转发值,
    # 同时把遗留的 SGL_ 前缀重写为 SGLANG_
    for old_name, deprecation in _DEPRECATED_ENVS.items():
        deprecation.apply(old_name)
​
    for key, value in list(os.environ.items()):
        if key.startswith("SGL_") and key not in _DEPRECATED_ENVS:
            new_key = key.replace("SGL_", "SGLANG_", 1)
            warnings.warn(
                f"Environment variable {key} is deprecated, please use {new_key}"
            )
            os.environ[new_key] = value

评论区精华

flag 命名从 --enable-w4a4-megamoe 改为 --enable-w4a4-mxfp4-megamoe 设计

作者在 cookbook 模板 diff 上自审评论:“Please rename this flag to `--enable-w4a4-mxfp4-megamoe`”,要求命名精确表达 MXFP4 量化格式。

结论:已采纳;server_args.py、三个模型 snippet、Playground、模板与测试全量统一使用新名,与 SRT 既有 `flashinfer_mxfp4_moe_precision` 命名风格对齐。 · 已解决

Mega-MoE handler 抽取到独立 hook 文件 设计

作者在 server_args.py 上自审评论:“Please move `_handle_w4a4_megamoe_env` and `_handle_moe_runner_backend_alias` to a newly created `mega_moe_hook.py` under arg_groups”,避免 resolution pipeline 继续膨胀。

结论:已采纳;新增 arg_groups/mega_moe_hook.py,pipeline 顶部改为调用 handle_mega_moe(self),类内旧方法删除。 · 已解决

风险与影响

  1. 旧环境变量静默失效:两个旧的 SGLANG_OPT_DEEPGEMM_MEGA_MOE_* 变量仅保留 warning 不转发,若用户仍只依赖旧变量,W4A4 路径不会开启。这是有意为之,但属于行为变化,需要靠告警文案引导。
  2. os.environ 直接覆盖而非 setdefault:旧转发逻辑用 setdefault(外部显式 DG_USE_* 优先),新逻辑在 flag 启用时无条件覆盖为 1test_enable_w4a4_mxfp4_megamoe_sets_deepgemm_env 已断言覆盖行为,说明是有意设计,但外部用户若同时设置 DG_USE_FP4_ACTS=0 会被忽略。
  3. 多进程环境继承依赖 fork 时序:环境变量注入发生在 ServerArgs 解析期,依赖所有 worker 在 resolution 之后 fork。PR 已在 GB300 实测四个 scheduler 进程均收到变量,但未来若引入更早 fork 的进程模型需重新验证。
  4. 文档数据契约联动面广:三个模型 snippet + Playground + cookbook 模板同时变更 w4a4 选项的 flags/env 契约,check_cookbook_configs.mjs 虽新增校验,但任何一侧遗漏都会导致 Playground 展示与实际启动命令不一致。

用户侧:DeepSeek V4 / Kimi-K3 / Qwen3.8 的 W4A4 用户启动命令从“导出两个 SGLang 环境变量”简化为“加一个 --enable-w4a4-mxfp4-megamoe flag”,cookbook 与 Playground 同步更新,降低配置门槛。系统侧:配置注入时机提前到解析期,kernel 运行时不再读取 SGLang 抽象 env,mega_moe.pyenviron.py 的状态面收敛;_run_resolution_pipeline 的 dispatcher 入口增加一个 hook 调用,对配置重构系列是正向演进。团队侧:提供了一个可复制的“env → CLI flag”迁移范式(钩子文件 + deprecation + 文档契约 + 双测试),后续同类迁移可直接照搬。

旧环境变量仅告警不生效 os.environ 直接覆盖非 setdefault 多进程继承依赖 fork 时序 文档数据契约联动面广

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论