Prhub

#34587 [Docs] Add Qwen3.8 cookbook

原始 PR 作者 zijiexia 合并时间 2026-08-12 23:07 文件变更 9 提交数 1 评论 0 代码增减 +1305 / -6

执行摘要

Qwen3.8 cookbook:7 平台 18 配方部署指南

PR body 明确指出:Qwen3.8-2.4T-A95B 此前没有任何 cookbook 页面,而它是 Qwen 目前最大的开源权重模型(2.4T 总参 / 95B 激活,92 层由 23 组『3 × (Gated DeltaNet → MoE) → 1 × (Gated Attention → MoE)』构成),部署方式与已有页面覆盖的稠密注意力模型完全不同:三分之二的层是线性注意力,因此限制并发的不是 KV cache 而是 GDN 循环状态池;且 2.4T 参数下 FP8 无法装入页面中任何平台的单节点。

值得精读。重点看两处设计:一是 qwen3.8.jsx 中 DSpark 选项的 disable 条件与 _handle_dsparkpython/sglang/srt/arg_groups/speculative_hook.py)硬约束的一一对应,这是『文档约束与运行时代码同源』的好范例;二是 _playground.jsxmodeMeta 的『先剥离同名 flag 头再追加』配合 applyAllDeltas 每次 render 重新 seed 的幂等机制,值得在同类配置生成引擎中复用。若后续要跟进,可为 _playground.jsx 补一个针对 PD 角色 flag 合并的单元测试,并关注 GB300 配方上游 flag 落地后移除标注。

讨论亮点

该 PR 无独立 review 评论(两位 reviewer JustinTong0323、wisclmy0611 均直接 APPROVED),以下要点来自作者在 PR body『Notes for reviewers』中主动澄清的设计决策:

  • 端口占位符是真实缺陷而非风格问题:作者说明模板原先硬编码 30000/30001,而引擎 decode 服务在 30100,字面端口会导致 router 打向 decode 进程从未监听的端口;修复为 {{PREFILL_PORT}} / {{DECODE_PORT}} / {{ROUTER_PORT}} 并同步更新作者参考文档。
  • DSpark 是模型专属策略 ID 而非第四个档位:作者论证 DSpark 是另一套投机解码器,不是吞吐/延迟曲线上的操作点,因此作为独立 strategy 芯片出现,并只在 pp == 1(DP-Attention 下还需 --enable-dp-lm-head 与内置 TP MoE)的组合下提供。
  • GB300 部分配方依赖未发布 flag:作者明确 Balanced 与 High Throughput 档需要 DeepEP v2 wheel(2.1.0+01dc3aa),--moe-a2a-backend deepep_v2 上游尚不存在;Low Latency 与其他平台配方只发 upstream 已有 flag。
  • --kv-cache-dtype fp8_e4m3 为逐格携带而非页级默认:B300 NVFP4 与 GB300 BF16 刻意以模型精度服务 KV,避免一刀切默认值误导。

