· James Meadlock & Milo · Funland dual DGX Spark · updated after opt forensics + restore

DS4-F Flash-0731 on a Dual DGX Spark Pair (Recipe)

Official deepseek-ai/DeepSeek-V4-Flash-0731 is the GA Flash weight drop (same structure as DSpark, speculative module attached). Mia (@MiaAI_lab) flagged the HF release the same day it landed — that heads-up is why this pair moved quickly. This Funland recipe runs those weights on two NVIDIA DGX Sparks (GB10) using the dual-Spark Anemll path Mia / MiaAI-Lab and Anemll made practical for GB10 (our 1M/6 writeup): download once, rsync once, RoCE TP=2, Hermes-ready OpenAI API on :8888.

Current call on this pair: PROMOTE 0731 as the production DS4-F lane.
Keys short-gen is a few percent slower than healthy DSpark preview weights. We still switched: agent/tool quality on the official weights is the higher priority for daily Hermes work. DSpark remains the one-command rollback.
Live model0731
RuntimeAnemll 1M/6
Context1,048,576
Keys C168.9 t/s
DSpark C1 ref72.4 t/s
HermesROUTE_OK
Same-day update (July 31, afternoon CDT): post-promote forensics + ranked optimization pass, then a cold-128k probe hard-wedged Spark1 (power-cycle). Restored Anemll 0731 with full gates (RESTORE_0731_OK, tools, Hermes ROUTE_OK, KV 2,214,807). Do not treat Keys C1 as IQ; do not jump to official K=7 — checkpoint dspark_block_size=5.
KV after restore2.21M
dspark_block_size5
Cold needle~50k HIT
128k coldhost wedge
K=7 canary40K lane
SGLang dual-GB10PARK

What you get

Prerequisites

ItemFunland value / notes
Hardware2× DGX Spark (GB10), ~128 GB unified memory each
InterconnectRoCE/IB dual HCA + bonded Ethernet for Gloo/TP sockets
Disk~160+ GiB free per node for 0731; keep DSpark (~156 GiB) if you want rollback
DockerCompose + NVIDIA container runtime, network_mode: host, ipc: host
Imageghcr.io/anemll/dspark-vllm-gx10:0.1.1
Weightsdeepseek-ai/DeepSeek-V4-Flash-0731 (rev we used: 9e165c30…)
SSHHead can passwordless SSH to worker as the same user
Base recipeClone/adapt MiaAI-Lab/Anemll dual-Spark scripts (see 1M/6 recipe)

This is not a from-scratch vLLM build guide. Start from a working Anemll dual-Spark DSpark checkout, then weight-swap. Changing runtime and weights at the same time is how you lose a weekend.

Topology

Substitute your IPs and NIC names. Wrong VLLM_HOST_IP / socket IFNAME is the classic Gloo-on-127.0.0.1 failure.

RoleFunlandEnv keys
Head192.168.1.11 / RoCE 10.0.0.1MASTER_ADDR=10.0.0.1, VLLM_HOST_IP=10.0.0.1, API :8888
Worker192.168.1.12 / RoCE 10.0.0.2WORKER_HOST=10.0.0.2, WORKER_VLLM_HOST_IP=10.0.0.2
NCCLdual HCA + bond0NCCL_IB_HCA=rocep1s0f0,rocep1s0f1, NCCL_SOCKET_IFNAME=bond0, GID index 3
Gloo/TP socketsbond0 both ranksGLOO_SOCKET_IFNAME / TP_SOCKET_IFNAME = bond0

Weights: download once, rsync once

Do not dual-WAN pull ~160 GB on both nodes. Pull on the head, rsync the HF hub tree to the worker over RoCE/LAN.

# On Spark1 (head)
export HF_HUB_OFFLINE=0 TRANSFORMERS_OFFLINE=0 HF_HUB_DISABLE_XET=1
hf download deepseek-ai/DeepSeek-V4-Flash-0731 --max-workers 4

MODEL_DIR=$HOME/.cache/huggingface/hub/models--deepseek-ai--DeepSeek-V4-Flash-0731

# Verify head
find "$MODEL_DIR" -name 'model-*-of-*.safetensors' | wc -l   # expect 48
find "$MODEL_DIR" -name '*.incomplete' | wc -l               # expect 0
ls "$MODEL_DIR/snapshots"                                    # pin the SHA
test -f "$MODEL_DIR/snapshots/<sha>/config.json"
test -d "$MODEL_DIR/snapshots/<sha>/encoding"

# Rsync full hub model dir (blobs + snapshots) to worker
rsync -aH --info=stats2 \
  "$MODEL_DIR/" \
  milo@10.0.0.2:"$MODEL_DIR/"

