Qwen3-Omni#
Qwen3-Omni is a multi-modal model that accepts text, image, audio, and video input and can produce text-only or text + audio output. This page covers every supported server configuration — use the generator to get the exact launch command for your hardware, then check the tables to confirm your combination is supported.
Prerequisites#
docker pull hongccc/sglang-omni:dev
docker run -it --shm-size 32g --gpus all hongccc/sglang-omni:dev /bin/zsh
pip install --upgrade pip
pip install uv
uv venv .venv -p 3.12 && source .venv/bin/activate
uv pip install --prerelease=allow "sglang-omni==0.1.9"
See Installation for Docker digests and source installs.
Server Configuration#
Use the selector below to generate the exact launch command for your configuration.
Compatibility Matrix#
Colocated topology requires --config examples/configs/qwen3_omni_colocated_h20.yaml
(or qwen3_omni_colocated_h200.yaml on H200) to set per-stage GPU memory budgets.
Mode |
Topology |
Thinker TP |
Precision |
Status |
|---|---|---|---|---|
Thinker-only |
— |
— |
BF16 |
✅ |
Thinker-only |
— |
— |
FP8 |
✅ |
Thinker-only |
— |
— |
AutoRound INT4 |
✅ |
Thinker-Talker |
Disaggregated |
TP=1 |
BF16 |
✅ |
Thinker-Talker |
Disaggregated |
TP=1 |
FP8 |
✅ |
Thinker-Talker |
Disaggregated |
TP=1 |
AutoRound INT4 thinker + BF16 talker/code2wav |
✅ |
Thinker-Talker |
Disaggregated |
TP=2 |
BF16 |
✅ |
Thinker-Talker |
Disaggregated |
TP=2 |
FP8 |
✅ |
Thinker-Talker |
Disaggregated |
TP=2 |
AutoRound INT4 thinker + BF16 talker/code2wav |
✅ |
Thinker-Talker |
Colocated |
TP=1 |
BF16 |
✅ |
Thinker-Talker |
Colocated |
TP=1 |
FP8 |
✅ |
Thinker-Talker |
Colocated |
TP=1 |
AutoRound INT4 thinker + BF16 talker/code2wav |
✅ |
Input / Output Modalities#
All input modality combinations work with both text-only and speech servers.
modalities: ["text", "audio"] requires a speech-mode server (omit --text-only).
Input |
Output |
Speech server |
Minimal request body |
Notes |
|---|---|---|---|---|
Text |
Text |
No |
|
— |
Image + text |
Text |
No |
|
— |
Audio |
Text |
No |
|
content must be “” when the query is spoken |
Image + audio |
Text |
No |
|
content must be “” when the query is spoken |
Image |
Text |
No |
|
content must be “” when query comes from image |
Video + text |
Text |
No |
|
— |
Video + audio |
Text |
No |
|
content must be “” when the query is spoken |
Video |
Text |
No |
|
content must be “” when query comes from video |
Text |
Text + Audio |
Yes |
|
— |
Image + text |
Text + Audio |
Yes |
|
— |
Audio |
Text + Audio |
Yes |
|
content must be “” when the query is spoken |
Image + audio |
Text + Audio |
Yes |
|
content must be “” when the query is spoken |
Image |
Text + Audio |
Yes |
|
content must be “” when query comes from image |
Video + text |
Text + Audio |
Yes |
|
— |
Video + audio |
Text + Audio |
Yes |
|
content must be “” when the query is spoken |
Video |
Text + Audio |
Yes |
|
content must be “” when query comes from video |
Sampling Parameters#
Standard sampling parameters apply to the thinker stage. When modalities includes "audio", the additional talker-specific parameters below control the speech generation independently.
Parameter |
Type |
Default |
Applies to |
|---|---|---|---|
|
float |
|
Thinker |
|
float |
|
Thinker |
|
int |
|
Thinker |
|
float |
|
Thinker |
|
float |
|
Thinker |
|
int |
|
Thinker |
|
int |
|
Thinker; OpenAI-compatible alias for |
|
str | list |
|
Thinker |
|
int |
|
Thinker |
|
bool |
|
Both |
|
dict |
|
Speech response format config, e.g. |
|
float |
|
Talker (audio output only) |
|
float |
|
Talker (audio output only) |
|
int |
|
Talker (audio output only) |
|
float |
|
Talker (audio output only) |
|
int |
|
Talker (audio output only) |
|
dict |
|
Per-stage sampling override |
|
dict |
|
Per-stage non-sampling params |
|
float |
|
Frame sampling rate for video input (uses server default if unset) |
|
int |
|
Maximum number of frames sampled from a video |
|
int |
|
Minimum pixels per video frame |
|
int |
|
Maximum pixels per video frame |
|
int |
|
Total pixel budget across all video frames |
|
bool |
|
Set to |
Non-streaming chat requests return HTTP 400 for invalid media, HTTP 503 when the request queue is full, and HTTP 500 for other
server failures. With stream=true, errors detected after the event stream
starts are sent as data: {"error": {"message": "...", "type": "invalid_request_error", "code": 400}},
followed by data: [DONE]. A full request queue uses type: "server_error" and code: 503. Other server failures use type: "server_error" and
code: 500. The HTTP status remains 200 once streaming has started; clients
must check for an error event, including after partial output.
Known Limitations#
Multiple videos must have the same sampled frame rate. The processor accepts one frame rate for video token timestamps. Requests with different sampled frame rates follow the invalid-input error contract above.
modalities: ["text", "audio"]has no effect on a text-only server. No error is raised — the response simply contains no audio. Use a speech-mode server (without--text-only) to get audio output.contentmust be""when the query is entirely inaudios,videos, orimages. Leaving a text query incontentalongside audio causes the model to process both, which is usually not what you want.Colocated topology does not support
--thinker.tp_size 2. The server raises aValueErrorat startup (“Qwen Phase 1 colocation does not support thinker TP”). Use disaggregated topology for TP=2.Requests that exceed the model’s context length are rejected with an error. The preprocessor raises a
ValueErrorwhen the prompt token count alone meets or exceedsmax_seq_len, or whenprompt tokens + max_new_tokens ≥ max_seq_len. Reduce input length or lowermax_tokensto stay within the limit. Without--preprocessing.factory.max_seq_lenand--thinker.factory.max_seq_len, the limit is the thinker’s context in the checkpoint config (65,536 tokens for the Instruct checkpoint). Setting both to a lower value caps it. The talker’s context is likewise the checkpoint’s unless--talker_ar.factory.max_seq_lensets it. When a long spoken prompt leaves less room thantalker_max_new_tokens, the talker generates only the frames that fit, so the audio can end before the text.
Qwen3-Omni persistent session stages#
The session profile serves Qwen3-Omni as a realtime voice assistant over the Session API. The graph has a VAD node, a dialog node that turns the audio between speech.started and speech.stopped (or a client commit) into one user turn, and the qwen_omni node that answers it:
preprocessing -> image_encoder -> audio_encoder -> thinker -> talker_ar -> code2wav
sgl-omni serve --config examples/qwen3_omni/session_h200.yaml --enable-realtime --port 8765
examples/qwen3_omni/session_h200.yaml sets what depends on the device: the per-stage memory fractions (those of the colocated speech profile for one H200) and max_sessions. On another device, declare both for that device; colocated stages require explicit memory fractions. Each open session retains up to the thinker’s max_seq_len (32768) tokens of KV, so max_sessions is the thinker’s KV pool in tokens, which the thinker logs at startup as KV Cache is allocated. ... #tokens, divided by 32768: 555,988 tokens and 16 sessions with these fractions on one H200. The image and audio encoders run in their own processes under their own fractions, so the thinker’s encoder_mem_reserve is 0.
The session takes 16 kHz PCM16 audio and camera frames. A user turn ends on speech.stopped, commit, or the end of input; the reply streams as text_delta and 24 kHz pcm16 with turn.queued, turn.started and turn.done, and turn.done arrives once the reply’s audio has left the server. The model hears each utterance whole and answers it with the conversation so far; it does not listen while it speaks. Speech that starts during a reply, or an interrupt control, stops the reply and publishes turn.interrupted. max_utterance_seconds (60) bounds the audio of one utterance and max_queued_turns (8) the finished utterances waiting behind the turn being answered; a client past either ends its session.
Camera input uses sglang.input_image.append, as for MiniCPM-o: a base64 JPEG or PNG in image and its audio timeline position in sglang.t_ms. The newest max_utterance_frames (4) frames that fall in an utterance go to the model with that turn; each frame costs thinker context for the rest of the session.
instructions can be set at session start and changed with configure until the first user turn is processed. sampling can be changed with configure at any time and applies from the next unit; the defaults are greedy decoding for the thinker and the checkpoint’s generation_config.json for the talker (talker_temperature 0.9, talker_top_k 50, talker_top_p 1.0, talker_repetition_penalty 1.05, talker_max_new_tokens 4096), with max_new_tokens 2048 per turn for the thinker.
Current limits:
No user transcript is published.
After an interruption, send
truncatewith the milliseconds of reply audio the listener heard (conversation.item.truncate); the model’s history then keeps only that much of the reply. Without it, the whole reply generated so far stays in the history.instructionscannot change after the first user turn is processed; open a new session instead.
See Session Graph for the shared routing and delivery contracts.