实现拆解

  1. 新增 Qwen3.8 模型配置数据docs/src/snippets/configs/Qwen/qwen3.8.jsx(+939)是整页的数据源,定义 7 平台 × 4 量化(BF16/FP8/NVFP4/MXFP4)× 4 策略(Low Latency/Balanced/High Throughput/DSpark)的部署矩阵、各平台 Docker 镜像、多节点 IB/NCCL 绑定提示、Playground 各卡片能力(Attention 并行、MoE backend 与 WideEP、推理/工具调用解析器、投机解码、PD 分发、层级 KV cache);qwen3.8-benchmarks.jsx(+23)为 18 个 recipe 提供空基准桩,页面显示 pending。

  2. 扩展 Playground PD Disagg 引擎docs/src/snippets/_playground.jsx(+18)允许配置中 modes[] 条目声明角色专属的 flags / env(如 prefill 的 --load-balance-method、decode 的轮询间隔),在角色分支内通过新增符号 modeMeta 查找当前角色,先按 flag 头剥离 base cell 同名 flag 再追加,env 按值去重;由于 applyAllDeltas 每次 render 从 baseFlags 重新 seed,对现有 8 个配置是 no-op。

  3. 新增 cookbook 页面并完成注册docs/cookbook/autoregressive/Qwen/Qwen3.8.mdx(+315)以中文叙述模型架构、配置要点(GDN 状态槽比例、NEXTN 并发默认值、SM90 与 SM100 线性注意力后端差异)并嵌入 Deployment/Playground 组件;docs/docs.json 在 Qwen 分组中注册页面;docs/cookbook/autoregressive/intro.mdx 的 Qwen 卡片链接指向 Qwen3.8;Qwen3.6.mdx 移除 tag: NEW 标记。

  4. 修复 cookbook 脚手架模板端口硬编码.claude/skills/cookbook-add-model/templates/config.jsx.tmpl 原先硬编码 router 的 prefill/decode 端口为 30000/30001,但引擎 decode 实际监听 30100,改为 {{PREFILL_PORT}} / {{DECODE_PORT}} / {{ROUTER_PORT}} 占位符,并同步更新 authoring-reference.md 说明。

  5. 校验与配套:无模型/内核代码改动,无对应测试文件;作者声明 mint validatemint broken-links 均通过;benchmark 以 stub 形式发布,避免未经验证的性能数字上页面。

文件 模块 状态 重要度
docs/src/snippets/configs/Qwen/qwen3.8.jsx 部署配置 added 7.52
docs/src/snippets/_playground.jsx 配置引擎 modified 6.5
docs/cookbook/autoregressive/Qwen/Qwen3.8.mdx 文档页面 added 5.62
docs/src/snippets/configs/Qwen/qwen3.8-benchmarks.jsx 基准数据 added 5.28
.claude/skills/cookbook-add-model/templates/config.jsx.tmpl 脚手架模板 modified 3.6
docs/docs.json 站点配置 modified 2.36
docs/cookbook/autoregressive/intro.mdx 文档页面 modified 2.31
docs/cookbook/autoregressive/Qwen/Qwen3.6.mdx 文档页面 modified 2.17
.claude/skills/cookbook-add-model/references/authoring-reference.md 脚手架文档 modified 1.93

关键符号

modeMeta

关键源码片段

docs/src/snippets/configs/Qwen/qwen3.8.jsx core-logic

整页部署配置的核心数据源(+939 行),定义 7 平台 × 4 量化 × 4 策略的 18 个 launch recipe,以及 Playground 各卡片能力、DSpark 约束建模、PD 角色 flag 声明。

// ----- Card: "Speculative Decoding" -----
// DSpark 是训练好的草稿模型,替换 NEXTN 作为独立 strategy 芯片,
// 而不是吞吐 / 延迟曲线上的另一个档位(不同解码器,不是不同操作点)。
speculative: {
  options: [
    { id: "current", label: "Inherited from base" },
    { id: "off", label: "Off (greedy)" },
    { id: "mtp", label: "EAGLE / MTP",
      flags: ["--speculative-algorithm EAGLE", "--speculative-num-steps 3",
              "--speculative-eagle-topk 1", "--speculative-num-draft-tokens 4"] },
    // _handle_dspark(python/sglang/srt/arg_groups/speculative_hook.py)
    // 在约束不满足时直接 raise 而不是降级:pp_size 必须为 1,
    // DP-Attention 下还要求 --enable-dp-lm-head、--moe-a2a-backend none
    // 且无 context parallel。因此下面的 disable 条件与 hook 的硬约束
    // 一一对应,保证 Playground 不会生成注定启动失败的命令。
    { id: "dspark", label: "DSpark",
      flags: ["--speculative-algorithm DSPARK",
              "--speculative-draft-model-path RadixArk/Qwen3.8-Max-DSpark"],
      disable: [
        { when: { dpAttnOn: [true] },
          reason: "DSpark with DP-Attention additionally requires " +
                  "--enable-dp-lm-head, the built-in TP MoE " +
                  "(--moe-a2a-backend none) and no context parallel." },
        { when: { hw: ["h200", "mi300x"] },
          reason: "DSpark requires pp_size == 1 and this recipe is " +
                  "pipelined (TP x PP across nodes)." },
        { when: { hw: ["b200", "b300"], quant: ["fp8"] },
          reason: "DSpark requires pp_size == 1 and the B200/B300 FP8 " +
                  "recipes are TP8 x PP2." },
      ] },
    { id: "ngram", label: "NGRAM",
      flags: ["--speculative-algorithm NGRAM",
              "--speculative-num-draft-tokens 16",
              "--speculative-ngram-max-bfs-breadth 10"],
      disable: { dpAttnOn: [true] } },
  ],
},
docs/src/snippets/_playground.jsx core-logic

