先给结论:它是一个多阶段编排层

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。官方架构博客把这类工作负载概括为不同计算、延迟和状态行为的阶段图;仓库的 PipelineConfigStageConfig 是这张图的可执行声明,而不是营销层面的模型标签。

版本锚点与证据范围

对象截至 2026-08-07 的锚点如何使用
SGLang-Omni 主线7daa5be3aa0e2c3787eb1bc371594ea277191b61,2026-08-07本页全部源码链接固定到该提交,避免把随后修改混入解释。
正式发布0.1.0,tag commit 8e272bcb...,2026-06-14它是可命名 release,不覆盖主线之后的 Qwen、Ming、Router 与 TTS 重构变化。
上游 SGLangsglang==0.5.16Omni 的 AR bridge 绑定这个版本;不能将 SGLang core main 的新 feature 自动归给 Omni。

固定来源:仓库主线提交0.1.0 release0.1.0 tag commit依赖定义

三种相邻 runtime,不能混写

普通 SGLang MLLM

通过 python -m sglang.launch_server 服务图文、音频或视频理解模型。官方 MLLM 文档的总述是多模态输入、文本输出;它是单个 serving engine 的扩展,不等于跨 Thinker/Talker/vocoder 的 pipeline。

SGLang-Omni

在独立仓库中声明多 stage 拓扑,拥有 Coordinator、Stage runtime、跨 stage relay、专门的流式语音生命周期和 OpenAI 兼容表面。Qwen3-Omni 的 text+audio 与 Ming-Omni 的 Talker 路径在这里实现。

SGLang-Diffusion

是 SGLang 的另一套 diffusion runtime。官方博客只将它与 Omni 描述为可能协同演进;这不构成“它负责 Qwen/Ming 声音生成”的证据。

LLaDA2.0-Uni 的提醒

它可在 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 wrapperOmni 模型表LLaDA cookbookSGLang-Diffusion 官方博客

代码地图:每一层谁负责

固定源码路径与关键符号职责
HTTP/WS APIserve/openai_api.pycreate_app_register_chat_completions_chat_stream解析 OpenAI 风格请求,注册 chat、speech、transcription、voice 与 realtime 路由。
客户端适配client/client.pygeneratecompletioncompletion_stream把 pipeline 事件组合为普通 JSON、SSE delta 或音频 payload。
控制中心pipeline/coordinator.pysubmitstreamabort投递入口请求、收集多个 terminal、将中止广播给执行图。
stage 外壳pipeline/stage/runtime.pyStage接收控制/数据消息,完成 fan-in,再把 payload 交给各自 scheduler。
拓扑与启动pipeline/mp_runner.pyconfig/schema.pyStageConfig 的 process、GPU、TP 与连接关系落为多进程 runtime。

静态拓扑怎样变成可执行图

一个 stage 的关键不是名称,而是它的合同:process 决定进程归属,gputp_size 决定放置与张量并行,nextstream_to 定义后继,wait_formerge_fn 定义 fan-in。route_fnwait_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/completionsPOST /v1/audio/speechPOST /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_arcode2wav。聚合器会向 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 configQwen stage factoriesQwen 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 configMing cookbook

媒体输入怎样成为 stage payload

Qwen 预处理器接受顶层 imagesaudiosvideos 或消息内 typed content,默认将音频标准化到 16 kHz;视频支持请求级 video_fpsvideo_max_frames、最小/最大/总像素预算。源码还暴露 use_audio_in_video:需要时在装载视频时抽取其中音轨,避免重复下载。图像、音频、视频会先生成 cache key,随后才做昂贵的解码和 encoder forward。

Ming 使用相同的顶层媒体思想,但音频会转成 Whisper 风格 mel 特征,视频帧经 Qwen2-VL image processor 形成 pixel_values_videosvideo_grid_thw。媒体解码本身不是 AR scheduler;它是请求进入 model graph 前的 CPU/I/O 与 encoder work,应与 Thinker 的 token latency 分开计时。

来源:通用 audio loader通用 video loaderQwen preprocessorMing 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 serverrealtime VADQwen realtime 文档

从架构读出的研究问题

首先,调度对象不再只是 token request,而是带媒体解码、多个 terminal、不同状态寿命和不同 GPU 放置的 DAG request。其次,abort 的正确性要求 Coordinator、relay、stage queue 和 model runner 对同一 request id 有一致的释放语义。最后,OpenAI 表面把多 terminal 隐藏为一个 response,这会掩盖真正影响体验的指标:媒体准备时间、首 token、首音频、文本完成和波形完成分别在哪里排队。

因此后续阅读应把“模型支持”拆成至少四项:输入模态能否进入预处理、拓扑能否启动、每个 terminal 是否正确、目标硬件和并发下是否有端到端证据。仓库存在 class 或分支,只能回答第一或第二项,不能自动回答后两项。

一手来源清单