2026-07-13 23:59:42 +08:00
# Qwen3-Omni: Online serving
2025-11-30 18:20:44 +08:00
2025-12-03 11:25:58 +08:00
Source <https://github.com/vllm-project/vllm-omni/tree/main/examples/online_serving/qwen3_omni>.
2025-11-30 18:20:44 +08:00
## 🛠️ Installation
2025-12-03 11:25:58 +08:00
Please refer to [README.md ](https://github.com/vllm-project/vllm-omni/tree/main/README.md )
2025-11-30 18:20:44 +08:00
## Run examples (Qwen3-Omni)
2025-12-03 11:25:58 +08:00
### Launch the Server
2025-11-30 18:20:44 +08:00
```bash
vllm serve Qwen/Qwen3-Omni-30B-A3B-Instruct --omni --port 8091
```
2026-04-24 11:25:22 +08:00
The default deployment configuration situated at `vllm_omni/deploy/qwen3_omni_moe.yaml` is resolved and loaded
automatically via the model registry, obviating the necessity for the `--deploy-config` flag in standard deployment topologies.
2026-09-03 12:24:33 +00:00
The bundled Qwen3-Omni setup explicitly sets `moe_backend: triton` for the Thinker and Talker stages. This keeps
both stages on vLLM's Triton unquantized MoE path and avoids the unstable FlashInfer CUTLASS unquantized MoE path on
some GPUs.
2026-04-24 11:25:22 +08:00
Asynchronous chunk streaming is **enabled by default** within the bundled configuration.
2026-01-26 11:21:24 +08:00
2026-04-24 11:25:22 +08:00
To explicitly utilize a custom deployment YAML, specify the configuration path:
2026-01-26 11:21:24 +08:00
```bash
2026-04-24 11:25:22 +08:00
vllm serve Qwen/Qwen3-Omni-30B-A3B-Instruct --omni --port 8091 \
--deploy-config /path/to/deploy_config_file
2026-01-26 11:21:24 +08:00
```
2026-08-27 16:21:03 +08:00
To serve **thinker-only** (text output, no talker / code2wav loaded) with Instruct
weights, pass the bundled thinker-only deploy YAML. The `pipeline:` key
`qwen3_omni_moe_thinker_only` overrides the HF `enable_audio_output` resolver:
```bash
vllm serve Qwen/Qwen3-Omni-30B-A3B-Instruct --omni --port 8091 \
--deploy-config vllm_omni/deploy/qwen3_omni_moe_thinking.yaml
```
Captioner / Thinking checkpoints (`enable_audio_output=false` ) still auto-select
the same single-stage pipeline without `--deploy-config` .
2026-04-24 11:25:22 +08:00
### Launch individual stages (stage-based CLI)
Adopt the stage-based CLI architecture to independently instantiate execution processes per functional stage.
2026-04-27 21:41:13 +08:00
The example below pins Stage 0 to GPU 0 and Stage 1/2 to GPU 1 via
`CUDA_VISIBLE_DEVICES` .
2026-04-24 11:25:22 +08:00
**1. Stage 0 (Thinker + API server)**
2025-11-30 18:20:44 +08:00
```bash
2026-04-27 21:41:13 +08:00
CUDA_VISIBLE_DEVICES = 0 vllm serve Qwen/Qwen3-Omni-30B-A3B-Instruct --omni \
2026-04-24 11:25:22 +08:00
--port 8091 \
--stage-id 0 \
--omni-master-address 127.0.0.1 \
--omni-master-port 26000
```
**2. Stage 1 (Talker)**
```bash
2026-04-27 21:41:13 +08:00
CUDA_VISIBLE_DEVICES = 1 vllm serve Qwen/Qwen3-Omni-30B-A3B-Instruct --omni \
2026-04-24 11:25:22 +08:00
--stage-id 1 \
--headless \
--omni-master-address 127.0.0.1 \
--omni-master-port 26000
```
**3. Stage 2 (Code2Wav)**
```bash
2026-04-27 21:41:13 +08:00
CUDA_VISIBLE_DEVICES = 1 vllm serve Qwen/Qwen3-Omni-30B-A3B-Instruct --omni \
2026-04-24 11:25:22 +08:00
--stage-id 2 \
--headless \
--omni-master-address 127.0.0.1 \
--omni-master-port 26000
```
Add `--deploy-config /path/to/deploy_config_file` to every command if you want
to override the bundled deploy YAML.
For the regular one-process launch, stage-specific CLI tuning is usually done
with `--stage-overrides` , for example:
```bash
vllm serve Qwen/Qwen3-Omni-30B-A3B-Instruct --omni --port 8091 \
--stage-overrides '{"1": {"gpu_memory_utilization": 0.5}}'
```
2026-09-03 12:24:33 +00:00
To experiment with another supported MoE backend, set `moe_backend` in the
deployment YAML for both the Thinker and Talker stages. For the stage-based
CLI, pass `--moe-backend` directly on each stage command.
2026-04-24 11:25:22 +08:00
```bash
2026-04-27 21:41:13 +08:00
CUDA_VISIBLE_DEVICES = 1 vllm serve Qwen/Qwen3-Omni-30B-A3B-Instruct --omni \
2026-04-24 11:25:22 +08:00
--stage-id 1 \
--headless \
--gpu-memory-utilization 0.5 \
--omni-master-address 127.0.0.1 \
--omni-master-port 26000
2025-11-30 18:20:44 +08:00
```
2025-12-03 11:25:58 +08:00
### Send Multi-modal Request
2025-11-30 18:20:44 +08:00
Get into the example folder
```bash
2025-12-01 16:01:54 +08:00
cd examples/online_serving/qwen3_omni
2025-11-30 18:20:44 +08:00
```
2025-12-03 11:25:58 +08:00
#### Send request via python
2025-11-30 18:20:44 +08:00
```bash
2026-02-27 17:28:35 +08:00
python openai_chat_completion_client_for_multimodal_generation.py --query-type use_image --port 8091 --host "localhost"
2025-11-30 18:20:44 +08:00
```
2025-12-03 11:25:58 +08:00
The Python client supports the following command-line arguments:
2025-12-30 21:55:32 +08:00
- `--query-type` (or `-q` ): Query type (default: `use_video` ). Options: `text` , `use_audio` , `use_image` , `use_video`
2025-12-03 11:25:58 +08:00
- `--model` (or `-m` ): Model name/path (default: `Qwen/Qwen3-Omni-30B-A3B-Instruct` )
2025-12-30 21:55:32 +08:00
- `--video-path` (or `-v` ): Path to local video file or URL. If not provided and query-type is `use_video` , uses default video URL. Supports local file paths (automatically encoded to base64) or HTTP/HTTPS URLs. Example: `--video-path /path/to/video.mp4` or `--video-path https://example.com/video.mp4`
2025-12-31 22:02:04 +08:00
- `--image-path` (or `-i` ): Path to local image file or URL. If not provided and query-type is `use_image` , uses default image URL. Supports local file paths (automatically encoded to base64) or HTTP/HTTPS URLs and common image formats: JPEG, PNG, GIF, WebP. Example: `--image-path /path/to/image.jpg` or `--image-path https://example.com/image.png`
2025-12-30 21:55:32 +08:00
- `--audio-path` (or `-a` ): Path to local audio file or URL. If not provided and query-type is `use_audio` , uses default audio URL. Supports local file paths (automatically encoded to base64) or HTTP/HTTPS URLs and common audio formats: MP3, WAV, OGG, FLAC, M4A. Example: `--audio-path /path/to/audio.wav` or `--audio-path https://example.com/audio.mp3`
- `--prompt` (or `-p` ): Custom text prompt/question. If not provided, uses default prompt for the selected query type. Example: `--prompt "What are the main activities shown in this video?"`
2025-12-03 11:25:58 +08:00
2025-12-31 22:02:04 +08:00
2025-12-03 11:25:58 +08:00
For example, to use a local video file with custom prompt:
```bash
python openai_chat_completion_client_for_multimodal_generation.py \
--query-type use_video \
--video-path /path/to/your/video.mp4 \
--prompt "What are the main activities shown in this video?"
```
#### Send request via curl
2025-11-30 18:20:44 +08:00
```bash
2025-11-30 21:30:17 +08:00
bash run_curl_multimodal_generation.sh use_image
2025-11-30 18:20:44 +08:00
```
2025-12-17 17:19:56 +08:00
## Modality control
2025-12-24 16:57:32 +09:00
You can control output modalities to specify which types of output the model should generate. This is useful when you only need text output and want to skip audio generation stages for better performance.
### Supported modalities
| Modalities | Output |
|------------|--------|
| `["text"]` | Text only |
2026-07-18 19:51:38 +08:00
| `["audio"]` | Audio only |
2025-12-24 16:57:32 +09:00
| `["text", "audio"]` | Text + Audio |
| Not specified | Text + Audio (default) |
### Using curl
#### Text only
```bash
curl http://localhost:8091/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen/Qwen3-Omni-30B-A3B-Instruct",
"messages": [{"role": "user", "content": "Describe vLLM in brief."}],
"modalities": ["text"]
}'
```
#### Text + Audio
```bash
2026-07-18 19:51:38 +08:00
response = $( curl -s http://localhost:8091/v1/chat/completions \
2025-12-24 16:57:32 +09:00
-H "Content-Type: application/json" \
-d '{
"model": "Qwen/Qwen3-Omni-30B-A3B-Instruct",
"messages": [{"role": "user", "content": "Describe vLLM in brief."}],
2026-07-18 19:51:38 +08:00
"modalities": ["text", "audio"]
}' )
echo " $response " | jq -r '.choices[0].message.content'
echo " $response " | jq -r '.choices[1].message.audio.data' | base64 -d > output.wav
2025-12-24 16:57:32 +09:00
```
### Using Python client
2025-12-17 17:19:56 +08:00
```bash
python openai_chat_completion_client_for_multimodal_generation.py \
--query-type use_image \
--modalities text
```
2025-12-24 16:57:32 +09:00
### Using OpenAI Python SDK
#### Text only
```python
from openai import OpenAI
client = OpenAI ( base_url = "http://localhost:8091/v1" , api_key = "EMPTY" )
response = client . chat . completions . create (
model = "Qwen/Qwen3-Omni-30B-A3B-Instruct" ,
messages = [{ "role" : "user" , "content" : "Describe vLLM in brief." }],
modalities = [ "text" ]
)
print ( response . choices [ 0 ] . message . content )
```
#### Text + Audio
```python
from openai import OpenAI
client = OpenAI ( base_url = "http://localhost:8091/v1" , api_key = "EMPTY" )
response = client . chat . completions . create (
model = "Qwen/Qwen3-Omni-30B-A3B-Instruct" ,
messages = [{ "role" : "user" , "content" : "Describe vLLM in brief." }],
2026-07-18 19:51:38 +08:00
modalities = [ "text" , "audio" ]
2025-12-24 16:57:32 +09:00
)
# Response contains two choices: one with text, one with audio
print ( response . choices [ 0 ] . message . content ) # Text response
print ( response . choices [ 1 ] . message . audio ) # Audio response
2026-01-06 22:32:46 +08:00
```
2025-12-31 22:02:04 +08:00
## Streaming Output
2026-03-28 19:24:15 +08:00
If you want to enable streaming output, please set the argument as below. The final output will be obtained just after generated by corresponding stage. We support both text streaming output and audio streaming output. Other modalities can output normally.
2025-12-31 22:02:04 +08:00
```bash
python openai_chat_completion_client_for_multimodal_generation.py \
--query-type use_image \
--stream
2025-12-24 16:57:32 +09:00
```
2025-11-30 18:20:44 +08:00
## Run Local Web UI Demo
2026-03-29 00:33:55 +08:00
!!! note "Gradio is an optional dependency"
The Gradio demo requires the `[demo]` extras. Install them first:
```bash
pip install 'vllm-omni[demo]'
` ``
Or, if installing from source: ` pip install -e '.[demo]'`
2025-11-30 18:20:44 +08:00
This Web UI demo allows users to interact with the model through a web browser.
### Running Gradio Demo
2025-12-19 18:09:43 +08:00
The Gradio demo connects to a vLLM API server. You have two options:
#### Option 1: One-step Launch Script (Recommended)
The convenience script launches both the vLLM server and Gradio demo together:
2025-11-30 18:20:44 +08:00
` ``bash
2025-12-19 18:09:43 +08:00
./run_gradio_demo.sh --model Qwen/Qwen3-Omni-30B-A3B-Instruct --server-port 8091 --gradio-port 7861
` ``
This script will:
1. Start the vLLM server in the background
2. Wait for the server to be ready
3. Launch the Gradio demo
4. Handle cleanup when you press Ctrl+C
The script supports the following arguments:
- ` --model`: Model name/path (default: Qwen/Qwen3-Omni-30B-A3B-Instruct)
- ` --server-port`: Port for vLLM server (default: 8091)
- ` --gradio-port`: Port for Gradio demo (default: 7861)
2026-04-19 10:36:00 +08:00
- ` --deploy-config`: Path to custom deploy config YAML file (optional)
2025-12-19 18:09:43 +08:00
- ` --server-host`: Host for vLLM server (default: 0.0.0.0)
- ` --gradio-ip`: IP for Gradio demo (default: 127.0.0.1)
- ` --share`: Share Gradio demo publicly (creates a public link)
#### Option 2: Manual Launch (Two-Step Process)
**Step 1: Launch the vLLM API server**
` ``bash
vllm serve Qwen/Qwen3-Omni-30B-A3B-Instruct --omni --port 8091
` ``
2026-08-20 07:09:12 +08:00
If you have a custom deploy config file:
2025-12-19 18:09:43 +08:00
` ``bash
2026-04-19 10:36:00 +08:00
vllm serve Qwen/Qwen3-Omni-30B-A3B-Instruct --omni --port 8091 --deploy-config /path/to/deploy_config_file
2025-12-19 18:09:43 +08:00
` ``
**Step 2: Run the Gradio demo**
In a separate terminal:
` ``bash
python gradio_demo.py --model Qwen/Qwen3-Omni-30B-A3B-Instruct --api-base http://localhost:8091/v1 --port 7861
2025-11-30 18:20:44 +08:00
` ``
Then open ` http://localhost:7861/` on your local browser to interact with the web UI.
2025-12-03 11:25:58 +08:00
The gradio script supports the following arguments:
2025-11-30 18:20:44 +08:00
2025-12-19 18:09:43 +08:00
- ` --model`: Model name/path (should match the server model)
- ` --api-base`: Base URL for the vLLM API server (default: http://localhost:8091/v1)
2025-11-30 18:20:44 +08:00
- ` --ip`: Host/IP for Gradio server (default: 127.0.0.1)
- ` --port`: Port for Gradio server (default: 7861)
2025-12-19 18:09:43 +08:00
- ` --share`: Share the Gradio demo publicly (creates a public link)
2025-11-30 18:20:44 +08:00
## Example materials
??? abstract "gradio_demo.py"
` `````py
2025-12-01 16:01:54 +08:00
--8<-- "examples/online_serving/qwen3_omni/gradio_demo.py"
2025-11-30 18:20:44 +08:00
` `````
??? abstract "openai_chat_completion_client_for_multimodal_generation.py"
` `````py
2025-12-01 16:01:54 +08:00
--8<-- "examples/online_serving/qwen3_omni/openai_chat_completion_client_for_multimodal_generation.py"
2025-11-30 18:20:44 +08:00
` `````
2025-12-08 02:43:48 +08:00
??? abstract "qwen3_omni_moe_thinking.yaml"
` `````yaml
2026-07-30 17:57:33 +08:00
--8<-- "vllm_omni/deploy/qwen3_omni_moe_thinking.yaml"
2025-12-08 02:43:48 +08:00
` `````
2025-11-30 18:20:44 +08:00
??? abstract "run_curl_multimodal_generation.sh"
` `````sh
2025-12-01 16:01:54 +08:00
--8<-- "examples/online_serving/qwen3_omni/run_curl_multimodal_generation.sh"
2025-11-30 18:20:44 +08:00
` `````
2025-12-22 21:29:40 +08:00
??? abstract "run_gradio_demo.sh"
` `````sh
--8<-- "examples/online_serving/qwen3_omni/run_gradio_demo.sh"
` `````