先给结论:它是一个多阶段编排层
SGLang-Omni 是单独发布的 Python 包和仓库,不是 SGLang core 中某一个普通 VLM 的别名。它把一个模型拆成预处理、图像或音频 encoder、聚合、AR Thinker、Talker、decoder、codec/vocoder 等 stage;每个 stage 可在不同进程和 GPU 上运行,并有自己的 scheduler。AR stage 尽量复用 SGLang 的调度、KV 内存和图优化,非 AR stage 则使用更轻量的执行循环。
这种边界解释了为什么它适合 Qwen3-Omni、Ming-Omni 和流式 TTS:端到端工作不是一个统一的 token decode loop。官方架构博客把这类工作负载概括为不同计算、延迟和状态行为的阶段图;仓库的 PipelineConfig 和 StageConfig 是这张图的可执行声明,而不是营销层面的模型标签。
版本锚点与证据范围
| 对象 | 截至 2026-08-07 的锚点 | 如何使用 |
|---|---|---|
| SGLang-Omni 主线 | 7daa5be3aa0e2c3787eb1bc371594ea277191b61,2026-08-07 | 本页全部源码链接固定到该提交,避免把随后修改混入解释。 |
| 正式发布 | 0.1.0,tag commit 8e272bcb...,2026-06-14 | 它是可命名 release,不覆盖主线之后的 Qwen、Ming、Router 与 TTS 重构变化。 |
| 上游 SGLang | sglang==0.5.16 | Omni 的 AR bridge 绑定这个版本;不能将 SGLang core main 的新 feature 自动归给 Omni。 |
固定来源:仓库主线提交、0.1.0 release、0.1.0 tag commit、依赖定义。
三种相邻 runtime,不能混写
通过 python -m sglang.launch_server 服务图文、音频或视频理解模型。官方 MLLM 文档的总述是多模态输入、文本输出;它是单个 serving engine 的扩展,不等于跨 Thinker/Talker/vocoder 的 pipeline。
在独立仓库中声明多 stage 拓扑,拥有 Coordinator、Stage runtime、跨 stage relay、专门的流式语音生命周期和 OpenAI 兼容表面。Qwen3-Omni 的 text+audio 与 Ming-Omni 的 Talker 路径在这里实现。
是 SGLang 的另一套 diffusion runtime。官方博客只将它与 Omni 描述为可能协同演进;这不构成“它负责 Qwen/Ming 声音生成”的证据。
它可在 Omni runtime 里使用多阶段结构,但 cookbook 明确标为实验性 text-output path:图像生成和 interleaved generation 尚未接到 OpenAI response。因此不能只因名称含 Uni 或系统含多 stage 就称作完整音频 Omni。
最直接的反证来自 SGLang core 的 Qwen wrapper:它设置 enable_talker = False、将 forward 绑定到 Thinker,并跳过 talker/code2wav 权重。core 可以做 Qwen3-Omni 的文本、图像、音频、视频理解,却不提供 Talker 音频生成。
来源:SGLang MLLM 支持表、core Qwen3-Omni wrapper、Omni 模型表、LLaDA cookbook、SGLang-Diffusion 官方博客。
代码地图:每一层谁负责
| 层 | 固定源码路径与关键符号 | 职责 |
|---|---|---|
| HTTP/WS API | serve/openai_api.py:create_app、_register_chat_completions、_chat_stream | 解析 OpenAI 风格请求,注册 chat、speech、transcription、voice 与 realtime 路由。 |
| 客户端适配 | client/client.py:generate、completion、completion_stream | 把 pipeline 事件组合为普通 JSON、SSE delta 或音频 payload。 |
| 控制中心 | pipeline/coordinator.py:submit、stream、abort | 投递入口请求、收集多个 terminal、将中止广播给执行图。 |
| stage 外壳 | pipeline/stage/runtime.py:Stage | 接收控制/数据消息,完成 fan-in,再把 payload 交给各自 scheduler。 |
| 拓扑与启动 | pipeline/mp_runner.py、config/schema.py | 把 StageConfig 的 process、GPU、TP 与连接关系落为多进程 runtime。 |
静态拓扑怎样变成可执行图
一个 stage 的关键不是名称,而是它的合同:process 决定进程归属,gpu 和 tp_size 决定放置与张量并行,next 或 stream_to 定义后继,wait_for 与 merge_fn 定义 fan-in。route_fn 与 wait_for_fn 允许模型按请求中的媒体实际存在性跳过分支;因此“六 stage”是拓扑声明,不是每个 text-only 请求的六次有效 GPU 计算。
StageConfig 的概念合同
process / gpu / tp_size 放置与进程拓扑
next / stream_to payload 或流式 chunk 的下游
wait_for / merge_fn 多个上游完成后的合并点
terminal 哪个 stage 对 Coordinator 产生最终结果
route_fn / project_payload 按模态裁剪路径并投影最小状态
这种声明式边界使同一请求既能拥有并行 encoder fan-out,也能在 Thinker 后拥有文本和声音的双 terminal。它并不自动证明任意图都已验证:每个模型的 config、GPU 拓扑、TP 组合仍应单独引用 cookbook 或测试证据。
来源:pipeline 文档、配置文档。
HTTP 入口不是模型执行入口
create_app 暴露的 surface 包括 POST /v1/chat/completions、POST /v1/audio/speech、POST /v1/audio/transcriptions、voice 管理和可选 WS /v1/realtime。端点统一不意味着每个模型都支持每个 endpoint:Qwen3-Omni 和 Ming-Omni 的 text+audio 对话路径是 chat completions;典型 TTS 才直接对应 speech endpoint。
chat route 将消息、顶层 images/audios/videos、modalities、采样参数、stage 参数和 request id 变为内部 GenerateRequest。非流式路径等待 terminal 汇总;流式路径先发送 role,再分别发送文本或音频 delta,最后 finish event 和 [DONE]。这也是为什么客户端看到的是一个 OpenAI 响应,而内部实际可能有多个 terminal stage。
从 HTTP 到 terminal 的真实调用链
POST /v1/chat/completions
-> openai_api._build_chat_generate_request(...)
-> Client.generate(...)
-> Coordinator.submit(...) 或 Coordinator.stream(...)
-> entry Stage 接收 SubmitMessage
-> Stage 完成 wait_for / merge,再调用本 stage scheduler
-> Stage 向 next / stream_to 发 DataReady 或 stream chunk
-> terminal Stage 发 CompleteMessage / StreamMessage
-> Coordinator 按 request_id 汇集 terminal 结果
-> Client.completion(...) 或 completion_stream(...)
-> FastAPI 返回 JSON 或 SSE
取消沿相反方向传播:API/Client 触发 abort,Coordinator 对 stage 图广播,stage 与 scheduler 释放或忽略对应 request。研究时要把“HTTP 已断开”“Coordinator 已发送 abort”和“GPU stage 已不再使用该 tensor”分开测量;它们不是同一个时刻。
Coordinator 与 Stage 的职责分界
Coordinator 不做模型 forward,也不应拥有每一种模型的媒体语义。它以 request id 路由,维护请求生命周期,知道哪些 terminal 已完成,并为 stream consumer 维护出口。Stage 也不决定全局 pipeline:它持有统一 inbox/outbox、控制消息和本地 scheduler,把数据投影或 relay 的选择留给 runtime 配置与通信层。
这个分界在 multi-terminal 场景尤其重要。Qwen speech request 既需要 decode 的文本终端,也需要 Code2Wav 的音频终端;Coordinator 要等请求所需的 terminal,而不是把“最先完成的文本”误当成整次 response。相同机制也支持只请求文本时的动态 terminal 选择。
Qwen3-Omni:6-stage 文本与 8-stage 声音
Qwen 的文本 pipeline 声明预处理、图像 encoder、音频 encoder、mm_aggregate、Thinker 和 decode 六个逻辑 stage。预处理基于输入模态路由;聚合 stage 只等待被实际选中的 encoder 结果,并调用 merge_for_thinker 将媒体 embedding 与 prompt 状态拼回 Thinker 输入。
speech pipeline 在此基础上加入 talker_ar 和 code2wav。聚合器会向 Talker 建立 partial-start 所需的初始状态;Thinker 产生文本时把流送给 decode 与 Talker;Talker 生成 codec codes;Code2Wav 消费 codes 并产生最终 waveform 或音频 chunk。默认 speech config 把 Thinker 放在 GPU 0、Talker/Code2Wav 放在 GPU 1;colocated config 只是把多个 GPU stage 放到同一张卡,源码仍为各 stage 保留独立 process 名称。
Qwen text
preprocessing -> image_encoder + audio_encoder -> mm_aggregate
-> thinker -> decode (terminal)
Qwen speech
preprocessing -> encoders -> mm_aggregate -> thinker -> decode (text terminal)
-> talker_ar -> code2wav (audio terminal)
来源:Qwen pipeline config、Qwen stage factories、Qwen cookbook。
Ming-Omni:文本、完整语音、流式语音三条图
Ming 也有预处理、audio/image encoder、聚合和 Thinker,但输出路径不同。text variant 是六 stage;speech variant 将 Thinker 连接到 decode 和 talker,Talker 作为声音 terminal;streaming speech variant 则使用 segmenter 接收增量文本,把它划成可说片段,再交给 talker_stream 发音频 chunk。
Ming text
preprocessing -> audio_encoder + image_encoder -> mm_aggregate -> thinker -> decode
Ming speech
... -> thinker -> decode (text) + talker (44.1 kHz speech)
Ming streaming speech
... -> streaming thinker -> decode + segmenter -> talker_stream (SSE chunks)
默认 sgl-omni serve --model-path 选择 Ming speech path,--text-only 才去掉 Talker。配置显式拒绝 Talker GPU 与 Thinker TP GPU 范围重叠。当前 cookbook 将 streaming 版标作需要 MingOmniStreamingSpeechPipelineConfig 的路径,而不是已经有通用 copy-paste launch 的默认部署。
来源:Ming pipeline config、Ming cookbook。
媒体输入怎样成为 stage payload
Qwen 预处理器接受顶层 images、audios、videos 或消息内 typed content,默认将音频标准化到 16 kHz;视频支持请求级 video_fps、video_max_frames、最小/最大/总像素预算。源码还暴露 use_audio_in_video:需要时在装载视频时抽取其中音轨,避免重复下载。图像、音频、视频会先生成 cache key,随后才做昂贵的解码和 encoder forward。
Ming 使用相同的顶层媒体思想,但音频会转成 Whisper 风格 mel 特征,视频帧经 Qwen2-VL image processor 形成 pixel_values_videos 与 video_grid_thw。媒体解码本身不是 AR scheduler;它是请求进入 model graph 前的 CPU/I/O 与 encoder work,应与 Thinker 的 token latency 分开计时。
来源:通用 audio loader、通用 video loader、Qwen preprocessor、Ming preprocessor。
terminal、SSE、Realtime 与中止
非流式 Client 将已到达的文本和音频终端合成为 chat-completions message;音频会编码为 base64。流式 Client 则把文本 delta、音频 delta 和最终原因分开发出。Ming 的非流式 response 可能看起来像“一次性音频”,但它仍由 terminal 合并得到;Qwen 的 Code2Wav 可以在请求结束前输出增量语音。
Qwen 的 realtime WebSocket 是另一条会话入口:服务端 VAD 接受 mono 16 kHz PCM16,自动提交 utterance,文本以 response.text.delta、声音以 24 kHz PCM16 的 response.audio.delta 返回。它只在 speech pipeline 和显式 text+audio negotiation 下可用;Thinker-only server 没有 Code2Wav,不应伪装成实时声音服务。
来源:API server、realtime VAD、Qwen realtime 文档。
从架构读出的研究问题
首先,调度对象不再只是 token request,而是带媒体解码、多个 terminal、不同状态寿命和不同 GPU 放置的 DAG request。其次,abort 的正确性要求 Coordinator、relay、stage queue 和 model runner 对同一 request id 有一致的释放语义。最后,OpenAI 表面把多 terminal 隐藏为一个 response,这会掩盖真正影响体验的指标:媒体准备时间、首 token、首音频、文本完成和波形完成分别在哪里排队。
因此后续阅读应把“模型支持”拆成至少四项:输入模态能否进入预处理、拓扑能否启动、每个 terminal 是否正确、目标硬件和并发下是否有端到端证据。仓库存在 class 或分支,只能回答第一或第二项,不能自动回答后两项。
一手来源清单
- SGLang-Omni 固定源码树 与 官方文档站
- API server 设计、pipeline 设计
- LMSYS 官方多阶段 runtime 博客,用于架构意图和已发布的 Higgs 例子,不替代固定源码。
- 下一页:调度、缓存、通信与部署