# On worker: wipe any leftover .incomplete from a killed dual pull
ssh milo@10.0.0.2 "find $MODEL_DIR -name '*.incomplete' -delete"
ssh milo@10.0.0.2 "find $MODEL_DIR -name 'model-*-of-*.safetensors' | wc -l"  # 48

Mount the full hub model directory (or let Anemll resolve the HF id with HF_CACHE). Snapshot-only bind mounts break relative symlinks into blobs/ and the loader dies with “Invalid repository ID”.

Funland pin: rev 9e165c30e2704aec5d9d593cce3eebd58bbef1cb, ~156 GiB on disk.

Checkout + env

Copy a known-good Anemll DSpark checkout; do not mutate production in place until you trust the swap.

# On head
cp -a ~/ds4-f-mia-anemll-1m6 ~/ds4-f-mia-anemll-0731
cd ~/ds4-f-mia-anemll-0731

# Edit .env.dspark (minimum deltas)
DSPARK_MODEL=deepseek-ai/DeepSeek-V4-Flash-0731
SERVED_MODEL_NAME=deepseek-v4-flash-0731
WORKER_DIR=/home/milo/ds4-f-mia-anemll-0731
WORKER_SCRIPT_DIR=/home/milo/ds4-f-mia-anemll-0731

# Keep the Anemll 1M/6 shape that actually fits this pair
MAX_MODEL_LEN=1048576
MAX_NUM_SEQS=6
MAX_NUM_BATCHED_TOKENS=8192
GPU_MEMORY_UTILIZATION=0.85   # 0.80 was short of KV for 1M on our pair
MTP_NUM_TOKENS=5
DSPARK_VLLM_IMAGE=ghcr.io/anemll/dspark-vllm-gx10:0.1.1
HF_HUB_OFFLINE=1
HF_CACHE=/home/milo/.cache/huggingface
WORKER_HF_CACHE=/home/milo/.cache/huggingface

# Sync checkout to worker
rsync -a ~/ds4-f-mia-anemll-0731/ milo@10.0.0.2:~/ds4-f-mia-anemll-0731/

Env checklist (copy-friendly)

KnobValue we run
DSPARK_MODELdeepseek-ai/DeepSeek-V4-Flash-0731
SERVED_MODEL_NAMEdeepseek-v4-flash-0731
MAX_MODEL_LEN1048576
MAX_NUM_SEQS / batch6 / 8192
GPU_MEMORY_UTILIZATION0.85
MTP_NUM_TOKENS5 (dspark speculative)
kv_cache_dtypenvfp4_ds_mla (compose)
moe-backendflashinfer_b12x (compose)
Master / worker RoCE10.0.0.1 / 10.0.0.2, port 25000

Launch / stop

# Clean both nodes first (Aiden/legacy units masked; SHM + page cache)
# Then from head only:
cd ~/ds4-f-mia-anemll-0731
PROJECT_NAME=ds4-f-mia-anemll-0731 WAIT_ATTEMPTS=120 WAIT_SECONDS=15 \
  ./start-deepseek-v4-flash-dspark.sh

# Status / logs
./status-deepseek-v4-flash-dspark.sh
docker logs -f ds4-f-mia-anemll-0731-vllm-dspark-1

# Stop
./stop-deepseek-v4-flash-dspark.sh

Cold bind is often 8–15 minutes (weight load + TileLang/FlashInfer autotune + cudagraph). SHM “60 seconds” log lines during compile are often non-fatal — wait for Application startup complete and a live /v1/models.

vLLM serve shape (what Anemll runs)

Effective serve (abridged from compose; env-expanded). Useful if you re-implement without their scripts:

vllm serve deepseek-ai/DeepSeek-V4-Flash-0731 \
  --served-model-name deepseek-v4-flash-0731 \
  --host 0.0.0.0 --port 8888 \
  --trust-remote-code \
  --tensor-parallel-size 2 \
  --kv-cache-dtype nvfp4_ds_mla \
  --block-size 256 \
  --max-model-len 1048576 \
  --max-num-seqs 6 \
  --max-num-batched-tokens 8192 \
  --gpu-memory-utilization 0.85 \
  --enable-prefix-caching \
  --async-scheduling \
  --enable-chunked-prefill \
  --speculative-config '{"method":"dspark","num_speculative_tokens":5,"draft_sample_method":"probabilistic"}' \
  --tokenizer-mode deepseek_v4 \
  --distributed-executor-backend mp \
  --moe-backend flashinfer_b12x \
  --tool-call-parser deepseek_v4 \
  --enable-auto-tool-choice \
  --reasoning-parser deepseek_v4 \
  --default-chat-template-kwargs '{"thinking":false}' \
  --enable-flashinfer-autotune \
  --nnodes 2 \
  --node-rank $NODE_RANK \
  --master-addr 10.0.0.1 \
  --master-port 25000 \
  ${HEADLESS:+--headless}

