First audio in
94 milliseconds.
Text plus a sentence describing a voice, and the first PCM frame is on the wire before the stock stack has finished thinking. The whole path — the 1.7B talker, its 15-step code predictor, the neural decoder, the scheduler, the HTTP server — is Rust and CUDA. No Python, no PyTorch, no SGLang in the runtime or the image.
$ export QWEN3_TTS_IMAGE=…@sha256:<digest> $ docker run --gpus device=0 --read-only \ -p 127.0.0.1:8080:8080 "$QWEN3_TTS_IMAGE"
Stock SGLang has better aggregate throughput than this runtime in every profile measured, and it is not close. It gets there by buffering to completion — you hear nothing until all of it exists. That is the trade: 28× sooner to the first frame and 19× less memory, paid for in tokens per second. If you are batching offline, use SGLang.
One DGX Spark, two alternating-order rounds of profiles B1/B3/B6, 2,600 measured requests, 24 warm-ups per cell, no competing CUDA process. Every number here is from that study or from checked JSON evidence in the repo — the paper has the methodology and the limitations.
Let your agent set it up
You were going to paste it into Claude anyway. The runbook checks you actually have a Spark, makes it resolve the digest from the release instead of grabbing a tag, waits out the warm-up and proves the thing speaks before it says it is done.
Set me up with qwen3-tts-native — Qwen3-TTS VoiceDesign serving in native Rust
and CUDA on a DGX Spark. Run this first, then follow it exactly, top to bottom:
curl -fsSL https://qwen.lukaloehr.com/setup.txt
Ask me its first question before doing anything else. Pin the image by digest,
never by tag, and never print my tokens.Two commands
Ah, so you haven’t fallen for the vibe yet. Respect. I still read commands before I run them too.
Run it by digest
Needs a DGX Spark (GB10, sm_121, linux/arm64) with Docker and the NVIDIA runtime. The image carries the pinned weights, so there is nothing to download afterwards. Copy the full reference from the current release: a mutable tag, a branch or latest is not a deployment identity, and the runbook refuses one.
# from the release notes, not a tag $ export QWEN3_TTS_IMAGE=ghcr.io/luka-loehr/ qwen3-tts-native@sha256:<digest> $ docker run --rm --gpus device=0 --read-only \ --cap-drop=ALL -p 127.0.0.1:8080:8080 \ "$QWEN3_TTS_IMAGE"
Wait for /health/ready. That gate is the model and the full pipeline, not the process — it only opens after a real frame has been pushed through. Cold start is around ten seconds.
Describe a voice, get speech
There is no voice name to look up and no sample to upload. You write a sentence about how it should sound, and that is the conditioning. Leave stream out and you get progressive PCM; set it to false for a buffered WAV.
$ curl -X POST localhost:8080/v1/voice-design/speech \
-H 'Content-Type: application/json' \
-d '{"text":"Good morning.",
"voice_description":"A calm adult male voice.",
"language":"english","stream":false}' \
-o speech.wavStreaming responses are multipart/mixed — parse the boundaries, because HTTP DATA frames are not audio packet boundaries. The server does not terminate TLS or authenticate anyone; put it behind a proxy and read SECURITY.md before exposing it.
VoiceDesign only, on purpose
No voice cloning, no reference audio, no speaker enrollment, no Base or CustomVoice checkpoint, no speech tokenizer. You cannot hand it a recording of someone and get their voice back, and that is a decision rather than a missing feature.
Ten languages are exposed explicitly — Chinese, English, Japanese, Korean, German, French, Russian, Portuguese, Spanish, Italian — plus auto. Anything outside that list is rejected at the boundary. Turkish has no language ID in the pinned checkpoint, so it is not advertised.
Measured on one Spark
Serving
Runtime
HTTP API
POST /v1/voice-design/speechprogressive PCM, or buffered WAVGET /v1/capabilitieslanguages, formats, limitsGET /health/readyengine loaded and fully warmedDELETE /v1/requests/{id}bounded cancellationGET /metricsprompt-free Prometheus counters8080