共享渲染引擎的唯一源码改动(+18),让 modes[] 条目可携带角色专属 flags/env,是本次唯一影响所有既有 cookbook 页的变更点。

// 确定当前 PD 角色:config 声明了 modes[] 时以 Playground 选中值为准,
// 否则回落到 Deploy 面板上的 pdMode(该角色在 Deploy 面板选择)。
const mode = (fc.modes || []).length ? value.mode : ((sel && sel.pdMode) || "off");if (mode === "prefill" || mode === "decode") {
  const backend = value.transferBackend || (backends[0] || {}).id || "mooncake";
  const adds = [
    `--disaggregation-mode ${mode}`,
    `--disaggregation-transfer-backend ${backend}`,
  ];
  // 回填 bootstrap 与 IB device flag(顺序与 base cell 保持一致)。
  if (bootstrapPort) adds.push(`--disaggregation-bootstrap-port ${bootstrapPort}`);
  if (value.ibDevice && value.ibDevice !== "auto") {
    adds.push(`--disaggregation-ib-device ${value.ibDevice}`);
  }  // 角色专属 flags:modes[] 条目可声明只属于 prefill / decode 的 flags
  //(如 prefill 的 --load-balance-method、decode 的轮询间隔)。先按
  // flag 头剥离 base cell 中同名 flag,让角色专属值胜出而不是重复输出。
  // 该剥离只发生在角色分支内:applyAllDeltas 每次 render 从 baseFlags
  // 重新 seed,角色关闭时不存在残留 base flag 需要清理。
  const modeMeta = (fc.modes || []).find((m) => m.id === mode);
  if (modeMeta && modeMeta.flags && modeMeta.flags.length) {
    flags = h.stripFlagsByFirstToken(
      flags, modeMeta.flags.map((f) => f.split(/[\s=]/)[0]));
    adds.push(...modeMeta.flags);
  }  // 单机无需 --dist-init-addr:prefill / decode 按 PD_PORTS 从各自
  // --port 推导 ZMQ 端口(间隔 100),范围不重叠;多机仍由渲染器
  // 注入跨节点 --dist-init-addr。
  flags = h.insertBeforeTail(flags, adds);  // 角色专属 serving 端口,使 router 的 prefill / decode 目标对齐。
  const servePort = PD_PORTS[mode].serve;
  flags = flags.map((f) =>
    f.split(/[\s=]/)[0] === "--port" ? `--port ${servePort}` : f);  // 后端 env 按 envWhen 硬件门控追加,保留 base cell 原有 env。
  const meta = backends.find((b) => b.id === backend);
  if (meta && meta.env && meta.env.length) {
    const gate = meta.envWhen;
    const ok = !gate || Object.keys(gate).every(
      (k) => (gate[k] || []).includes(sel[k]));
    if (ok) env = [...env, ...meta.env.filter((e) => !env.includes(e))];
  }
  // 角色专属 env 同样按值去重;apply 是纯函数、每次从 baseEnv 重建,
  // 不会跨 render 残留上一个角色的 env。
  if (modeMeta && modeMeta.env && modeMeta.env.length) {
    env = [...env, ...modeMeta.env.filter((e) => !env.includes(e))];
  }
}
return { flags, env };