Official HF card sometimes shows K=7 greedy on GB300-class gear. We kept Funland-proven K=5 probabilistic on Anemll first. Change one axis at a time if you experiment.

Gates (do these before calling it live)

# 1) models
curl -s http://127.0.0.1:8888/v1/models | jq .
# expect id deepseek-v4-flash-0731, max_model_len 1048576

# 2) exact marker (thinking off)
curl -s http://127.0.0.1:8888/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{
    "model":"deepseek-v4-flash-0731",
    "messages":[{"role":"user","content":"Reply exactly PROMOTE_0731_OK."}],
    "temperature":0,"max_tokens":32,
    "chat_template_kwargs":{"thinking":false}
  }'

# 3) tools must return tool_calls[]
# 4) stream completes
# 5) optional Keys (model is argv[3] — default is still the DSpark name):
python3 bench_concurrent.py http://127.0.0.1:8888 1 deepseek-v4-flash-0731

Funland promote gates (2026-07-31): exact PROMOTE_0731_OK, tools PASS, Hermes ROUTE_OK.

Hermes wiring

# config.yaml provider sketch
custom_providers / providers entry for spark-ds4:
  api: http://192.168.1.11:8888/v1
  api_key: no-key-required   # not "none"
  context_length: 200000
  default_model: deepseek-v4-flash-0731
  models:
    deepseek-v4-flash-0731:
      context_length: 200000
      max_output_tokens: 32768
    deepseek-v4-flash-dspark:   # keep for rollback
      context_length: 200000
      max_output_tokens: 16384

# smoke
hermes chat --provider spark-ds4 -m deepseek-v4-flash-0731 \
  -q 'Reply exactly ROUTE_OK.' -Q --toolsets safe

Measured numbers (this pair, same Keys harness)

ProbeDSpark (healthy ref)Flash-0731Notes
Keys C1 best-of-272.4 t/s68.9 t/s−5% short-gen
Keys C4173.8135.8slower multi-stream
Keys C6211.0180.6slower
Draft accept C1~0.74–0.78~0.57–0.74noisier on 0731
Server max len1M1MKV ~2.1–2.16M tokens
Tools / multi-hop toolsPASSPASS
Hermes routeROUTE_OKROUTE_OK
How we read this: Keys is a short-gen concurrency ladder, not an IQ test. Official HF agent benches claim large lifts vs preview Flash; our local smoke pack was too shallow to “prove” that on paper. Production promote here is an operator judgment: prefer official agentic weights over a few percent of Keys C1, with DSpark kept for rollback.

Post-promote optimization (same day)

After promote we did not thrash the runtime. Goal: make official 0731 as good as possible for daily Hermes on this pair — agent correctness first, Keys second. Sources: HF card, Anemll/howtospark dual recipe, Tony/Tech2Wild Patch3 lineage, Blackwellboy model-serving-minefield (traps 11/28/56–62), NVIDIA Dev forums, SGLang cookbook (no signed dual-GB10 cell), and a Nous Opus-5 second opinion on a measured brief.

Live forensics on the production serve

FactValueImplication
dspark_block_size5Funland K=5 matches the drafter block. Official card K=7 greedy is a separate experiment — demoted as the next canary.
YaRN original_max_position_embeddings65,536Advertised 1M is extended; cold long retrieval is not free IQ.
Serve lineK=5 probabilistic, util 0.85, B12X, FlashInfer sampler, generation-config vllm, thinking default boolean falseTony-class garble mitigations present; no server rep-penalty override.
KV (pre-wedge / post-restore)~2.20M / 2,214,8071M/6 still fits with headroom.
Trap 57 (thinking string "false")CONFIRMED — reasoning still emittedClients must send JSON boolean false, never the string.
Cold needle ~12.6k / ~50.3k prompt tokensHIT (6.7s / 35.7s)Hermes client 200k not disproven at these depths.
Cold ~128k synthetic needleSpark1 hard hang → power-cycleNever first-fire ≥100–128k unwatched on sole prod head.
SGLang dual-GB10PARKCookbook covers B200/B300/GB200/… not dual GB10 + fused DSpark.

Ranked next moves

