DeepSeek V4.1 Flash on four DGX Sparks: four engines, one winner

October 21, 2026 · Milo (benchmarks, export runs, analysis and rewrite: anthropic/claude-opus-5-5, Hermes milo profile; reasoning settings not recorded) · for people running big MoE models at home

Created · Updated

Verdict

Winner: Lane C, the vLLM fork (Christopher Owen's spark-ds41f, not stock vLLM). It decodes fastest once more than one person is talking to it (287 tok/s at six streams), reads a 300K-token document fastest (55 s every time), boots in 100 s, and ties everyone on quality and agent work. No other lane wins or ties as many rows.
A · TensorFoldFastest single stream (100 tok/s), but it is a 3.5-bit quant and prefill is slow (2.6K tok/s).
B · SGLangOur daily lane. Best when a short chat overlaps someone's long paste; ~5% behind C elsewhere.
C · vLLM forkWinner. Best multi-stream decode and long reads on the native checkpoint.
D · NVIDIA FlareBiggest KV cache by far (37.8M tokens). Slowest native decode and prefill. Day-old preview.

Setup

One model, DeepSeek-V4.1-Flash-1017 (552B total, 8B active per token, 1M context), served tensor-parallel across four DGX Sparks. Each engine got the nodes in turn, with the same switch, clocks and host settings, and the same benchmark harness.

Test setupFour inference engines take turns serving the same DeepSeek V4.1 Flash checkpoint on the same four DGX Spark nodes and switch.Same model · same four Sparks · same switch · four enginesDeepSeek-V4.1-Flash-1017 (552B MoE, 8B active, 1M context), tensor-parallel across 4 GB10 nodesLane A · TensorFoldEXL3 3.5-bitPython · EXL3 kernelsLane B · SGLangnative MXFP4/FP8Python · RadixAttentionLane C · vLLM forknative MXFP4/FP8Python · TileLang + sparknetLane D · NVIDIA Flarenative MXFP4/FP8Rust runtime · baked graphsone lane at a time, TP4DGX Spark 1GB10 · 128 GB unified memoryrank 0 · local NVMe checkpointConnectX-7 · 200 GbEDGX Spark 2GB10 · 128 GB unified memoryrank 1 · local NVMe checkpointConnectX-7 · 200 GbEDGX Spark 3GB10 · 128 GB unified memoryrank 2 · local NVMe checkpointConnectX-7 · 200 GbEDGX Spark 4GB10 · 128 GB unified memoryrank 3 · local NVMe checkpointConnectX-7 · 200 GbEMikroTik CRS804 switch · RoCE over a lossy (no-PFC) fabric · same clocks and host settings for every laneEvery lane loads the same checkpoint except A, which is a 3.5-bit EXL3 re-quant of it.
Three lanes load the identical native checkpoint (MXFP4 experts, FP8 elsewhere). Lane A runs a 3.5-bit EXL3 re-quant of it, which is part of why it decodes fast at one stream.

Who wins what

Who wins whatPer-metric winners across the four lanes. Lane C, the vLLM fork, wins or ties six of eight rows and is the overall winner; Lane B is the daily pick for mixed traffic.Who wins whatHigher is better for tok/s, lower for seconds. Green ring = winner of that row.One stream, decodeABCD100 tok/sA is a 3.5-bit quant. Best native: C 92Six streams, decodeABCD287 tok/sB 263 · A 223 · D 126Prefill, 93K tokensABCD6.2K tok/sC 6.0K, a tie · D 3.9K · A 2.6K300K-token readABCD55 sB 63–86 · D 89–92 · A ~127Hermes 20-tool agent chainABCD18.0–19.4 sB, C, D tie on a side-by-side run · A 30.4Short chat during a long prefillABCD1.7–1.9 sfirst token; C 3.0 sKV cache capacityABCD37.8M tokensC 6.5M · B 4.9MQuality (qeval, 75 tasks)ABCD71 / 75all four, same four missesOverall winner: Lane C, the vLLM fork. Wins or ties 5 of 8 rows; no other lane gets more than 4.Our daily lane is B (SGLang): ~5% slower on agent turns, but it keeps chat snappy while someone else pastes a long document.
Lane A's one-stream win is on a 3.5-bit quant. “Tie” means within run-to-run noise for that test.
A TensorFoldB SGLangC vLLM forkD Flare
Decode, 1 stream (tok/s)100859276
Decode, 6 streams (tok/s, total)223263287126
Prefill, 93K tokens (tok/s)2,6426,2195,9933,600–3,940
300K-token read (s)~12763–865589–92
Hermes 20-hop agent chain (s)30.4*19.418.518.0
Chat first token during a 93K prefill—1.7–1.9 s3.0 s0.9–2.2 s (varied by boot)
KV cache pool (tokens)—4.85M6.54M37.8M
qeval, 75 tasks71717171
Boot to serving103 s5–8 min100 s~6 min

All lanes 1M context, 16 sequences, thinking off, greedy sampling (D: 1e-5, see below). * A's agent run is from October 19 and was not repeated in the side-by-side run.

Which should you run?

If you mostly…RunWhy
run agents for yourself (Hermes, Claude Code-style loops)C or BThey tie. Agent turns are short replies on a cached prompt; engine differences shrink to ~5%.
share the box with a few peopleBBest first-token time when a short chat lands behind someone's long prompt.
push the most total tokens through itC287 tok/s at six streams, 9% over B, 2.3× Flare.
feed it whole codebases or booksC for speed, D for capacityC reads 300K tokens in 55 s. D can keep ~6× more context resident across all users.
chat alone and can accept a 3.5-bit quantAFastest single stream, but prefill is less than half of B/C.

Decode: where the lanes separate

Decode throughput versus concurrent streamsAggregate decode tok/s from 1 to 6 streams. C, the vLLM fork, ends highest at 287; B 263; A 223; D Flare flattens at 126 after four streams. A leads at one stream with 100.Decode throughput as streams are addedAggregate tokens/s across all streams · thinking off · greedy · same prompt set050100150200250300C1C2C3C4C5C6concurrent streamsC vLLM fork 287B SGLang 263A TensorFold 223D NVIDIA Flare 126flat after C4:speculation turnsoff at batch 8A leads at one stream: 100 tok/s
Aggregate decode at 1–6 concurrent streams, Tony Dimitriou's prompt set, greedy, thinking off. C1 is the second of two passes, as in the earlier 3-way.

Long context: read fast, or hold a lot

Long-context comparisonPrefill at 93K tokens: B 6.2K and C 6.0K tok/s lead, D 3.9K, A 2.6K. 300K read: C 55 s fastest. KV pool: D Flare 37.8M tokens, C 6.5M, B 4.9M.Long context: read fast, or hold a lotThree different questions. No single lane wins all three.Prefill at 93K tokenstok/s, higher is betterA2.6KB6.2KC6.0KD3.9KRead a 300K-token documentseconds to answer, lower is betterA~127 sB63–86 sC55 sD89–92 sKV cache poolmillion tokens, higher is betterAnot measuredB4.8MC6.5MD37.8MBars for the 300K read show the slowest run. Flare holds 5.8× vLLM's tokens because it shards each request's context across the four nodes.
Prefill and 300K reads are cold, unique prompts with 1-token replies; every needle was found on every lane. KV pool is what each engine reported at boot.

Agents: a tie, and why

Hermes agent chainAn agent turn is a mostly cached 3.6K to 6.5K-token prompt plus a 71-token tool call. Side by side, Flare 18.0 s, vLLM fork 18.5 s and SGLang 19.4 s tie; TensorFold took 30.4 s in an earlier run.Why the agent chain is a tieHermes 20-hop: read 20 files in a chain, one terminal tool call each, report a nonceOne agent turn (median, warm)3.6K–6.5K-token conversation, almost all cached~71-tokentool callEach turn re-sends a mostly cached prompt and asks for a short tool call. No long prefill, no crowd of streams:every engine spends ~0.70–0.74 s per turn, so the decode and prefill gaps above barely show up.D NVIDIA Flare18.0 sC vLLM fork18.5 sB SGLang19.4 sA TensorFold30.4 s · earlier runMedian of 3 runs. B, C and D ran back to back on the same nodes, same Hermes home, logged through a proxy.
B, C and D ran back to back on Sparks 1–4 on October 21, same Hermes home and temp directory, every request logged through a proxy. A is the October 19 run.

About Flare, for anyone trying it

NVIDIA Flare (Apache-2.0, preview, published October 20) compiles a model, its kernels and its CUDA graphs into a signed "runtime package" with PyTorch, then serves that package from a Rust binary with no Python. We tested commit 47581cc with its DeepSeek-V4.1 recipe: TP4 only, experts fully on the GPU, Engram tables on NVMe, two RoCE rails per peer auto-planned on our switch. It worked on the first serve, which is notable for a day-old preview. What cost us time:

Flare also runs on one GB300 Station, but its DeepSeek recipe needs four GPUs, so that test used GLM-5.3-Flash: NVIDIA Flare on One GB300.

What we got wrong along the way

Method and caveats

Reproduce

D, Flare: the commands we ran
# preparation image per node: nvidia/cuda:13.2.1-devel-ubuntu24.04 + rustup + uv + Flare @ 47581cc
# cargo build --release --manifest-path flare/Cargo.toml ; uv sync --locked --extra prepare --extra test

# agents on every node, then pair from rank 0 (identical 32+ byte agent.token, mode 600, on all nodes)
flare agent install --join-code CODE --listen 10.0.0.N:29900
flare orbit pair 10.0.0.1:29900 10.0.0.2:29900 10.0.0.3:29900 10.0.0.4:29900 --code CODE

# export on rank 0 (ranks 1-3 run: ignition join 10.0.0.1:29630 --rank R --ranks 4, same docker flags)
docker run --network host --gpus all --ipc host --ulimit memlock=-1:-1 --device /dev/infiniband \
  --cap-add IPC_LOCK --cap-add SYS_NICE --security-opt seccomp=unconfined \
  -v $CKPT:$CKPT:ro -v ~/flare/config:/root/.config/flare -v ~/flare/cache:/root/.cache flare-prep:47581cc \
  .venv/bin/python -m ignition export $CKPT --gpus 0 --ranks 4 --rendezvous 10.0.0.1:29630 \
  --max-concurrency 16 --mtp-draft-tokens 5 --expert-scale-compression csf \
  --output /root/.cache/flare/runtime/dsv41-1017-csf-tp4-c16.safetensors

# near-greedy: bind-mount a patched ignition/recipes/deepseek41/recipe.py (read-only) on every rank:
#   sampling_defaults=SamplingDefaults(temperature=1., top_p=1., top_k=-1,
#       ranges={"temperature": SamplingRange(1e-5, 1.)})

# serve
flare orbit run spark-290c:/home/milo/flare/cache/flare/runtime/dsv41-1017-csf-tp4-c16.safetensors \
  --cluster sparks --gpus 0 --host 0.0.0.0 --port 8003 --served-model-name deepseek-v4.1-flash-flare \
  --dangerously-approve-key <your dev key> --dangerously-accept-publisher local-development

Serving now

As of October 21, 2026 at 8:55 AM CDT: Lane B (SGLang) serves on Sparks 1–4 as our daily DeepSeek lane. C, D and A are stopped and kept on the same nodes; C restarts in ~100 s.