Qwen3.8-Flash-Next NVFP4 on one DGX Spark (TP=1): vLLM V2 + b12x, 4-token MTP, sparkrun recipe, measured throughput and a quality gate
See the code
sparkrun recipe: Qwen3.8-Flash-Next (NVFP4 / MXFP8, MTP ×4) on 1x DGX Spark.
vLLM with b12x GB10 kernels, PLE table paged from NVMe, OpenAI-compatible endpoint, quality-gated releases.
60 / 75 tok/sTG c1defaults (ISL/OSL 2048/512), v2.2.0 / T=0, thinking off (coding), v2.2.0 | 137 / 192 tok/sTG aggregate c8defaults (ISL/OSL 2048/512), v2.2.0 / T=0, thinking off (coding), v2.2.0 | 92/100Hardmodepass ≥ 88, T=0, thinking on | 7.1 sTTFT, ISL 16Kc1, cold prefix |
262K context, max_num_seqs 8, MTP ×4, OpenAI-compatible API, quality-gated releases
GPU power, GPU only (nvidia-smi), not wall power: idle 9.7 W, c1 24.2 W, c8 28.9 W; TG per GPU watt 2.49 (c1) and 4.73 (c8) tok/s/W at server defaults.
TG cells: server defaults (ISL/OSL 2048/512, T=1.0, thinking on) first, T=0 coding (36 prompts, thinking off) second, both aggregate output tok/s. Means over 6 boots where measured; sd between boots in the details. Release v2.2.0.
| Metric | Mean | sd between boots | Boots | Workload | Sampling | Release (date) | Source |
|---|---|---|---|---|---|---|---|
| TG c1, defaults | 60.4 tok/s | 3.22 | 6 | llama-benchy task mode, ISL/OSL 2048/512 | T=1.0, top-p 0.95, top-k 20, thinking on | v2.2.0 (2026-10-10) | results |
| TG c1, coding | 74.9 tok/s | 0.31 | 6 | 36 prompts, OSL ≤768, aggregate output tok/s per pass | T=0, thinking off | v2.2.0 (2026-10-10) | results |
| TG c1, coding, per-prompt median | 77.0 tok/s | – | 1 | 36 prompts (Python, C++, Rust, Go), OSL ≤768, median over prompts | T=0, thinking off | v2.1.0 (2026-10-10) | results |
| TG c1, coding, defaults, per-prompt median | 60.9 tok/s | – | 1 | 36 prompts, OSL ≤768; 198/216 requests hit the 768-token cap inside thinking | server defaults, thinking on | v2.1.0 (2026-10-10) | results |
| TG aggregate c8, defaults | 136.7 tok/s | 3.30 | 6 | llama-benchy task mode, ISL/OSL 2048/512 | T=1.0, top-p 0.95, top-k 20, thinking on | v2.2.0 (2026-10-10) | results |
| TG aggregate c8, coding | 192.0 tok/s | 1.02 | 6 | 36 prompts, OSL ≤768, aggregate output tok/s per pass | T=0, thinking off | v2.2.0 (2026-10-10) | results |
| TTFT, ISL 16K | 7.10 s | 0.02 | 4 | c1, cold prefix | – | v2.4.0 (2026-10-16) | results |
| Hardmode | 92/100 | – | 1 | 88 multi-step tool-use scenarios; pass ≥ 88 | T=0, thinking on | v2.4.0 (2026-10-16) | results |
| GPU power, idle | 9.7 W | – | 6 | server up, no requests, 120 s | – | v2.2.0 (2026-10-10) | results |
| GPU power, TG c1 defaults | 24.2 W | – | 6 | power.draw, GPU only (nvidia-smi), not wall power, mean over the cell | T=1.0, top-p 0.95, top-k 20, thinking on | v2.2.0 (2026-10-10) | results |
| TG per GPU watt, c1 defaults | 2.49 tok/s/W | – | 6 | TG aggregate / GPU W | T=1.0, top-p 0.95, top-k 20, thinking on | v2.2.0 (2026-10-10) | results |
| GPU power, TG c8 defaults | 28.9 W | – | 6 | power.draw, GPU only (nvidia-smi), not wall power, mean over the cell | T=1.0, top-p 0.95, top-k 20, thinking on | v2.2.0 (2026-10-10) | results |
| TG per GPU watt, c8 defaults | 4.73 tok/s/W | – | 6 | TG aggregate / GPU W | T=1.0, top-p 0.95, top-k 20, thinking on | v2.2.0 (2026-10-10) | results |
Method and full tables: docs/BENCHMARKS.md.
Requirements:
<spark> = hostname or IP; --solo = single
node.sparkrun registry add https://github.com/ursuciprian/qwen3.8-flash-next-1x-dgx-spark
sparkrun run qwen3.8-flash-next-1x-dgx-spark --hosts <spark> --solo
First run downloads ~135 GB (a fresh checkpoint download took 3 h 15 min at ~8.6 MB/s on my link; on a slow link,
pre-fetch it, see below). Boot with model and image on disk: 256 s on the v2.4.0 image check, with the plan file and the
compile cache coming from the image (171 s on v2.1.0 with a warm page cache); a cold-page-cache boot was not timed. sparkrun run returns before the engine is ready: poll http://<spark>:8000/health, then use
http://<spark>:8000/v1, model qwen3.8-flash-next:
curl http://<spark>:8000/v1/chat/completions -H 'Content-Type: application/json' \
-d '{"model": "qwen3.8-flash-next", "messages": [{"role": "user", "content": "Hello"}]}'
No API key: keep it on a trusted network or put an authenticating proxy in front.
Multi-user setups. I set this recipe up for a single user. --enable-prompt-tokens-details (since v2.3.0) makes the usage field report prompt_tokens_details.cached_tokens exactly, so on a server shared by several users or tenants one user can tell whether someone else already sent the same prompt prefix. Prefix caching already leaks this through time to first token; the flag makes it exact. With several users or tenants, give each one its own random, secret cache_salt in the request body (the pinned vLLM accepts it on /v1/chat/completions, /v1/completions and /v1/responses; a gateway can set it per API key), so their prefix-cache entries never match each other. Otherwise, remove --enable-prompt-tokens-details from the recipe.
The recipe serves its own checkpoint, about 98 GB. A fresh download took about 3 h 15 min on my link (~8.6 MB/s). Download it on the Spark before the first boot, together with the two files of the base checkpoint that the recipe uses for PP (2.6 GiB):
hf download ursuciprian/Qwen3.8-Flash-Next-NVFP4-GDN-MSE --revision 03f4a0570496bbe741189f4a2a7d611679e85406
hf download local-inference-lab/Qwen3.8-Flash-Next-NVFP4 --revision 7c4f1bc1a2d6847e0cbc01ac6b823f00251de8dd \
model-00035-of-00036.safetensors model.safetensors.index.json
sparkrun run returns before the engine is ready. Wait for health, then check that the reply has both reasoning and
an answer:
H=http://<spark>:8000
until [ "$(curl -s -o /dev/null -w '%{http_code}' $H/health)" = 200 ]; do sleep 10; done
curl -s $H/v1/chat/completions -H 'Content-Type: application/json' -d '{
"model":"qwen3.8-flash-next","max_tokens":1024,
"messages":[{"role":"user","content":"Write a Python function that reverses a string."}]}' \
| python3 -c "import json,sys; m=json.load(sys.stdin)['choices'][0]['message']
print('reasoning:', len(m.get('reasoning') or m.get('reasoning_content') or ''), 'chars')
print('content :', (m.get('content') or '')[:300])"
Empty content with long reasoning means max_tokens ran out inside thinking; garbled text means a checkpoint
mismatch (see Troubleshooting under Details below). Optional long-context check (stdlib Python), expect exact 20 at
both depths:
git clone https://github.com/ursuciprian/qwen3.8-flash-next-1x-dgx-spark && cd qwen3.8-flash-next-1x-dgx-spark
python3 scripts/fidelity_probe.py --base $H --model qwen3.8-flash-next --depths 8000,32000
The server binds 0.0.0.0 with no API key: keep it on a trusted network or put a proxy with auth in front. Stop with
sparkrun stop --all. To upgrade, run sparkrun registry update qwen38-flashnext-1x first: sparkrun caches
registries and does not refresh them on run.
Moved here on 2026-10-08 from qwen3.8-flash-next-dgx-spark-tp-2, which keeps a copy of this recipe so existing
sparkrun runsetups keep working. If both registries are added, pick this one withsparkrun run @qwen38-flashnext-1x/qwen3.8-flash-next-1x-dgx-spark --hosts <spark> --solo.
| Model | ursuciprian/Qwen3.8-Flash-Next-NVFP4-GDN-MSE @ 03f4a057: NVFP4 experts, MXFP8 dense and attention, GDN projections NVFP4 for TG and MXFP8 for PP |
| MTP | MTP ×4, probabilistic drafts, rejection sampling; drafter D3 refit on the served model's outputs (v2.1.0: D1) |
| Hardware | 1x DGX Spark (GB10, 128 GB unified), checkpoint on local NVMe |
| Parallelism / memory | TP=1; 26.8 GiB PLE table paged from NVMe (VLLM_PLE_MMAP=1), 14 GiB KV pool |
| Engine | vLLM + b12x (NVFP4 MoE, MXFP8 linears, GDN, QSA), plan and compile caches baked into the image |
| Context | 262,144 tokens (max_model_len) |
| Concurrent requests | up to 8 (max_num_seqs) |
| KV cache | 993,754 tokens, 3.79 concurrent 262K requests (v2.1.0 boot log) |
| API | OpenAI-compatible, tool calling, reasoning on (reasoning_effort medium); usage.prompt_tokens_details.cached_tokens reports prefix-cache hits |
| Disk / start time | ~135 GB / ~3 min warm (256 s on the v2.4.0 image check) |
| License | Recipe Apache-2.0; weights Qwen Community License 1.0 |
| Task | Section |
|---|---|
| TG, PP, TTFT, context depth | Performance |
| Sizing: 1x vs TP=2 vs DP=2 | 1x vs 2x TP=2 vs 2x DP=2 |
| Quality gate results | Quality gate |
| Raw data and provenance per number | Every number and where it comes from |
| Pin or roll back a release | Recipes, VERSIONS.md |
Aggregate TG scales to c8 while per-request TG drops. TTFT grows with ISL on a cold prefix; multi-turn requests hit the prefix cache and run PP only on the new tokens.
Left: 1x Spark v2.1.0, 2x Spark TP=2 v2.0.0, 2x Spark DP=2 v2.1.0; llama-benchy task mode. Right: 1x Spark v2.4.0, 2x Spark TP=2 v2.0.0/v1.4.0; c1, cold prefix.
Left: llama-benchy task mode (agent coding turn), ISL/OSL 2048/512, T=1.0, top-p 0.95, top-k 20, thinking on, prefix caching. Aggregate = all output tokens / wall time, PP included; per request = TG rate of one stream after its first token.
1x Spark: release v2.1.0, 2026-10-08, llama-benchy task mode, mean ± sd over runs, one boot
2x Spark TP=2: release v2.0.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271, mean ± sd of 3 runs, one boot
2x Spark DP=2: release v2.1.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271, mean ± sd of 3 runs, one boot
Versions are numbered per setup. Data: docs/data/capability.csv, with the source file of every point.
Right: c1, cold prefix (no cache hit). Each point: mean of 1 to 4 samples of one run (n per point in the CSV).
1x Spark: release v2.4.0, 2026-10-16, cold.py (k101)
2x Spark TP=2: release v2.0.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271; v1.4.0, 2026-10-07, fidelity_probe.py
1x Spark: not measured above 128K yet.
Data: docs/data/capability.csv, with the source file of every point.
Left: 1x Spark v2.4.0, 2x Spark TP=2 v2.0.0; c1, cold prefix. Right: 1x Spark v2.1.0; llama-benchy, ISL/OSL 2048/512 at depth.
Left: c1, cold prefix (no cache hit). Each point: mean of 1 to 4 samples of one run (n per point in the CSV).
1x Spark: release v2.4.0, 2026-10-16, cold.py (k101)
2x Spark TP=2: release v2.0.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271
Data: docs/data/capability.csv, with the source file of every point.
Right: 1x Spark: release v2.1.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271, mean ± sd of 2 Sparks x 3 runs, one boot each (older release; shipped v2.4.0 not measured on this test yet). Server default sampling. Each point: ISL/OSL 2048/512 on top of the cached context, same harness as the concurrency chart. Concurrency levels measured at one depth only are left out.
Data: docs/data/capability.csv, with the source file of every point.
1x Spark v2.1.0, 2x Spark TP=2 v2.0.0, 2x Spark DP=2 v2.1.0; llama-benchy task mode.
llama-benchy task mode (agent coding turn), ISL/OSL 2048/512, T=1.0, top-p 0.95, top-k 20, thinking on, prefix caching. Aggregate = all output tokens / wall time, PP included; per request = TG rate of one stream after its first token.
1x Spark: release v2.1.0, 2026-10-08, llama-benchy task mode, mean ± sd over runs, one boot
2x Spark TP=2: release v2.0.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271, mean ± sd of 3 runs, one boot
2x Spark DP=2: release v2.1.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271, mean ± sd of 3 runs, one boot
Versions are numbered per setup. Data: docs/data/capability.csv, with the source file of every point.
| Concurrency | TG tok/s, aggregate | TG tok/s, per request | Release, run |
|---|---|---|---|
| 1 | 60.4 ± 3.2 | 56.9 ± 4.1 | v2.2.0, 2026-10-10 |
| 8 | 136.7 ± 3.3 | 22.0 ± 0.5 | v2.2.0, 2026-10-10 |
Release v2.2.0. llama-benchy task mode, ISL/OSL 2048/512, T=1.0, thinking on; mean ± sd, where sd is between runs or between boots as the CSV stat column says for each run.
Shipped release of each setup where measured; the bracket names an older release.
TG, coding c1 (median, n=36, T=0): 1x v2.1.0, 2026-10-10, coding_probe.py, up to 768 tokens out; TP=2 v2.0.0, 2026-10-10, coding_probe.py, up to 768 tokens out; not measured: 2x Spark DP=2.
TG c1, defaults: 1x v2.2.0, 2026-10-10, llama-benchy task mode; TP=2 v2.0.0, 2026-10-10, llama-benchy task mode; DP=2 v2.1.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271.
TG, aggregate c8, defaults: 1x v2.2.0, 2026-10-10, llama-benchy task mode; TP=2 v2.0.0, 2026-10-10, llama-benchy task mode; DP=2 v2.1.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271.
TTFT, ISL 16K, cold prefix: 1x v2.4.0, 2026-10-16, cold.py (k101); TP=2 v2.0.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271; not measured: 2x Spark DP=2.
KV cache: concurrent 262K-token requests: 1x v2.1.0, 2026-10-08, serve log; TP=2 v2.0.0, 2026-10-09, serve log; DP=2 v2.1.0, 2026-10-08, serve log.
TG c1/c8: llama-benchy task mode, ISL/OSL 2048/512, server defaults. KV row: vLLM's 'Maximum concurrency for 262,144 tokens per request' at boot (DP=2: two replicas, one pool each).
Data: docs/data/capability.csv, with the source file of every point.
Agent replay, one boot per layout: two-Spark v1.5.0 (old name b1.6) (TP=2); DP=2 on one-Spark v2.1.0 (old name v3e) (DP=2).
All sessions start at once; each turn resends the full conversation (prefix cache on), tools on, T=0.6, thinking off.
2x Spark TP=2: two-Spark v1.5.0 (old name b1.6), 2026-10-08, agent replay (drive.py), one boot
2x Spark DP=2: DP=2 on one-Spark v2.1.0 (old name v3e), 2026-10-08, agent replay (drive.py), one boot
Data: docs/data/capability.csv, with the source file of every point.
| Check | Result | Criterion |
|---|---|---|
| Hardmode | 92/100 | score /100, pass ≥ 88 (88 scenarios), T=0, thinking on |
| TC-45 | 100/100 | regression test (1 scenario, 2 pts, 5 trials) |
| Fidelity | 20/20 | 20 needles retrieved via tool calls, ISL 8K to ~245K |
| Stragglers | none | no stalled request at c7-c16 (max_num_seqs 8, rest queued) |
Gate run: release v2.4.0, 2026-10-16. Every release passes this gate before promotion.
Full gate tables: docs/BENCHMARKS.md.
Each release's own promotion run and gate.
TG: llama-benchy task mode, ISL/OSL 2048/512, T=1.0, thinking on, from each release's own first run (usually its promotion A/B; the runs line below names each), unpaired across releases, so day-to-day drift is included; paired A/B per release in VERSIONS.md.
TG runs: v1.0.0 2026-10-02, v1.1.0 2026-10-04, v1.2.0 2026-10-04, v1.3.0 2026-10-05, v2.0.0 2026-10-05 (llama-benchy task mode, mean ± sd over 3 runs, one boot); v2.1.0 2026-10-08 (llama-benchy task mode, mean ± sd over runs, one boot); v2.2.0 2026-10-10 (llama-benchy task mode, mean of 6 boots, sd between boots).
Hardmode: promotion gate of each release (b0: gate on the pinned checkpoint), v1.1.0 2026-10-04, v1.2.0 2026-10-04, v1.3.0 2026-10-05, v2.0.0 2026-10-05, v2.1.0 2026-10-07, v2.2.0 2026-10-09, v2.3.0 2026-10-13, v2.4.0 2026-10-16; v1.0.0: score not in the data.
Data: docs/data/capability.csv, with the source file of every point.
VLLM_PLE_MMAP=1), WILLNEED before each TG
gather, 50 ms NVMe keepalive; ~72 GiB of other weights stay resident.reasoning_effort medium, tool calling, max_model_len 262,144.The shipped releases were measured as a full grid in k76 on 2026-10-10
(tp-2 #128); where a cell has no k76
value, the table shows the newest release that has one.
TG rows are aggregate unless marked "per request"; sampling is the server default (temperature 1.0,
thinking on) unless the run says otherwise. The charts and tables are written by
uv run scripts/make_charts.py from docs/data/capability.csv, where every point lists
its raw file (1x: paths are in this repo, 2x: paths in the
two-Spark repo). Full grids for every build:
docs/BENCHMARKS.md.
| 1x Spark | 2x Spark TP=2 | 2x Spark DP=2 | |
|---|---|---|---|
| TG c1, tok/s | 60.4 a | 88.7 b | 57.5 c |
| TG c4, tok/s: per request / aggregate | 32.4 d / 111.4 d | 48.6 b / 156.6 b | 43.4 c / 137.5 c |
| TG c8, tok/s: per request / aggregate | 22.0 d / 136.7 a | 33.2 b / 172.2 b | 32.5 c / 203.6 c |
| TG c16, tok/s: per request / aggregate | > max_num_seqs 8 | 22.1 b / 231.3 b | 21.7 c / 240.9 c |
| TG, coding c1 (36 prompts), tok/s median: T=0 / defaults | 77 e / 61 e | 119 f / 92 f | not measured |
| Copy-heavy (MTP acceptance near 1), aggregate tok/s c1 / c4 / c8, mean | 80.8 g / 183.5 g / 274.1 g | 120.5 h / 303.5 h / 453.4 h | not measured |
| PP tok/s, ISL 2K / 16K / 64K / 128K, c1 | 1,916 i / 2,306 j / 2,133 j / 1,872 j | 2,809 b / 2,913 b / 2,651 b / 2,362 b | not measured |
| TTFT s, ISL 2K / 16K / 64K / 128K, cold prefix | 1.1 i / 7.1 j / 30.7 j / 70.0 j | 0.7 b / 5.6 b / 24.8 b / 55.5 b | not measured |
| ITL p50, ms, c1 / c8 (MTP emits several tokens per step) | 19 k / 47 k | 13 l / 31 l | 19 m / 48 m |
| Stream chunk gap p50, ms, c1 / c8 | 56 n / 143 n | 41 o / 90 o | not measured |
| TG aggregate tok/s, depth 0 → 64K, c1 / c4 | 56.9 d → 55.6 d / 111.4 d → 98.4 d | 88.7 b → 82.8 b / 156.6 b → 104.3 b | 57.5 c → – / 137.5 c → – |
| max_model_len | 262,144 (recipe) | 262,144 (recipe) | 262,144 (recipe) |
| KV cache, tokens | 993,754 p | 3,525,633 q | 1,987,508 r |
| Concurrent 262K requests in KV (vLLM count) | 3.79 s | 13.46 t | 2 × 3.79 u |
| Requests that fit KV at 16K / 64K / 128K | 39.7 v / 14.1 v / 7.5 v | not measured | not measured |
| Gate: hardmode / TC-45 / fidelity to ~245K / stragglers | 92 w / 100 w / 20/20 w / none, c7-c16 w | 90 x / 100 x / 20/20 x / none, c8-c16 x | 93 y / 100 y / 20/20 y / none, c5-c16 y |
Releases and runs behind the numbers:
| Hardware | One DGX Spark (GB10, 128 GB unified); checkpoint on local NVMe (the PLE table is read through the page cache) |
| Launcher | sparkrun ≥ 0.3.6 |
| Disk | ~135 GB (97.7 GiB checkpoint + 2.6 GiB MXFP8 shard + 28.4 GB image) |
| Kernel | No NCCL at TP=1, so the 7.0.0-1019-nvidia NCCL regression of the two-Spark recipe does not apply |
| Boot | ~3 min (171 s) with the compile cache from the image and a warm page cache, once the checkpoint is downloaded |
| Concurrency | max_num_seqs 8, KV pool 14 GiB (993,754 tokens, 3.79x at 262,144) |
Checkpoint: ursuciprian/Qwen3.8-Flash-Next-NVFP4-GDN-MSE
@ 03f4a057 (v2.2.0, drafter D3; v2.1.0: 16c9bd54, drafter D1). It is the NVFP4 checkpoint
local-inference-lab/Qwen3.8-Flash-Next-NVFP4
@ 7c4f1bc1 with the GDN projections in weight-only NVFP4 and, since 16c9bd54, a retrained MTP drafter. Coming
from 16c9bd54, only model-00034-of-00036.safetensors (4.5 GB) is new. Its model
card covers what changed, how it was built and the license (Qwen Community License 1.0). The recipe also fetches
shard 35 and the index of 7c4f1bc1 (2.6 GiB) for the MXFP8 PP copy. Image and video input are not tested.
VLLM_CACHE_ROOT): their torch AOT keys are the same and the artifacts are not. The first boot of each copies the
AOT seed from its own image; the b12x plan cache is shared.max_num_seqs 32 run (quality gate not run at that cap, v2.0.0) reached 189.3 tok/s aggregate TG
at c32 (llama-benchy task mode, mean of 3 runs); a boot at max_num_seqs 16 was stopped by the 4 GiB memory guard
(high concurrency).| Recipe | Release | Image | Use |
|---|---|---|---|
qwen3.8-flash-next-1x-dgx-spark | v2.4.0 | k106s-20261017-a1ad1b69-5dad364d-10d0acc8-warm (also 1x-v2.4.0) | Default (checkpoint @ 03f4a057, drafter D3, b12x a1ad1b69 with the HC down projection BF16 path, GDN prefill views) |
qwen3.8-flash-next-1x-dgx-spark-previous | v2.3.0 | k95-20261013-b45fe867-5dad364d-warm (also 1x-v2.3.0) | Rollback (checkpoint @ 03f4a057, drafter D3, b12x tile fix b45fe867) |
Each recipe's header lists every change since the first release with its measured delta. Earlier recipes: archive/recipes/. Renames: recipes/RENAMES.md.
Releases use semantic versions per repo; VERSIONS.md lists every shipped release with its old build name, date, what changed, its measured delta and its manifest (image digest, vLLM and b12x commits, checkpoint, drafter, plan seed). Each release's own A/B against the one before it is in the release history and in docs/BENCHMARKS.md. Arms that were screened and not promoted: results/README.md.
scripts/arm_verdict.py).Index of every run and verdict: results/README.md. The issue history up to 2026-10-08 is in the tp-2 repo; open single-Spark issues are here.
VLLM_PLE_MMAP=1), with a
WILLNEED pass before each TG gather and a 50 ms NVMe keepalive, so ~72 GiB of other weights fit on one GB10.docker/b0-warm/).tools/mtp_refit/).Every flag and environment variable, with the reason for it, is in the recipe header. Engine-wide configuration, image provenance and rejected experiments shared with the two-Spark recipe: REFERENCE.md and ENGINEERING.md in the tp-2 repo.
The recipe sets the server default to reasoning_effort: medium. On my DevOps task set (two Sparks), b1.2 at the
template default xhigh passed 42.5% of checks with 23/42 runaway-thinking runs and a 246 s median per task; b1.4 at
medium passed 95.9% with 0/42 runaway and 33 s. A request can still ask for xhigh or low;
"reasoning_effort": "none" turns thinking off. For hard reasoning problems xhigh per request helps: on the
hotel-lights check, v3c (old name) went from 21/32 at medium to 31/31 completed runs; allow a long client timeout, since most
of those answers took over 30 minutes at 8 concurrent requests. Override table:
REFERENCE.md.
| Symptom | Fix |
|---|---|
/health silent for minutes | Expected on a cold boot. sparkrun logs qwen3.8-flash-next-1x-dgx-spark -f |
| OOM / earlyoom at first boot | Plan seed not used, so it autotunes; see Known limits above |
Recipe ... matches multiple registries | Both this registry and the tp-2 one are added; use @qwen38-flashnext-1x/qwen3.8-flash-next-1x-dgx-spark |
| Garbled output | Checkpoint mismatch: the serve log must show the pinned snapshots/03f4a057... (or 16c9bd54... for -previous) |
Empty content, long reasoning | max_tokens ran out during thinking; raise it or send "reasoning_effort": "low" |
| Old release boots after an upgrade | sparkrun registry update qwen38-flashnext-1x |
| Anything else | Try the -previous recipe, then open an issue with sparkrun logs <recipe> -a |
| VERSIONS.md | Release names, old build names, manifests |
| docs/BENCHMARKS.md | Full benchmark and quality tables for every build, method, history |
| docs/THUNDERDOME.md | The screen every candidate build runs |
| results/ | Every raw measurement and verdict |
| archive/ | Superseded recipes (not listed by sparkrun) |
| tools/mtp_refit/ | MTP drafter refit pipeline behind v2.1.0 (D1) and v2.2.0 (D3) |
This build stands on these projects:
Apache-2.0, see LICENSE. The vLLM overlays under archive/mods/ keep their upstream Apache-2.0 headers.
Model weights are not part of this repo and keep their own license (Qwen Community License 1.0; see the checkpoint's
model card).
Qwen3.8-Flash-Next NVFP4 on one DGX Spark (TP=1): vLLM V2 + b12x, 4-token MTP, sparkrun recipe, measured throughput and a quality gate
See the code
sparkrun recipe: Qwen3.8-Flash-Next (NVFP4 / MXFP8, MTP ×4) on 1x DGX Spark.
vLLM with b12x GB10 kernels, PLE table paged from NVMe, OpenAI-compatible endpoint, quality-gated releases.
60 / 75 tok/sTG c1defaults (ISL/OSL 2048/512), v2.2.0 / T=0, thinking off (coding), v2.2.0 | 137 / 192 tok/sTG aggregate c8defaults (ISL/OSL 2048/512), v2.2.0 / T=0, thinking off (coding), v2.2.0 | 92/100Hardmodepass ≥ 88, T=0, thinking on | 7.1 sTTFT, ISL 16Kc1, cold prefix |
262K context, max_num_seqs 8, MTP ×4, OpenAI-compatible API, quality-gated releases
GPU power, GPU only (nvidia-smi), not wall power: idle 9.7 W, c1 24.2 W, c8 28.9 W; TG per GPU watt 2.49 (c1) and 4.73 (c8) tok/s/W at server defaults.
TG cells: server defaults (ISL/OSL 2048/512, T=1.0, thinking on) first, T=0 coding (36 prompts, thinking off) second, both aggregate output tok/s. Means over 6 boots where measured; sd between boots in the details. Release v2.2.0.
| Metric | Mean | sd between boots | Boots | Workload | Sampling | Release (date) | Source |
|---|---|---|---|---|---|---|---|
| TG c1, defaults | 60.4 tok/s | 3.22 | 6 | llama-benchy task mode, ISL/OSL 2048/512 | T=1.0, top-p 0.95, top-k 20, thinking on | v2.2.0 (2026-10-10) | results |
| TG c1, coding | 74.9 tok/s | 0.31 | 6 | 36 prompts, OSL ≤768, aggregate output tok/s per pass | T=0, thinking off | v2.2.0 (2026-10-10) | results |
| TG c1, coding, per-prompt median | 77.0 tok/s | – | 1 | 36 prompts (Python, C++, Rust, Go), OSL ≤768, median over prompts | T=0, thinking off | v2.1.0 (2026-10-10) | results |
| TG c1, coding, defaults, per-prompt median | 60.9 tok/s | – | 1 | 36 prompts, OSL ≤768; 198/216 requests hit the 768-token cap inside thinking | server defaults, thinking on | v2.1.0 (2026-10-10) | results |
| TG aggregate c8, defaults | 136.7 tok/s | 3.30 | 6 | llama-benchy task mode, ISL/OSL 2048/512 | T=1.0, top-p 0.95, top-k 20, thinking on | v2.2.0 (2026-10-10) | results |
| TG aggregate c8, coding | 192.0 tok/s | 1.02 | 6 | 36 prompts, OSL ≤768, aggregate output tok/s per pass | T=0, thinking off | v2.2.0 (2026-10-10) | results |
| TTFT, ISL 16K | 7.10 s | 0.02 | 4 | c1, cold prefix | – | v2.4.0 (2026-10-16) | results |
| Hardmode | 92/100 | – | 1 | 88 multi-step tool-use scenarios; pass ≥ 88 | T=0, thinking on | v2.4.0 (2026-10-16) | results |
| GPU power, idle | 9.7 W | – | 6 | server up, no requests, 120 s | – | v2.2.0 (2026-10-10) | results |
| GPU power, TG c1 defaults | 24.2 W | – | 6 | power.draw, GPU only (nvidia-smi), not wall power, mean over the cell | T=1.0, top-p 0.95, top-k 20, thinking on | v2.2.0 (2026-10-10) | results |
| TG per GPU watt, c1 defaults | 2.49 tok/s/W | – | 6 | TG aggregate / GPU W | T=1.0, top-p 0.95, top-k 20, thinking on | v2.2.0 (2026-10-10) | results |
| GPU power, TG c8 defaults | 28.9 W | – | 6 | power.draw, GPU only (nvidia-smi), not wall power, mean over the cell | T=1.0, top-p 0.95, top-k 20, thinking on | v2.2.0 (2026-10-10) | results |
| TG per GPU watt, c8 defaults | 4.73 tok/s/W | – | 6 | TG aggregate / GPU W | T=1.0, top-p 0.95, top-k 20, thinking on | v2.2.0 (2026-10-10) | results |
Method and full tables: docs/BENCHMARKS.md.
Requirements:
<spark> = hostname or IP; --solo = single
node.sparkrun registry add https://github.com/ursuciprian/qwen3.8-flash-next-1x-dgx-spark
sparkrun run qwen3.8-flash-next-1x-dgx-spark --hosts <spark> --solo
First run downloads ~135 GB (a fresh checkpoint download took 3 h 15 min at ~8.6 MB/s on my link; on a slow link,
pre-fetch it, see below). Boot with model and image on disk: 256 s on the v2.4.0 image check, with the plan file and the
compile cache coming from the image (171 s on v2.1.0 with a warm page cache); a cold-page-cache boot was not timed. sparkrun run returns before the engine is ready: poll http://<spark>:8000/health, then use
http://<spark>:8000/v1, model qwen3.8-flash-next:
curl http://<spark>:8000/v1/chat/completions -H 'Content-Type: application/json' \
-d '{"model": "qwen3.8-flash-next", "messages": [{"role": "user", "content": "Hello"}]}'
No API key: keep it on a trusted network or put an authenticating proxy in front.
Multi-user setups. I set this recipe up for a single user. --enable-prompt-tokens-details (since v2.3.0) makes the usage field report prompt_tokens_details.cached_tokens exactly, so on a server shared by several users or tenants one user can tell whether someone else already sent the same prompt prefix. Prefix caching already leaks this through time to first token; the flag makes it exact. With several users or tenants, give each one its own random, secret cache_salt in the request body (the pinned vLLM accepts it on /v1/chat/completions, /v1/completions and /v1/responses; a gateway can set it per API key), so their prefix-cache entries never match each other. Otherwise, remove --enable-prompt-tokens-details from the recipe.
The recipe serves its own checkpoint, about 98 GB. A fresh download took about 3 h 15 min on my link (~8.6 MB/s). Download it on the Spark before the first boot, together with the two files of the base checkpoint that the recipe uses for PP (2.6 GiB):
hf download ursuciprian/Qwen3.8-Flash-Next-NVFP4-GDN-MSE --revision 03f4a0570496bbe741189f4a2a7d611679e85406
hf download local-inference-lab/Qwen3.8-Flash-Next-NVFP4 --revision 7c4f1bc1a2d6847e0cbc01ac6b823f00251de8dd \
model-00035-of-00036.safetensors model.safetensors.index.json
sparkrun run returns before the engine is ready. Wait for health, then check that the reply has both reasoning and
an answer:
H=http://<spark>:8000
until [ "$(curl -s -o /dev/null -w '%{http_code}' $H/health)" = 200 ]; do sleep 10; done
curl -s $H/v1/chat/completions -H 'Content-Type: application/json' -d '{
"model":"qwen3.8-flash-next","max_tokens":1024,
"messages":[{"role":"user","content":"Write a Python function that reverses a string."}]}' \
| python3 -c "import json,sys; m=json.load(sys.stdin)['choices'][0]['message']
print('reasoning:', len(m.get('reasoning') or m.get('reasoning_content') or ''), 'chars')
print('content :', (m.get('content') or '')[:300])"
Empty content with long reasoning means max_tokens ran out inside thinking; garbled text means a checkpoint
mismatch (see Troubleshooting under Details below). Optional long-context check (stdlib Python), expect exact 20 at
both depths:
git clone https://github.com/ursuciprian/qwen3.8-flash-next-1x-dgx-spark && cd qwen3.8-flash-next-1x-dgx-spark
python3 scripts/fidelity_probe.py --base $H --model qwen3.8-flash-next --depths 8000,32000
The server binds 0.0.0.0 with no API key: keep it on a trusted network or put a proxy with auth in front. Stop with
sparkrun stop --all. To upgrade, run sparkrun registry update qwen38-flashnext-1x first: sparkrun caches
registries and does not refresh them on run.
Moved here on 2026-10-08 from qwen3.8-flash-next-dgx-spark-tp-2, which keeps a copy of this recipe so existing
sparkrun runsetups keep working. If both registries are added, pick this one withsparkrun run @qwen38-flashnext-1x/qwen3.8-flash-next-1x-dgx-spark --hosts <spark> --solo.
| Model | ursuciprian/Qwen3.8-Flash-Next-NVFP4-GDN-MSE @ 03f4a057: NVFP4 experts, MXFP8 dense and attention, GDN projections NVFP4 for TG and MXFP8 for PP |
| MTP | MTP ×4, probabilistic drafts, rejection sampling; drafter D3 refit on the served model's outputs (v2.1.0: D1) |
| Hardware | 1x DGX Spark (GB10, 128 GB unified), checkpoint on local NVMe |
| Parallelism / memory | TP=1; 26.8 GiB PLE table paged from NVMe (VLLM_PLE_MMAP=1), 14 GiB KV pool |
| Engine | vLLM + b12x (NVFP4 MoE, MXFP8 linears, GDN, QSA), plan and compile caches baked into the image |
| Context | 262,144 tokens (max_model_len) |
| Concurrent requests | up to 8 (max_num_seqs) |
| KV cache | 993,754 tokens, 3.79 concurrent 262K requests (v2.1.0 boot log) |
| API | OpenAI-compatible, tool calling, reasoning on (reasoning_effort medium); usage.prompt_tokens_details.cached_tokens reports prefix-cache hits |
| Disk / start time | ~135 GB / ~3 min warm (256 s on the v2.4.0 image check) |
| License | Recipe Apache-2.0; weights Qwen Community License 1.0 |
| Task | Section |
|---|---|
| TG, PP, TTFT, context depth | Performance |
| Sizing: 1x vs TP=2 vs DP=2 | 1x vs 2x TP=2 vs 2x DP=2 |
| Quality gate results | Quality gate |
| Raw data and provenance per number | Every number and where it comes from |
| Pin or roll back a release | Recipes, VERSIONS.md |
Aggregate TG scales to c8 while per-request TG drops. TTFT grows with ISL on a cold prefix; multi-turn requests hit the prefix cache and run PP only on the new tokens.
Left: 1x Spark v2.1.0, 2x Spark TP=2 v2.0.0, 2x Spark DP=2 v2.1.0; llama-benchy task mode. Right: 1x Spark v2.4.0, 2x Spark TP=2 v2.0.0/v1.4.0; c1, cold prefix.
Left: llama-benchy task mode (agent coding turn), ISL/OSL 2048/512, T=1.0, top-p 0.95, top-k 20, thinking on, prefix caching. Aggregate = all output tokens / wall time, PP included; per request = TG rate of one stream after its first token.
1x Spark: release v2.1.0, 2026-10-08, llama-benchy task mode, mean ± sd over runs, one boot
2x Spark TP=2: release v2.0.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271, mean ± sd of 3 runs, one boot
2x Spark DP=2: release v2.1.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271, mean ± sd of 3 runs, one boot
Versions are numbered per setup. Data: docs/data/capability.csv, with the source file of every point.
Right: c1, cold prefix (no cache hit). Each point: mean of 1 to 4 samples of one run (n per point in the CSV).
1x Spark: release v2.4.0, 2026-10-16, cold.py (k101)
2x Spark TP=2: release v2.0.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271; v1.4.0, 2026-10-07, fidelity_probe.py
1x Spark: not measured above 128K yet.
Data: docs/data/capability.csv, with the source file of every point.
Left: 1x Spark v2.4.0, 2x Spark TP=2 v2.0.0; c1, cold prefix. Right: 1x Spark v2.1.0; llama-benchy, ISL/OSL 2048/512 at depth.
Left: c1, cold prefix (no cache hit). Each point: mean of 1 to 4 samples of one run (n per point in the CSV).
1x Spark: release v2.4.0, 2026-10-16, cold.py (k101)
2x Spark TP=2: release v2.0.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271
Data: docs/data/capability.csv, with the source file of every point.
Right: 1x Spark: release v2.1.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271, mean ± sd of 2 Sparks x 3 runs, one boot each (older release; shipped v2.4.0 not measured on this test yet). Server default sampling. Each point: ISL/OSL 2048/512 on top of the cached context, same harness as the concurrency chart. Concurrency levels measured at one depth only are left out.
Data: docs/data/capability.csv, with the source file of every point.
1x Spark v2.1.0, 2x Spark TP=2 v2.0.0, 2x Spark DP=2 v2.1.0; llama-benchy task mode.
llama-benchy task mode (agent coding turn), ISL/OSL 2048/512, T=1.0, top-p 0.95, top-k 20, thinking on, prefix caching. Aggregate = all output tokens / wall time, PP included; per request = TG rate of one stream after its first token.
1x Spark: release v2.1.0, 2026-10-08, llama-benchy task mode, mean ± sd over runs, one boot
2x Spark TP=2: release v2.0.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271, mean ± sd of 3 runs, one boot
2x Spark DP=2: release v2.1.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271, mean ± sd of 3 runs, one boot
Versions are numbered per setup. Data: docs/data/capability.csv, with the source file of every point.
| Concurrency | TG tok/s, aggregate | TG tok/s, per request | Release, run |
|---|---|---|---|
| 1 | 60.4 ± 3.2 | 56.9 ± 4.1 | v2.2.0, 2026-10-10 |
| 8 | 136.7 ± 3.3 | 22.0 ± 0.5 | v2.2.0, 2026-10-10 |
Release v2.2.0. llama-benchy task mode, ISL/OSL 2048/512, T=1.0, thinking on; mean ± sd, where sd is between runs or between boots as the CSV stat column says for each run.
Shipped release of each setup where measured; the bracket names an older release.
TG, coding c1 (median, n=36, T=0): 1x v2.1.0, 2026-10-10, coding_probe.py, up to 768 tokens out; TP=2 v2.0.0, 2026-10-10, coding_probe.py, up to 768 tokens out; not measured: 2x Spark DP=2.
TG c1, defaults: 1x v2.2.0, 2026-10-10, llama-benchy task mode; TP=2 v2.0.0, 2026-10-10, llama-benchy task mode; DP=2 v2.1.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271.
TG, aggregate c8, defaults: 1x v2.2.0, 2026-10-10, llama-benchy task mode; TP=2 v2.0.0, 2026-10-10, llama-benchy task mode; DP=2 v2.1.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271.
TTFT, ISL 16K, cold prefix: 1x v2.4.0, 2026-10-16, cold.py (k101); TP=2 v2.0.0, 2026-10-10, llama-benchy 0.4.1.dev4+g0d4de4271; not measured: 2x Spark DP=2.
KV cache: concurrent 262K-token requests: 1x v2.1.0, 2026-10-08, serve log; TP=2 v2.0.0, 2026-10-09, serve log; DP=2 v2.1.0, 2026-10-08, serve log.
TG c1/c8: llama-benchy task mode, ISL/OSL 2048/512, server defaults. KV row: vLLM's 'Maximum concurrency for 262,144 tokens per request' at boot (DP=2: two replicas, one pool each).
Data: docs/data/capability.csv, with the source file of every point.
Agent replay, one boot per layout: two-Spark v1.5.0 (old name b1.6) (TP=2); DP=2 on one-Spark v2.1.0 (old name v3e) (DP=2).
All sessions start at once; each turn resends the full conversation (prefix cache on), tools on, T=0.6, thinking off.
2x Spark TP=2: two-Spark v1.5.0 (old name b1.6), 2026-10-08, agent replay (drive.py), one boot
2x Spark DP=2: DP=2 on one-Spark v2.1.0 (old name v3e), 2026-10-08, agent replay (drive.py), one boot
Data: docs/data/capability.csv, with the source file of every point.
| Check | Result | Criterion |
|---|---|---|
| Hardmode | 92/100 | score /100, pass ≥ 88 (88 scenarios), T=0, thinking on |
| TC-45 | 100/100 | regression test (1 scenario, 2 pts, 5 trials) |
| Fidelity | 20/20 | 20 needles retrieved via tool calls, ISL 8K to ~245K |
| Stragglers | none | no stalled request at c7-c16 (max_num_seqs 8, rest queued) |
Gate run: release v2.4.0, 2026-10-16. Every release passes this gate before promotion.
Full gate tables: docs/BENCHMARKS.md.
Each release's own promotion run and gate.
TG: llama-benchy task mode, ISL/OSL 2048/512, T=1.0, thinking on, from each release's own first run (usually its promotion A/B; the runs line below names each), unpaired across releases, so day-to-day drift is included; paired A/B per release in VERSIONS.md.
TG runs: v1.0.0 2026-10-02, v1.1.0 2026-10-04, v1.2.0 2026-10-04, v1.3.0 2026-10-05, v2.0.0 2026-10-05 (llama-benchy task mode, mean ± sd over 3 runs, one boot); v2.1.0 2026-10-08 (llama-benchy task mode, mean ± sd over runs, one boot); v2.2.0 2026-10-10 (llama-benchy task mode, mean of 6 boots, sd between boots).
Hardmode: promotion gate of each release (b0: gate on the pinned checkpoint), v1.1.0 2026-10-04, v1.2.0 2026-10-04, v1.3.0 2026-10-05, v2.0.0 2026-10-05, v2.1.0 2026-10-07, v2.2.0 2026-10-09, v2.3.0 2026-10-13, v2.4.0 2026-10-16; v1.0.0: score not in the data.
Data: docs/data/capability.csv, with the source file of every point.
VLLM_PLE_MMAP=1), WILLNEED before each TG
gather, 50 ms NVMe keepalive; ~72 GiB of other weights stay resident.reasoning_effort medium, tool calling, max_model_len 262,144.The shipped releases were measured as a full grid in k76 on 2026-10-10
(tp-2 #128); where a cell has no k76
value, the table shows the newest release that has one.
TG rows are aggregate unless marked "per request"; sampling is the server default (temperature 1.0,
thinking on) unless the run says otherwise. The charts and tables are written by
uv run scripts/make_charts.py from docs/data/capability.csv, where every point lists
its raw file (1x: paths are in this repo, 2x: paths in the
two-Spark repo). Full grids for every build:
docs/BENCHMARKS.md.
| 1x Spark | 2x Spark TP=2 | 2x Spark DP=2 | |
|---|---|---|---|
| TG c1, tok/s | 60.4 a | 88.7 b | 57.5 c |
| TG c4, tok/s: per request / aggregate | 32.4 d / 111.4 d | 48.6 b / 156.6 b | 43.4 c / 137.5 c |
| TG c8, tok/s: per request / aggregate | 22.0 d / 136.7 a | 33.2 b / 172.2 b | 32.5 c / 203.6 c |
| TG c16, tok/s: per request / aggregate | > max_num_seqs 8 | 22.1 b / 231.3 b | 21.7 c / 240.9 c |
| TG, coding c1 (36 prompts), tok/s median: T=0 / defaults | 77 e / 61 e | 119 f / 92 f | not measured |
| Copy-heavy (MTP acceptance near 1), aggregate tok/s c1 / c4 / c8, mean | 80.8 g / 183.5 g / 274.1 g | 120.5 h / 303.5 h / 453.4 h | not measured |
| PP tok/s, ISL 2K / 16K / 64K / 128K, c1 | 1,916 i / 2,306 j / 2,133 j / 1,872 j | 2,809 b / 2,913 b / 2,651 b / 2,362 b | not measured |
| TTFT s, ISL 2K / 16K / 64K / 128K, cold prefix | 1.1 i / 7.1 j / 30.7 j / 70.0 j | 0.7 b / 5.6 b / 24.8 b / 55.5 b | not measured |
| ITL p50, ms, c1 / c8 (MTP emits several tokens per step) | 19 k / 47 k | 13 l / 31 l | 19 m / 48 m |
| Stream chunk gap p50, ms, c1 / c8 | 56 n / 143 n | 41 o / 90 o | not measured |
| TG aggregate tok/s, depth 0 → 64K, c1 / c4 | 56.9 d → 55.6 d / 111.4 d → 98.4 d | 88.7 b → 82.8 b / 156.6 b → 104.3 b | 57.5 c → – / 137.5 c → – |
| max_model_len | 262,144 (recipe) | 262,144 (recipe) | 262,144 (recipe) |
| KV cache, tokens | 993,754 p | 3,525,633 q | 1,987,508 r |
| Concurrent 262K requests in KV (vLLM count) | 3.79 s | 13.46 t | 2 × 3.79 u |
| Requests that fit KV at 16K / 64K / 128K | 39.7 v / 14.1 v / 7.5 v | not measured | not measured |
| Gate: hardmode / TC-45 / fidelity to ~245K / stragglers | 92 w / 100 w / 20/20 w / none, c7-c16 w | 90 x / 100 x / 20/20 x / none, c8-c16 x | 93 y / 100 y / 20/20 y / none, c5-c16 y |
Releases and runs behind the numbers:
| Hardware | One DGX Spark (GB10, 128 GB unified); checkpoint on local NVMe (the PLE table is read through the page cache) |
| Launcher | sparkrun ≥ 0.3.6 |
| Disk | ~135 GB (97.7 GiB checkpoint + 2.6 GiB MXFP8 shard + 28.4 GB image) |
| Kernel | No NCCL at TP=1, so the 7.0.0-1019-nvidia NCCL regression of the two-Spark recipe does not apply |
| Boot | ~3 min (171 s) with the compile cache from the image and a warm page cache, once the checkpoint is downloaded |
| Concurrency | max_num_seqs 8, KV pool 14 GiB (993,754 tokens, 3.79x at 262,144) |
Checkpoint: ursuciprian/Qwen3.8-Flash-Next-NVFP4-GDN-MSE
@ 03f4a057 (v2.2.0, drafter D3; v2.1.0: 16c9bd54, drafter D1). It is the NVFP4 checkpoint
local-inference-lab/Qwen3.8-Flash-Next-NVFP4
@ 7c4f1bc1 with the GDN projections in weight-only NVFP4 and, since 16c9bd54, a retrained MTP drafter. Coming
from 16c9bd54, only model-00034-of-00036.safetensors (4.5 GB) is new. Its model
card covers what changed, how it was built and the license (Qwen Community License 1.0). The recipe also fetches
shard 35 and the index of 7c4f1bc1 (2.6 GiB) for the MXFP8 PP copy. Image and video input are not tested.
VLLM_CACHE_ROOT): their torch AOT keys are the same and the artifacts are not. The first boot of each copies the
AOT seed from its own image; the b12x plan cache is shared.max_num_seqs 32 run (quality gate not run at that cap, v2.0.0) reached 189.3 tok/s aggregate TG
at c32 (llama-benchy task mode, mean of 3 runs); a boot at max_num_seqs 16 was stopped by the 4 GiB memory guard
(high concurrency).| Recipe | Release | Image | Use |
|---|---|---|---|
qwen3.8-flash-next-1x-dgx-spark | v2.4.0 | k106s-20261017-a1ad1b69-5dad364d-10d0acc8-warm (also 1x-v2.4.0) | Default (checkpoint @ 03f4a057, drafter D3, b12x a1ad1b69 with the HC down projection BF16 path, GDN prefill views) |
qwen3.8-flash-next-1x-dgx-spark-previous | v2.3.0 | k95-20261013-b45fe867-5dad364d-warm (also 1x-v2.3.0) | Rollback (checkpoint @ 03f4a057, drafter D3, b12x tile fix b45fe867) |
Each recipe's header lists every change since the first release with its measured delta. Earlier recipes: archive/recipes/. Renames: recipes/RENAMES.md.
Releases use semantic versions per repo; VERSIONS.md lists every shipped release with its old build name, date, what changed, its measured delta and its manifest (image digest, vLLM and b12x commits, checkpoint, drafter, plan seed). Each release's own A/B against the one before it is in the release history and in docs/BENCHMARKS.md. Arms that were screened and not promoted: results/README.md.
scripts/arm_verdict.py).Index of every run and verdict: results/README.md. The issue history up to 2026-10-08 is in the tp-2 repo; open single-Spark issues are here.
VLLM_PLE_MMAP=1), with a
WILLNEED pass before each TG gather and a 50 ms NVMe keepalive, so ~72 GiB of other weights fit on one GB10.docker/b0-warm/).tools/mtp_refit/).Every flag and environment variable, with the reason for it, is in the recipe header. Engine-wide configuration, image provenance and rejected experiments shared with the two-Spark recipe: REFERENCE.md and ENGINEERING.md in the tp-2 repo.
The recipe sets the server default to reasoning_effort: medium. On my DevOps task set (two Sparks), b1.2 at the
template default xhigh passed 42.5% of checks with 23/42 runaway-thinking runs and a 246 s median per task; b1.4 at
medium passed 95.9% with 0/42 runaway and 33 s. A request can still ask for xhigh or low;
"reasoning_effort": "none" turns thinking off. For hard reasoning problems xhigh per request helps: on the
hotel-lights check, v3c (old name) went from 21/32 at medium to 31/31 completed runs; allow a long client timeout, since most
of those answers took over 30 minutes at 8 concurrent requests. Override table:
REFERENCE.md.
| Symptom | Fix |
|---|---|
/health silent for minutes | Expected on a cold boot. sparkrun logs qwen3.8-flash-next-1x-dgx-spark -f |
| OOM / earlyoom at first boot | Plan seed not used, so it autotunes; see Known limits above |
Recipe ... matches multiple registries | Both this registry and the tp-2 one are added; use @qwen38-flashnext-1x/qwen3.8-flash-next-1x-dgx-spark |
| Garbled output | Checkpoint mismatch: the serve log must show the pinned snapshots/03f4a057... (or 16c9bd54... for -previous) |
Empty content, long reasoning | max_tokens ran out during thinking; raise it or send "reasoning_effort": "low" |
| Old release boots after an upgrade | sparkrun registry update qwen38-flashnext-1x |
| Anything else | Try the -previous recipe, then open an issue with sparkrun logs <recipe> -a |
| VERSIONS.md | Release names, old build names, manifests |
| docs/BENCHMARKS.md | Full benchmark and quality tables for every build, method, history |
| docs/THUNDERDOME.md | The screen every candidate build runs |
| results/ | Every raw measurement and verdict |
| archive/ | Superseded recipes (not listed by sparkrun) |
| tools/mtp_refit/ | MTP drafter refit pipeline behind v2.1.0 (D1) and v2.2.0 (D3) |
This build stands on these projects:
Apache-2.0, see LICENSE. The vLLM overlays under archive/mods/ keep their upstream Apache-2.0 headers.
Model weights are not part of this repo and keep their own license (Qwen Community License 1.0; see the checkpoint's
model card).