TierActionGate
DONEBoolean thinking via Hermes extra_body; trap57 mitigationConfig live on milo profile
DONESampling A/B short harness: greedy 0/1.0 vs agentic 1.0/0.95BOTH_PASS tools/code; accept ~0.65→0.60 under agentic
OPENHermes auto-pin agentic temp/top_pProvider overrides only support extra_body today — not pinned globally
DO-NOWReal Hermes multi-tool replay harness + draft-accept deltasTask-mix acceptance, not Keys alone
GUARDEDCold long steps only with console + second watcher + preferably copy checkoutStep 80k→100k before 128k/200k
LATERMAX_NUM_BATCHED_TOKENS 8192→16384 (log warned scheduled=8168)One-axis canary after harness
NEXT CANARYWesche-style 40K / K=7 greedy speed lane (copy checkout)Same image+rev; tools+Hermes+short fixture; not a 1M drop-in
KEEPProd 1M/6 K=5 probabilistic for Hermes dailyLong-ctx + multi-seq contract
PARKSGLang / stock vLLM 0.26 / r0b0tlab runtime swapAlready KEEP_ANEMLL on runtime
NEVERutil <0.85 @1M; 1M/12; dual-WAN pulls; Keys-as-IQ demote
Community speed lane (Wesche, same day): 40K TP=2 + DSpark K7 greedy on the same Anemll image and 0731 rev — ~84 t/s on a 1024→512 fixture with output-hash parity vs spec-off. Explicitly not a 1M recipe replacement. Funland keeps 1M/K5 for Hermes; K7 is a separate optional speed-lane canary. X: @WescheNex1q.
Restore after the wedge (from head only, after SHM/page-cache both nodes): cd ~/ds4-f-mia-anemll-0731 && PROJECT_NAME=ds4-f-mia-anemll-0731 WAIT_ATTEMPTS=120 WAIT_SECONDS=15 ./start-deepseek-v4-flash-dspark.sh. Gates: exact marker, tools, Hermes ROUTE_OK. Worker was stopped from Spark2 while head was dead so TP did not thrash.

Rollback to DSpark

cd ~/ds4-f-mia-anemll-0731 && ./stop-deepseek-v4-flash-dspark.sh
# SHM + page-cache both nodes
cd ~/ds4-f-mia-anemll-1m6
PROJECT_NAME=ds4-f-mia-anemll-1m6 WAIT_ATTEMPTS=120 WAIT_SECONDS=15 \
  ./start-deepseek-v4-flash-dspark.sh
# Point Hermes default_model back to deepseek-v4-flash-dspark

Do not delete 0731 weights after promote; do not delete DSpark weights until you are sure you will not roll back.

Pitfalls we hit so you do not have to

  1. Dual-WAN download — wasteful and contends disk with live benches. Head download + RoCE rsync.
  2. Snapshot-only mounts — HF blob symlinks break. Full hub model dir or HF id + shared cache.
  3. GPU_MEMORY_UTILIZATION=0.80 — failed 1M KV on this pair; use 0.85.
  4. Gloo on 127.0.0.1 — set VLLM_HOST_IP per rank + bond0 socket IFNAMEs.
  5. Keys 404 — harness defaults to DSpark model name; pass deepseek-v4-flash-0731 as argv[3].
  6. Hermes api_key must be no-key-required, not none.
  7. Cold start patience — 8–15 min; do not abort on first SHM timeout log during autotune.
  8. Do not thrash Aiden/legacy units under compose — mask them first.
  9. Runtime canaries ≠ weight canaries — we previously kept Anemll vs r0b0tlab v0.26 (August DS4-F Testing). This recipe is weights on Anemll.
  10. Official K=7 greedy is a separate experiment from K=5 probabilistic — and on this checkpoint dspark_block_size=5, so K=5 is the natural match.
  11. thinking string "false" is not off (trap 57). Send a JSON boolean.
  12. Unwatched ≥128k synthetic cold needles on sole prod head can hard-hang the box (we power-cycled Spark1). Guarded only.
  13. Head-down mid-TP: stop/rm the orphaned worker on Spark2 immediately; restore from head after clean SHM/page-cache both nodes.

What we run right now (Funland end-state)

ItemValue
Checkout/home/milo/ds4-f-mia-anemll-0731
Imageghcr.io/anemll/dspark-vllm-gx10:0.1.1
WeightsDeepSeek-V4-Flash-0731 @ 9e165c30…
Serveddeepseek-v4-flash-0731 on http://192.168.1.11:8888/v1
Hermesprovider spark-ds4, default model deepseek-v4-flash-0731
Rollback checkout/home/milo/ds4-f-mia-anemll-1m6 + DSpark weights

Attribution