Qwen3.8-27B on single DGX Spark: 1.9x stock NVFP4 (2.5x FP8) at 16 concurrent, ~50 tok/s on a single request

A dense 27B reads all 27 billion parameters per token. That is why it is good, and why it is unusable out of the box on one Spark. This is a measured configuration that fixes it, installed by one script — v1.0: albond/DenseSpark-Qwen3.8-27B · GitHub

Why this model. On Artificial Analysis’s Intelligence Index v4.1.1: Qwen3.8-27B scores 52 at high reasoning effort, Qwen3.5 122B A10B scores 33, Flash-Next scores 56 at 180B resident. 27B dense is the size one Spark holds whole, four points off a model seven times larger. Those points cost reasoning tokens — and length is only affordable if tokens arrive fast.

16 concurrent requests. NVIDIA’s three shapes, output tok/s. Stock figures as published on this forum; mine are the median of three retained runs after a warm-up, on the image the installer builds.

test stock FP8 stock NVFP4 this vs NVFP4
balanced (1k/1k) 104.44 134.41 260.2 1.94x
decode-heavy (1k/8k) 99.47 132.07 227.0 1.72x
prompt-heavy (8k/1k) 65.58 87.91 111.2 1.26x

Single request — 58.1 tok/s across five prompts, three runs each, decode alone. Full spread, not the best of it:

prompt tok/s TTFT
Q&A 256 36.6 217 ms
LongCode 2048 49.6 249 ms
Code 512 51.0 248 ms
Math 64 75.5 243 ms
JSON 1024 77.9 249 ms

Token-weighted 54.8. First token in ~0.25 s; a 2,000-token answer in ~35 s — about ten times faster than you read.

Where stock wins: time to first token, all three shapes. NVFP4 4.05 s vs my 7.57 (balanced), 29.81 vs 37.97 (prompt-heavy), 4.05 vs 7.56 (decode-heavy). The prefill path that would have closed it was built, measured, dropped — it fails the quality gate. If your load is many short requests, weigh that first.

Quality.

  • Runtime: paired mean-NLL delta −0.00012 nat/token against exact dequantization of its checkpoint, threshold 0.005, over 23,997 tokens. No measurable degradation on that gate — not proof every answer is identical, not a task benchmark.
  • Checkpoint: NVFP4 and FP8 are formats — a fixed rule converts the tensor. AutoRound is a calibrated method: it searches rounding decisions against calibration data, so quality is a property of how the build was made, not only of its bit count. A stock 4-bit build is already a good starting point.
  • You are not stuck with mine. Quantize your own with your own calibration set and point the installer at it. The kernels take any checkpoint meeting their contract — symmetric GPTQ, 4-bit, group 128, BF16 activations, no act-order, no zero points, this model’s geometry. That knob does not exist with a fixed-format checkpoint.
  • I have not measured this checkpoint against the FP8 or NVFP4 builds on quality, so no ranking between them is claimed here.

How. AutoRound INT4 weights; the checkpoint’s built-in MTP layer proposing tokens the full model verifies; SM121-specific kernels for the output projection, the linear attention 48 of 64 layers use, and the backbone matmuls, each dispatched by row count.

Use.

git clone https://github.com/albond/DenseSpark-Qwen3.8-27B
cd DenseSpark-Qwen3.8-27B
./install.sh

It asks one question — how many concurrent requests you expect — then ./configs/launch-densespark.sh serves an OpenAI-compatible API. That question is not cosmetic: speculation depth is selected per concurrency, 8 at one request and 3 from three up, because a long proposal pays off when the machine would otherwise wait and wastes work when sixteen keep it busy.

Not claimed. Concurrency above 16, context beyond ~9k tokens, multimodal, task accuracy, any other machine. Negative results are in the repo with reasons — including the faster prefill path that is not shipped, and a draft-head variant withdrawn for killing the engine on deterministic requests.

Small fix — v1.1

  • Fixed chat clients rendering the model’s reasoning as part of the reply, with a bare </think> in it — the profile now serves with vLLM’s Qwen3 reasoning parser. Note it strips the reasoning rather than forwarding it, so clients won’t show a collapsible thinking block yet.
  • Fixed the API being reachable only on loopback, so a chat UI on another machine couldn’t connect — DENSESPARK_BIND_HOST now selects the interface, defaulting to loopback. No authentication, so read SECURITY.md before exposing it.
  • Fixed install.sh ignoring DENSESPARK_MODEL, which silently left the draft-head structure built for the default checkpoint.

Performance numbers are unchanged — the parser formats the chat response without touching generation.

Please report anything you hit.

Amazing tok/s numbers, well done. Is it possible to use this for coding or are there tradeoffs that make it difficult? Trying with claude code gives:
```
● API Error: 400 “auto” tool choice requires --enable-auto-tool-choice and --tool-call-parser to be set
```

I just added these to configs/_common.sh but I think the intention is to set them through DENSESPARK_EXTRA_ARGS, e.g.

DENSESPARK_EXTRA_ARGS=“–tool-call-parser qwen3_xml --enable-auto-tool-choice” DENSESPARK_CONCURRENCY=1 DENSESPARK_BIND_HOST=0.0.0.0 ./configs/launch-densespark.sh

There are some other options that might be useful for agentic coding, e.g. DENSESPARK_MAX_LEN=240000 DENSESPARK_PREFIX_CACHING=1

Small fix — v1.2

  • Added OpenAI-compatible tool calling. The profile now serves with vLLM’s qwen3_xml tool-call parser and automatic tool choice, so a client that sends tools gets structured tool calls back

Thanks for support

I created a PR (bench_densespark: fix warmup failing on reasoning checkpoints by fossouo · Pull Request #1 · albond/DenseSpark-Qwen3.8-27B · GitHub) with comments on my testing journey of this.

Thank you, let me check. My DGX Spark will be available for this fix after couple of hours EOD. I will replay soon.
I add thinking mode in V1.1, after fix performance, so forget re-run tests. When I enabled thinking, in V1.1 we have issue with long thinking typical for Qwen.

Fixed and released as 1.3 — thanks @AliBaba_97, your patch went in as 74e824b.

1.1 added --reasoning-parser qwen3, which buffers the thinking trace until its closing tag. A request whose budget runs out first gets nothing back: two of the five benchmark prompts failed outright, the other three counted the buffered trace but timed only the visible tail. The benchmark now measures with reasoning off.

So the single-request figure was overstated and is corrected: 44.9 tok/s cross-prompt mean, 49.1 token-weighted, replacing 58.1 and 54.8.

The three NVIDIA-shape numbers are unaffected — that benchmark uses /v1/completions, no chat template, no parser. 1.94x / 1.26x / 1.72x against stock NVFP4 stand.

1.3: Release DenseSpark_Qwen3.8_27b 1.3 · albond/DenseSpark-Qwen3.8-27B · GitHub