执行摘要
本 PR 为 Ling-3.0-flash cookbook 的 Deploy 面板新增 Spec Decode 一级选择器,把原先隐式的 NEXTN 投机解码升级为 NEXTN / DSPARK / Off 三档,并为每个 spec 提供独立基准行。核心实现是 ling-3.0-flash.jsx 中新增的 spec 匹配维度与 IIFE + dsparkTwin 自动生成 DSPARK 配方(固定 --linear-replayssm-cache-len 32),以及共享 Playground 组件对 ReplaySSM flag 的识别与清理。实测 B200 BF16 下 DSPARK 相对 NEXTN 吞吐提升约 2.1×(c1)与 1.35×(c16),GSM8K 精度基本持平。纯文档变更,无引擎代码改动。
功能与动机
PR body 的目标是把投机解码从隐性配置提升为显式选项:"Promotes speculative decoding on the Ling-3.0-flash cookbook to a first-class Spec Decode selector in the Deploy panel — NEXTN (built-in MTP) / DSPARK (external draft) / Off"。
动机有两点:
- 性能收益:DSPARK 外部草稿路径在 B200 BF16 上比内置 MTP 的 NEXTN 快 2.1×(c1 吞吐 1902 vs 886 tok/s/GPU)与 1.35×(c16 8025 vs 5936),平均接受长度 6.22,而 GSM8K 精度几乎持平(96.59% vs 96.66%)。
- 配方可运行性:草稿 block size 8 使验证窗口为 9 tokens,KDA ReplaySSM ring 必须是 2 的幂且不小于 2× 窗口,默认的 16 会直接触发启动校验失败——该参数是作者实际运行组合命令时发现并推导出来的。
实现拆解
- 新增 spec 匹配维度(ling-3.0-flash.jsx):引入
matchDims 中的 spec 维度(nextn / dspark / off),Deploy 面板据此渲染 Spec Decode 选择器;既有 low-latency 配方补 spec: "nextn",high-throughput 补 spec: "off"(饱和场景下 draft/verify 开销不划算)。
- IIFE + dsparkTwin 生成 DSPARK twin:Mintlify snippet 编译器只求值导出的表达式、丢弃顶层模块代码,因此 cells 整体迁入 IIFE。
dsparkTwin 从每个 NEXTN low-latency cell 复制 twin,把 --speculative-algorithm NEXTN 替换为 DSPARK_FLAGS(DSPARK 算法 + 草稿路径 + ReplaySSM + cache-len 32),并只在 b200 + bf16 上标 verified: true。
- 共享 Playground 对齐(_playground.jsx):
deriveFromBase 的识别列表与 stripFlagsByFirstToken 的剥离列表补上 --enable-linear-replayssm-spec 与 --linear-replayssm-cache-len,保证从 DSPARK 切回 NEXTN / Off 时无残留 flag;该组件被所有模型页面共享,改动不影响其他模型。
- 基准按 spec 键化(ling-3.0-flash-benchmarks.jsx):每条
match 补 spec 字段,与 cells 形成一致的数据契约;B200 BF16 low-latency 基于 PR #33561 head 0e5e40d8f(dev-Ling-3.0-flash 镜像)重新测量,新增 NEXTN / DSPARK 两套速度与精度数据。
- 文档正文配套(Ling-3.0-flash.mdx):Available Models 增补 DSPARK draft checkpoint;Configuration Tips 说明 ReplaySSM ring 参数推导(block size 8 → 9-token 验证窗口 → 2 的幂且 ≥ 18 → 32),并给出验证环境与数据。
测试与配套:无引擎测试变更;验证链路为 docs 自带 check_cookbook_configs.mjs、mint validate、mint broken-links,以及作者在 4×B200 上端到端 serving、smoke、bench 与全量 GSM8K 跑分。
docs/src/snippets/configs/inclusionAI/ling-3.0-flash.jsx
本 PR 的核心实现文件:新增 spec 匹配维度与 DSPARK 选项,cells 迁移到 IIFE 并用 dsparkTwin 自动生成 DSPARK twin 配方。
// Mintlify 的 snippet 编译器只求值导出的表达式,顶层模块代码会被整体丢弃,
// 因此 cells 必须放进 IIFE,flatMap 生成 DSPARK twin 的逻辑才能被执行。
cells: (() => {
// DSPARK 外部草稿路径由 4 个 flag 联动:
// --speculative-algorithm DSPARK 切到外部草稿算法;
// --enable-linear-replayssm-spec 启用 KDA ReplaySSM 线性验证路径;
// --linear-replayssm-cache-len 32 是推导值:草稿 block size 8 使 verify
// 窗口为 9 tokens,ReplaySSM ring 必须是 2 的幂且 >= 2× 窗口,
// 默认 16 过小,服务会在启动校验时拒绝。
const DSPARK_FLAGS = [
"--speculative-algorithm DSPARK",
"--speculative-draft-model-path inclusionAI/Ling-3.0-flash-dspark",
"--enable-linear-replayssm-spec",
"--linear-replayssm-cache-len 32",
];
// 从 NEXTN low-latency cell 复制出 DSPARK twin:
// match 键改为 spec: "dspark",flags 中出现的 NEXTN 整体替换为 DSPARK_FLAGS。
const dsparkTwin = (cell, verified) => ({
...cell,
verified,
match: { ...cell.match, spec: "dspark" },
flags: cell.flags.flatMap((f) =>
f === "--speculative-algorithm NEXTN" ? DSPARK_FLAGS : [f]),
});
// 原有 low-latency 配方补上 spec: "nextn" 字段,flags 不变;
// 下面仅保留 b200 + bf16 的完整 cell 作示例,其余硬件同构。
const lowLatencyCells = [
{
match: { hw: "b200", variant: "default", quant: "bf16",
strategy: "low-latency", spec: "nextn", nodes: "single" },
verified: true,
flags: [
"--model-path {{MODEL_NAME}}",
"--tp 4",
"--speculative-algorithm NEXTN",
"--mem-fraction-static 0.8",
"--host {{HOST_IP}}",
"--port {{PORT}}",
],
},
// ...h20-3e / h200 / h800 / h100 / gb300 以及 fp8 系列同构
];
// 每个 low-latency cell 后紧跟其 DSPARK twin;
// 只有 b200 + bf16 组合在 4×B200 上做过完整验证,标 verified。
return [
...lowLatencyCells.flatMap((c) => [
c,
dsparkTwin(c, c.match.hw === "b200" && c.match.quant === "bf16"),
]),
// ...high-throughput(spec: "off")与 hicache(spec: "nextn")系列 cell
];
})(),
docs/src/snippets/_playground.jsx
共享的 Playground 组件:speculative 轴的 flag 识别与剥离列表新增 ReplaySSM 参数,保证切换 spec 时不留过期 flag,是所有模型页面共用的交互引擎。
// ---- Axis: Speculative Decoding -----------------------------------------
// 单选项轴:value 为 "current" 时保持 base 原样;为 "off" 时剥离全部
// spec flag(greedy);为具体选项时先剥离旧 flag,再插入选中项自己的 flags。
// deriveFromBase:收集 cell 里现有的 --speculative-* flag 集合,
// 与各选项的 flags 做数量 + 内容双重匹配,命中即视为该选项,否则回退 "current"。
deriveFromBase: (cell, fc) => {
const flags = (cell && cell.flags) || [];
const baseSpec = flags.filter((f) => {
const head = f.split(/[\s=]/)[0];
return head === "--speculative-algorithm"
|| head === "--speculative-num-steps"
|| head === "--speculative-eagle-topk"
|| head === "--speculative-num-draft-tokens"
|| head === "--speculative-dspark-block-size"
// ReplaySSM 是 DSPARK 外部草稿的配套验证路径,必须纳入识别与剥离,
// 否则从 DSPARK 切回 NEXTN / Off 时会残留 --linear-replayssm-cache-len。
|| head === "--enable-linear-replayssm-spec"
|| head === "--linear-replayssm-cache-len"
|| head === "--speculative-ngram-max-bfs-breadth";
});
if (baseSpec.length === 0) return "off";
for (const opt of (fc.options || [])) {
if (!opt.flags || opt.flags.length !== baseSpec.length) continue;
const ok = opt.flags.every((pf) => baseSpec.includes(pf));
if (ok) return opt.id;
}
return "current";
},
// apply:切换选项时按首个 token 剥离全部 spec 相关 flag,
// 再插入目标选项的 preset flags;选择与 base 一致时直接返回以保留 flag 位置。
apply: ({ flags, env, value, fc, sel, h, derived }) => {
if (value === "current") return { flags, env };
if (derived && value === derived) return { flags, env };
const picked = (fc.options || []).find((p) => p.id === value);
if (picked && h.evaluateChip(picked, {
...sel,
dpAttnOn: h.hasFlag(flags, "--enable-dp-attention"),
}).disabled) {
return { flags, env };
}
flags = h.stripFlagsByFirstToken(flags, [
"--speculative-algorithm", "--speculative-num-steps",
"--speculative-eagle-topk", "--speculative-num-draft-tokens",
"--speculative-dspark-block-size", "--enable-linear-replayssm-spec",
"--linear-replayssm-cache-len",
"--speculative-ngram-max-bfs-breadth",
]);
const preset = (fc.options || []).find((p) => p.id === value);
if (preset?.flags?.length) flags = h.insertBeforeTail(flags, preset.flags);
return { flags, env };
},
评论区精华
本 PR 几乎没有人工 review 交锋:唯一的 review 是 zijiexia 的 APPROVED(空 body),唯一的 PR 评论来自 mintlify[bot] 的 preview 部署通知,不涉及技术内容。
真正有价值的信息藏在 8 个 commit 的演进里:
- commit
255df4a "fix Ling cookbook render — keep snippet config free of top-level code" 揭示了核心实现约束——Mintlify snippet 编译器只求值导出表达式,顶层模块代码会被丢弃,因此 cells 必须迁入 IIFE,dsparkTwin 也只能写在其中。
- commit
ec31e57 "drop stray semicolon" 说明作者在渲染链路中还处理了残留分号问题;多次 retrigger mintlify preview 反映文档预览系统的迭代成本。
这些 commit 本身就是与构建约束的"讨论",也是本 PR 最有学习价值的部分。
风险与影响
风险:
- 草稿仓库未公开:PR body 明确说明 draft repo 当前为私有,HF 链接匿名访问会 404。文档发布后用户按配方操作会先遇到 404,属于已知的临时性外部依赖风险,建议仓库公开后回访更新。
- 文档内数据不一致:PR body 表格为 NEXTN 96.66% / DSPARK 96.59%,mdx 正文为 DSPARK 96.66% / NEXTN 96.44%(stop rate 99.77% / 99.62%),两处可能来自不同测量轮次,读者对照时容易困惑。
- 共享组件匹配逻辑脆弱:
deriveFromBase 要求 flag 数量与内容完全相等才判中;未来若引擎给 cell 追加其它 speculative flag,长度不匹配会让选择器回退为 "current",表现为默认态异常。
- 基准数据易过期:所有数据锚定 PR #33561 具体 commit 与 dev-Ling-3.0-flash 镜像,mdx 已留有 GB300 数据待补的 TODO,引擎演进后需要重新测量。
影响:用户侧是 Ling-3.0-flash 部署页新增 Spec Decode 维度,可一键切换并查看各自基准;系统侧无运行时影响;团队侧为其他模型 cookbook 扩展外部草稿投机解码提供了可复制的样板模式(matchDims 新维度 + IIFE 生成 twin)。
关联脉络
本 PR 是 Ling-3.0-flash cookbook 系列的延伸,直接依赖 PR #33561 的配方与基准(benchmarks 文件锚定其多个 commit,验证使用 dev-Ling-3.0-flash 镜像)。它与仓库中 speculative-decoding 功能的演进方向一致:从 NEXTN 内置 MTP 覆盖到 DSPARK 外部草稿 + KDA ReplaySSM 验证,把引擎能力沉淀为文档站的一等配置项。值得注意的是,改动将共享的 _playground.jsx 的 flag 生命周期管理又推进了一步,后续其他模型接入新的投机解码算法时,需要同步维护识别与剥离列表。
参与讨论