Qwen3.6-27B running on a single DGX Spark with SGLang

This post is a direct follow-up to yesterday's M2.7 MXFP4 run. After fighting through eight separate gotchas to get a 115 GB MoE model running across two Sparks and measuring 12 t/s at single-request throughput, we asked the obvious question: what does a smaller, faster model look like on the same hardware?

The answer is Qwen3.6-27B-FP8. One Spark. SGLang. NEXTN speculative decoding. Here's what happened.

What Is Qwen3.6?

Qwen3.6-27B is not the same as Qwen3-30B-A3B (the MoE variant). It's a dense 27B-parameter model with a hybrid attention architecture — a mix of standard Gated Attention layers and Gated DeltaNet linear attention layers. The linear attention component is what makes it architecturally interesting: it scales more efficiently with sequence length than standard attention and makes speculative decoding particularly effective.

In FP8, the weights come in at about 27 GB — comfortably within a single GB10 Spark's 119 GiB unified memory pool, with room to spare for KV cache.

The Stack

The launch was straightforward. No Ray cluster, no multi-node setup, no page cache rituals. One docker run, model loaded in under 4 minutes, server up.

docker run -d \
  --name qwen36-sglang \
  --gpus all \
  --shm-size=10g \
  --network=host \
  -v /home/milo/models:/models \
  -e SGLANG_DISABLE_DEEP_GEMM=1 \
  -e SGLANG_ENABLE_SPEC_V2=1 \
  scitrera/dgx-spark-sglang:0.5.12 \
  python3 -m sglang.launch_server \
    --model-path /models/Qwen3.6-27B-FP8 \
    --served-model-name qwen3.6-27b-mtp \
    --context-length 65536 \
    --mem-fraction-static 0.75 \
    --tp-size 1 \
    --host 0.0.0.0 \
    --port 8003 \
    --kv-cache-dtype fp8_e4m3 \
    --page-size 64 \
    --cuda-graph-max-bs 64 \
    --reasoning-parser qwen3 \
    --tool-call-parser qwen3_coder \
    --fp8-gemm-backend cutlass \
    --speculative-algo NEXTN \
    --speculative-num-steps 5 \
    --speculative-num-draft-tokens 9 \
    --speculative-eagle-topk 1 \
    --max-running-requests 8 \
    --trust-remote-code

Benchmark Results

Full llama-benchy sweep: pp=[512, 1024, 2048], tg=[128, 256], depth=[0, 1024, 4096, 16384], concurrency=[1, 4, 8], 3 runs each. Completed in approximately 3 hours with no crashes, no OOM, no intervention.

Generation Throughput (depth=0)

TestTotal t/sPer-req t/sPeak t/s
tg128 (c1)22.622.627.7
tg128 (c4)54.316.297.7
tg128 (c8)95.315.5170.3
tg256 (c1)18.718.727.7
tg256 (c4)56.115.392.0
tg256 (c8)97.813.7161.3

Prefill Throughput

TestTotal t/sTTFT (ms)
pp2048 (c1, d=0)1,5001,377
pp512 (c1, d=0)931562
pp2048 (c4, d=0)9508,542
pp2048 (c1, d=16384)87521,074

Generation at Depth

Depthtg128 c1 t/stg128 c4 t/stg128 c8 t/s
022.654.395.3
1,02420.163.459.2
4,09618.732.725.4
16,38419.48.77.1

The depth story is nuanced. Single-request TG (c1) stays remarkably stable across all depths — 22.6 down to 19.4 t/s even at 16K depth. Speculative decoding continues to work effectively at depth. But concurrent serving at high depth collapses: c4 at d=16384 is 8.7 t/s, c8 is 7.1 t/s. This is expected — 8 concurrent requests each holding 16K+ tokens of KV cache saturates the available memory for KV allocation, forcing sequential processing. For single-user agent workloads this is a non-issue. For multi-user concurrent serving at deep context, you're memory-limited on a single Spark.

The Speculative Decoding Effect

NEXTN at topk=1, 5 steps gives a ~20% burst uplift at c1 (22.6 sustained, 27.7 peak). The peak column in the benchmark represents the best individual run out of 3, and you can see it consistently hitting 27–28 t/s — that's the speculative path firing well. On coding and templated tasks where token prediction is easier, this gap would be larger. On truly creative or random outputs it narrows. For agent workloads (tool calls, structured responses, chain-of-thought) it's a real gain.

Vs. MiniMax M2.7 MXFP4 (Dual Spark)

MetricQwen3.6-27B (1 Spark)M2.7 MXFP4 (2 Sparks)
TG c1 (sustained)22.6 t/s12.4 t/s
TG c8 (aggregate)95.3 t/s~65 t/s
TG peak c8170 t/s~65 t/s
Prefill pp2048 c11,500 t/s1,004 t/s
TTFT pp2048 c11,377 ms1,676 ms
Sparks used12
Benchmark completion~3 hoursDid not complete
OOM events01 (aborted first run)
Startup time<4 min~4 min (warm cache)

Qwen3.6-27B wins on every operational metric: faster TG, lower latency, uses half the hardware, benchmarked clean in 3 hours, never crashed. M2.7 is the larger model — more parameters, broader knowledge, likely better at genuinely hard tasks — but for the day-to-day agent workload where you're doing tool calls, reasoning loops, and structured output, Qwen3.6-27B is the right answer on this hardware.

What Spark 2 Is Doing Now

Nothing. It's free. That's the point. Running M2.7 required both Sparks tied together for one endpoint. Running Qwen3.6-27B leaves Spark 2 available for a second model, a different task, or just idling. For a two-Spark lab, single-Spark inference unlocks a lot more flexibility.

Wiring It Into Hermes

Qwen3.6-27B is now our primary candidate for the Hermes agent provider. It has native reasoning support (--reasoning-parser qwen3), native tool calling (--tool-call-parser qwen3_coder), and 22+ t/s interactive response speed. The OpenClaw alias wiring will come in a follow-up post once we've tuned the system prompt for agent use.

Practical Notes