评论区精华

router 端口占位符修复的必要性 正确性

PR 无独立 review 评论;作者在 body Notes for reviewers 中说明:模板原先硬编码 30000 / 30001,而引擎 decode 服务实际监听 30100,字面端口会让 router 打向 decode 进程从未监听的端口,故改为 {{PREFILL_PORT}} / {{DECODE_PORT}} / {{ROUTER_PORT}} 占位符。

结论:接受修复;同步更新 authoring-reference.md,规定新建页面必须使用占位符而非字面端口。 · 已解决

DSpark 作为第四 strategy 而非 tier 的设计 设计

作者在 Notes for reviewers 中论证:dspark 是模型专属策略 ID,因为 DSpark 是另一套投机解码器,不同于吞吐 / 延迟曲线上的操作点;_handle_dspark 在约束不满足时 raise 而非降级,因此页面仅在 pp == 1(DP-Attention 下还需 --enable-dp-lm-head 与内置 TP MoE)的组合提供该选项。

结论:两位 reviewer 直接批准,无异议。 · 已解决

GB300 配方依赖未发布的 DeepEP v2 flag question

作者在 Notes for reviewers 中主动声明:GB300 Balanced 与 High Throughput 档需要 DeepEP v2 wheel(2.1.0+01dc3aa),--moe-a2a-backend deepep_v2 上游尚不存在;Low Latency 与其他平台配方只发 upstream 已有 flag。

结论:作为已知项接受,未阻塞合并;但与上游发布存在时序耦合。 · 已解决

风险与影响

  1. 共享渲染引擎回归风险_playground.jsx 被所有 cookbook 页面共用,本次 +18 改动无对应测试;作者声明对现有 8 个配置是 no-op 且逐一核验过,但后续任何 config 结构变更若触发 modeMeta 分支都有可能在全部页面产生静默命令差异。
  2. GB300 配方依赖未发布 flag--moe-a2a-backend deepep_v2 上游尚不存在,若用户按文档在旧版本 SGLang 上直接运行 Balanced/High Throughput 命令会启动失败;虽在页面标注,仍存在被误用的可能。
  3. 基准数据全部 pending:18 个 benchmark cell 均为空桩,用户无法据此选型;页面也未说明测量的预计时间表。
  4. Docker 镜像 tag 依赖发布时序lmsysorg/sglang:qwen38 与 ROCm 镜像 tag(如 v0.5.17-rocm720-mi35x-20260812)为发布期 pin,若镜像未同步推送则 docker pull 失败。
  5. 脚手架模板修复的传播范围config.jsx.tmpl 的端口占位符改动会影响此后所有新建 cookbook,但已按旧模板生成的页面需逐个确认是否仍携带 30001 字样。

对用户:Qwen3.8 部署者获得 day-0 级别的跨平台配方,尤其受益于 GDN 状态池而非 KV cache 作为并发瓶颈的配置指引(状态槽比例 1/3/5、PP 关掉 overlap scheduler 时为 4),这是此前稠密注意力页面从未覆盖的架构差异。对团队:cookbook 编写 skill 修复了端口缺陷,后续所有模型页面生成都会受益;Playground 引擎能力扩展为 PD 角色专属 flag 提供了标准表达位置,降低未来在 cell 里塞角色类 flag 的倾向。对系统:纯文档与脚手架改动,无推理路径、无运行时影响;_playground.jsx 的幂等 delta 设计保证对既有页面零行为变化。

共享渲染引擎改动无测试覆盖 配方依赖未发布 flag 基准数据全部 pending 端口占位符修复影响后续页面生成

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论