[WIP] Add GB300 AgentX Qwen3.5 recipes#2121
Conversation
csahithi
commented
Jul 8, 2026
- 9 Qwen3.5-397B-A17B-NVFP4 GB300 sglang AgentX recipes (agg + disagg pareto)
- configs/nvidia-master.yaml: qwen3.5-fp4-gb300-dynamo-sglang{,-agentic-agg,-agentic-disagg}
- perf-changelog.yaml: agentic pareto entry
- runners/launch_gb300-nv.sh: qwen3.5 launcher branch + dynamo-wheels cache
|
Thanks for the contribution! Please reach out to respective companies' CODEOWNER to fill in the latest PR_REVIEW_CHECKLIST.md before pinging core maintainer on Slack for review. In order for the signoff PR check bot to trigger, you must follow the PR_REVIEW_CHECKLIST.md template correctly, including the phrase For PR verification, add the PR authors are responsible for ensuring that after merging, all GitHub Action jobs fully pass. A lot of the time, failures are just flakes and simply re-running the failed jobs will fix it. See GitHub's docs on re-running failed jobs 感谢你的贡献!请联系相应公司的 CODEOWNER 填写最新的 PR_REVIEW_CHECKLIST.md,然后再在 Slack 上联系核心维护者进行审阅。为了触发 signoff PR 检查机器人,你必须正确遵循 PR_REVIEW_CHECKLIST.md 模板,包括保留英文语句 如需进行 PR 验证,请为此 PR 添加 PR 作者有责任确保合并后所有 GitHub Action 任务完全通过。 很多时候失败只是偶发抖动(flake),重新运行失败的任务即可解决。参见 GitHub 关于重新运行失败任务的文档 |
2 similar comments
|
Thanks for the contribution! Please reach out to respective companies' CODEOWNER to fill in the latest PR_REVIEW_CHECKLIST.md before pinging core maintainer on Slack for review. In order for the signoff PR check bot to trigger, you must follow the PR_REVIEW_CHECKLIST.md template correctly, including the phrase For PR verification, add the PR authors are responsible for ensuring that after merging, all GitHub Action jobs fully pass. A lot of the time, failures are just flakes and simply re-running the failed jobs will fix it. See GitHub's docs on re-running failed jobs 感谢你的贡献!请联系相应公司的 CODEOWNER 填写最新的 PR_REVIEW_CHECKLIST.md,然后再在 Slack 上联系核心维护者进行审阅。为了触发 signoff PR 检查机器人,你必须正确遵循 PR_REVIEW_CHECKLIST.md 模板,包括保留英文语句 如需进行 PR 验证,请为此 PR 添加 PR 作者有责任确保合并后所有 GitHub Action 任务完全通过。 很多时候失败只是偶发抖动(flake),重新运行失败的任务即可解决。参见 GitHub 关于重新运行失败任务的文档 |
|
Thanks for the contribution! Please reach out to respective companies' CODEOWNER to fill in the latest PR_REVIEW_CHECKLIST.md before pinging core maintainer on Slack for review. In order for the signoff PR check bot to trigger, you must follow the PR_REVIEW_CHECKLIST.md template correctly, including the phrase For PR verification, add the PR authors are responsible for ensuring that after merging, all GitHub Action jobs fully pass. A lot of the time, failures are just flakes and simply re-running the failed jobs will fix it. See GitHub's docs on re-running failed jobs 感谢你的贡献!请联系相应公司的 CODEOWNER 填写最新的 PR_REVIEW_CHECKLIST.md,然后再在 Slack 上联系核心维护者进行审阅。为了触发 signoff PR 检查机器人,你必须正确遵循 PR_REVIEW_CHECKLIST.md 模板,包括保留英文语句 如需进行 PR 验证,请为此 PR 添加 PR 作者有责任确保合并后所有 GitHub Action 任务完全通过。 很多时候失败只是偶发抖动(flake),重新运行失败的任务即可解决。参见 GitHub 关于重新运行失败任务的文档 |
b90cee7 to
7dc6bac
Compare
|
see unofficial run visualizer at https://inferencex.semianalysis.com/inference?unofficialRun=28975134400 |
There was a problem hiding this comment.
Additional findings (outside current diff — PR may have been updated during review):
-
🔴
configs/nvidia-master.yaml:10940-10969— 9 new sweep entries in configs/nvidia-master.yaml (agentic-agg + agentic-disagg, lines 10940–11085) declarespec-decoding: none, but every one of the 9 corresponding recipe files enables NEXTN MTP (speculative-algorithm: NEXTN+speculative-num-steps: 3+ eagle-topk/num-draft-tokens; the recipe filenames also encode-mtp-). The engine runs MTP correctly because srtctl applies the recipe directly, butSPEC_DECODINGpropagates verbatim intoRESULT_FILENAME(_spec-none_…in artifact names, benchmark-multinode-tmpl.yml:225) and into the aggregated result JSON'sspec_decodingfield (utils/agentic/aggregation/process_agentic_result.py:139), so downstream dashboards / Pareto comparisons will silently misclassify these MTP runs as non-MTP. Fix: changespec-decoding: none→spec-decoding: "mtp"on all 9 entries in this block (matches the file's existing MTP convention — every other qwen3.5/dsr1/dsv4 MTP entry usesmtp; the parallel dsv4 agentic entry usingnoneis self-consistent because its vLLM recipes have nospeculative-*fields).Extended reasoning...
What the bug is
All 9 newly added sweep entries under
qwen3.5-fp4-gb300-dynamo-sglang-agentic-aggandqwen3.5-fp4-gb300-dynamo-sglang-agentic-disagg(configs/nvidia-master.yaml lines 10943, 10957, 10986, 11000, 11014, 11029, 11044, 11059, 11074) set:spec-decoding: none
But every one of the 9 corresponding recipe files under
benchmarks/multi_node/srt-slurm-recipes/sglang/qwen3.5/gb300-fp4/agentic/*.yamlenables NEXTN MTP:speculative-algorithm: NEXTN speculative-num-steps: 3 speculative-eagle-topk: 1 speculative-num-draft-tokens: 4
The recipe filenames themselves also encode
-mtp-(e.g.agg-gb300-tp4-c1-mtp-hicache-jid2191933.yaml,disagg-gb300-1p1d-tp4-tp4-c32-mtp-hicache-convaware-jid2212783.yaml).Why the engine still runs MTP but the metadata is wrong
srtctl applyreads the recipe file directly, so the engine gets--speculative-algorithm NEXTN …on its command line and NEXTN MTP runs as intended. Thespec-decodingfield innvidia-master.yamlis not a live engine setting — it feedsSPEC_DECODINGinto the workflow env, which has two downstream consumers, and both are silently corrupted by this mislabel:-
Artifact filenames —
.github/workflows/benchmark-multinode-tmpl.yml:225bakes_spec-${{ env.SPEC_DECODING }}_directly intoRESULT_FILENAME. So uploaded result JSONs land as…_spec-none_conc*.jsondespite the run actually using MTP. -
Aggregated result JSON body —
utils/agentic/aggregation/process_agentic_result.py:139writes"spec_decoding": os.environ.get("SPEC_DECODING", "none")verbatim into the aggregated result JSON. Downstream dashboards / Pareto plots that filter or facet onspec_decodingwill silently misclassify these MTP runs as non-MTP.
(Some verifiers also flagged
utils/compare_results.py:51readingresult['spec_decoding']for baseline lookup — worth double-checking, but the two consumers above are sufficient on their own.)Convention check
Every other MTP recipe in
nvidia-master.yaml(dsr1-mtp, dsv4-b200-vllm-mtp, qwen3.5 fixed-seq-len MTP tiers, etc.) usesspec-decoding: "mtp". The one other agentic entry that legitimately usesspec-decoding: none—dsv4-fp4-gb300-dynamo-vllm-agentic— is self-consistent because its vLLM recipes atbenchmarks/multi_node/srt-slurm-recipes/vllm/deepseek-v4/agentic/*.yamlcontain nospeculative-*fields. So this is a real inconsistency introduced by this PR, not the file's existing style.Step-by-step proof (agentic-agg conc=1)
- Sweep matrix expands the
spec-decoding: none/conc-list: [1]entry into a GHA job withSPEC_DECODING=none,CONFIG_FILE=recipes/sglang/qwen3.5/gb300-fp4/agentic/agg-gb300-tp4-c1-mtp-hicache-jid2191933.yaml. srtctl apply -f $CONFIG_FILEreads the recipe, which containsspeculative-algorithm: NEXTN+speculative-num-steps: 3— the sglang server starts with NEXTN MTP enabled. ✅ Engine correct.benchmark-multinode-tmpl.yml:225computesRESULT_FILENAME=…_spec-none_conc1_…fromenv.SPEC_DECODING=none. ❌ Artifact filename claims non-MTP.process_agentic_result.py:139readsos.environ.get("SPEC_DECODING", "none")→"none"and writes"spec_decoding": "none"into the aggregated result JSON. ❌ Result body claims non-MTP.- A downstream MTP-vs-non-MTP Pareto plot that groups by
spec_decodingputs this run in the non-MTP bucket, distorting the frontier.
Fix
Mechanical 9-line change — replace
spec-decoding: nonewithspec-decoding: "mtp"on all 9 new entries in this block (lines 10943, 10957, 10986, 11000, 11014, 11029, 11044, 11059, 11074). Nothing else in the recipe files needs to change; the change is purely to keep the master-config label truthful to what the recipe actually runs. -
| - config-keys: | ||
| - qwen3.5-fp4-gb300-dynamo-sglang-agentic-agg | ||
| - qwen3.5-fp4-gb300-dynamo-sglang-agentic-disagg | ||
| description: | ||
| - "Add Qwen3.5-397B-A17B-NVFP4 FP4 GB300 SGLang AgentX Pareto-frontier benchmarks via the srtctl/dynamo stack" | ||
| - "agg: single aggregated node (TP4, MTP/NEXTN, hierarchical KV cache), concurrencies [1, 96]" | ||
| - "disagg: 1P1D-4P1D (TP4/DEP4 prefill, TP4/DEP4/DEP8 decode, MTP/NEXTN, hicache, conv-aware routing) over 7 Pareto points at concurrency 32-384" | ||
| - "Image: lmsysorg/sglang:nightly-dev-cu13-20260624-b2c8f7a2; runner: gb300-nv" | ||
| pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/2121 |
There was a problem hiding this comment.
🔴 The new perf-changelog entry for qwen3.5-fp4-gb300-dynamo-sglang-agentic-{agg,disagg} (perf-changelog.yaml:4366-4373) will block the changelog gate on two independent grounds: (1) it's missing the required pr-link field, and (2) it's inserted mid-file rather than appended to the end. Fix: move the 8-line block to the end of the file and add pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/2121 (or the XXX placeholder while WIP).
Extended reasoning...
What breaks. utils/validate_perf_changelog.py (invoked from .github/workflows/run-sweep.yml on every PR push) enforces three independent checks that this new entry violates. Any one of them is enough to fail the changelog gate; the entry fails all three.
1. Missing pr-link — schema-level rejection. In utils/matrix_logic/validation.py:683, ChangelogEntry declares pr_link: str = Field(alias="pr-link") with no default and extra="forbid". parse_changelog (validate_perf_changelog.py:128-133) calls ChangelogEntry.model_validate(entry) on every entry; Pydantic raises ValidationError on the new entry, which is re-raised as ChangelogValidationError('… fails ChangelogEntry validation'). Even if that were bypassed, validate_added_pr_link (lines 144-160) rejects it a second time: str(entry.get('pr-link') or '') == '', which is neither in PR_LINK_PLACEHOLDERS = {'XXX', 'https://github.com/SemiAnalysisAI/InferenceX/pull/XXX'} nor equal to the canonical PR URL, so it raises ChangelogValidationError('new PR entry must use …').
2. Mid-file insertion — positional rejection. The new 8-line block sits at lines 4366-4373, between an existing pull/1931 entry and the pre-existing minimaxm3-fp4-mi355x-vllm-mtp entry — with ~30 more historical entries after it. compare_entries (lines 163-208) walks base_entries and head_entries in lockstep by index; at the insertion index, head_entries[i] is the new qwen3.5 entry but base_entries[i] is the pre-existing minimaxm3 entry, and without_pr_link differs, so it raises ChangelogValidationError('entry N changed; existing entries are immutable except for pr-link-only corrections').
3. Byte-level prefix check. validate_raw_change (lines 211-235) additionally requires head_raw.startswith(base_raw) when there are additions. A mid-file insertion breaks that even before compare_entries runs, raising 'appended entries changed historical perf-changelog.yaml bytes; restore the base file byte-for-byte and append at the end'. AGENTS.md line 78 codifies the same rule: 'new entries MUST be appended to the END, never inserted in the middle or prepended.'
Step-by-step proof.
- CI runs
python3 utils/validate_perf_changelog.py --base-ref origin/main --head-ref HEAD. parse_changelogreads perf-changelog.yaml and iterates entries. When it reaches the qwen3.5 entry,ChangelogEntry.model_validate({config-keys: [...], description: [...]})fails becausepr-linkis required and absent →ChangelogValidationError→ exit non-zero → theValidate perf-changelogcheck turns red → PR cannot merge. If pr-link were the only issue, addingpr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/2121at the end of the block would clear check 1.- Even then,
validate_raw_changecomputesbase_raw = git show origin/main:perf-changelog.yamlandhead_raw = the current file; because ~30 entries follow the insertion point in head_raw but not at the same byte offset in base_raw,head_raw.startswith(base_raw)is false → raises. Only after moving the 8-line block to the file end (after the current last entry) does this pass. compare_entriesthen compares base and head entries index-by-index; index-of-first-difference is now len(base_entries), the appended entry is treated as an addition,validate_added_pr_linkre-validates the pr-link, and the gate passes.
Fix. Two edits:
- Move the qwen3.5-fp4-gb300-dynamo-sglang-agentic-{agg,disagg} entry (perf-changelog.yaml:4366-4373) to the end of perf-changelog.yaml, after the current last entry.
- Add
pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/2121to the moved block (orpr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/XXXfor early WIP).
There was a problem hiding this comment.
Resolved both the above comments
80d1f5c to
ae49f13
Compare
|
see unofficial run visualizer at https://inferencex.semianalysis.com/inference?unofficialRun=28977280171 |
| speculative-algorithm: NEXTN | ||
| speculative-num-steps: 3 | ||
| speculative-eagle-topk: 1 | ||
| speculative-num-draft-tokens: 4 |
There was a problem hiding this comment.
started about discussion about AgentX MTP +viz @kedarpotdar-nv
|
see unofficial run visualizer at https://inferencex.semianalysis.com/inference?unofficialRun=28977625116 |
- 9 Qwen3.5-397B-A17B-NVFP4 GB300 sglang AgentX recipes (agg + disagg pareto)
- configs/nvidia-master.yaml: qwen3.5-fp4-gb300-dynamo-sglang{,-agentic-agg,-agentic-disagg}
- perf-changelog.yaml: agentic pareto entry
- runners/launch_gb300-nv.sh: qwen3.5 launcher branch + dynamo-wheels cache
- run-sweep.yml: pass the list-valued conc correctly to the multi-node agentic
template — conc-list via toJson, conc as conc[0]. Passing the raw list to the
scalar 'conc' input made GitHub reject the job ("A sequence was not
expected"), so no agentic matrix jobs instantiated.
- run-sweep.yml: add sweep-agentic + sweep-multi-node-agentic to the
collect-results gate so agentic-only sweeps collect their results.
- benchmark-multinode-tmpl.yml: job-name label shows the full concurrency batch.
The 9 qwen3.5 agentic-agg/disagg entries declared spec-decoding: none, but their recipes enable NEXTN MTP (speculative-algorithm NEXTN). SPEC_DECODING flows into RESULT_FILENAME and the aggregated result JSON's spec_decoding field, so dashboards/Pareto would misclassify these MTP runs as non-MTP. Set spec-decoding: "mtp" to match the engine + the file's MTP convention.
bd940fb to
e571715
Compare
Pin synthetic acceptance to the committed golden AL (golden_al_distribution/ qwen3.5_mtp.yaml, thinking_on, draft-len 3 = 3.39) on the decode worker (disagg) / aggregated worker (agg), per the AgentX fairness guideline, instead of the draft head's variable acceptance: SGLANG_SIMULATE_ACC_LEN: '3.39' SGLANG_SIMULATE_ACC_METHOD: match-expected SGLANG_SIMULATE_ACC_TOKEN_MODE: "real-draft-token" real-draft-token keeps real per-token timing (non-zero ITL); the real NEXTN speculative-* settings are unchanged.
…-074bb928 Align the agentic-agg and agentic-disagg keys: 20260624-b2c8f7a2 -> 20260709-074bb928.
|
see unofficial run visualizer at https://inferencex.semianalysis.com/inference?unofficialRun=29055853595 |
|
see unofficial run visualizer at https://inferencex.semianalysis.com/inference?unofficialRun=29056354557 |