1. 先确定它解决的是什么问题
普通多模态文本服务可以把图像、音频或视频编码为输入 token,随后仍由一个自回归模型输出文本。any-to-any 模型则可能在一次交互里先理解视频与音频,再生成思考文本、离散语音码,最后以声码器或扩散模型合成波形、图像或视频。不同阶段的计算形态、批处理方式、显存状态和设备偏好并不相同。
官方架构概览把 vLLM-Omni 的目标定义为支持图像、音频、视频和 action 等非文本输出,并把自回归(AR)与非自回归的 DiT 工作负载纳入同一服务框架。它并不宣称每一个多模态 checkpoint 都可无需适配地运行;模型须有对应的流水线定义、输入输出处理器和部署配置。
2. 六个组件的职责边界
从外向内看,入口层包括 OpenAI 风格 API、同步 Omni 和异步 AsyncOmni。异步入口把一个逻辑请求交给 AsyncOmniEngine;引擎再把控制面请求送进 Orchestrator。Orchestrator 维护各个 stage 的客户端和请求路由,而 AR stage 与扩散 stage 分别由对应执行客户端驱动。
官方图中的 OmniRouter 负责把模型及运行参数解析到合适的流水线;OmniConnector 则是数据面的抽象,用于搬运 embedding、hidden state、音频 chunk 等大对象。因而「收到 HTTP 请求」和「把上游 tensor 真正送到下游设备」是两条不同的路径,前者不能替代后者的带宽、所有权和回收设计。
入队、取消、stage 选择、输出完成判定和请求关联。它应传递小的元数据与通知,而非默认复制所有中间 tensor。
hidden state、编码结果、codec token 或扩散条件等载荷。它由本地共享内存或远端 connector 传送,性能和故障语义需单独验证。
3. 模型图与部署图不是同一个配置
模型流水线描述的是「哪些 stage 存在、边如何连接、何处为最终输出」;部署配置描述的是「每个 stage 用什么设备、并行策略、批量上限和 connector」。官方概览列出三类常见结构:以 DiT 为主并使用 AR 文本编码器的 Qwen-Image 类;以 AR 为主、DiT 负责生成的 BAGEL 类;以及把 AR 与 DiT/专用生成器串联的 Qwen-Omni 类。
源码中的 pipeline registry 将已知模型类型映射到流水线配置,而不是运行时凭 checkpoint 名称猜测图结构。这个分层使同一图可在不同硬件上换部署策略,也意味着仅复制 YAML 并不能让未登记模型获得正确的中间表示、停止条件和输出处理。
4. 一个逻辑请求从 AsyncOmni 开始
AsyncOmni.generate() 是异步调用面的关键入口。调用者提交一个逻辑请求,并通过异步迭代取得最终输出;对扩散模型,一个逻辑请求仍只对应一个 prompt,但多个兼容的在途逻辑请求可以由调度器组成批次。这个约束避免把「应用层的一次生成」误解为「必须独占一个设备批次」。
应用程序 -> AsyncOmni.generate(...) -> AsyncOmniEngine.add_request(...) -> 输入处理器 + OutputProcessor[0] -> Janus 请求队列 -> Orchestrator -> stage 0 客户端 -> 后续 stage 与最终输出队列 -> AsyncOmni._process_single_result(...) -> async for result in generate(...)
上述顺序来自官方异步架构说明与 async_omni.py。它说明返回给应用的对象已走过该模型定义的终点,而不是每个 stage 的内部 token 流都直接暴露为用户输出。
5. 主进程、编排线程与 stage 进程
当前异步设计把用户侧主进程与 Orchestrator 线程分开,并用 Janus 队列跨同步/异步边界传递控制消息。每个实际计算 stage 则通过 StageEngineCoreClient 或 StageDiffusionClient 与后台的 AR StageCoreProc 或 DiffusionEngine 通信;官方文档明确标注这些客户端使用 ZMQ。
因此,单个 Python API 调用不表示全部工作都在同一事件循环或同一 GPU 上进行。排查卡顿时,至少应分别观察:入口是否入队、编排器是否取到请求、stage 是否接受请求、上游是否产出、路由是否把输出交给下游、最终队列是否被消费。把这些状态混成一个「模型慢」指标会掩盖队列背压和传输等待。
6. Orchestrator 的轮询与路由
orchestrator.py 持有 stage pool,并先把新请求投给 stage 0。它在编排循环中轮询已运行 stage:语言模型路径调用异步输出获取,扩散路径使用非阻塞读取;拿到结果后交给对应 output processor,再根据流水线边调用 _route_output 和 _forward_to_next_stage。
这是一种按 stage 分治的调度结构,不是把整个端到端图压成一个单一 vLLM 请求。优点是每个 stage 可以有各自的 engine 和批处理策略;代价是阶段间的消息、张量存放和请求关联成为显式系统问题。若下游未就绪,上游输出的暂存位置与回压策略就会影响端到端尾延迟。
7. Qwen3-Omni 的三阶段实例
在该 tag 的 Qwen3-Omni pipeline 中,stage 0 是 Thinker:它是多模态 AR stage,拥有 tokenizer,并可产生最终文本。stage 1 是 Talker:它从 Thinker 接收信息,以 AR 方式生成语音相关的 codec token。stage 2 是 Code2Wav:它把来自 Talker 的码流变为最终音频。
输入(文本 / 图像 / 音频 / 视频)
-> Thinker(stage 0,LLM_AR)
-> 最终文本
-> Thinker2Talker 中间表示
-> Talker(stage 1,LLM_AR)
-> codec token
-> Code2Wav(stage 2,LLM_GENERATION)
-> 最终音频
这张调用链不是模型结构论文的抽象重画,而是该版本注册的服务流水线。它也解释了为什么同一个用户提示可能有文本与音频两条产物路径,以及为什么一个 stage 的完成并不必然等于整个逻辑请求完成。
8. 中间表示如何进入下游
Qwen3 输入处理器显示了这不是仅转发文本 token 的接口。Thinker 到 Talker 的完整负载包含第 0 层 embedding、第 24 层 hidden state、token id、说话人和语言相关信息;异步路径会把负载 detach 到 CPU,再交由传输与下游处理。Talker 到 Code2Wav 的处理器则收集 codec 输出并按配置组织 chunk。
这些字段是 Qwen3 适配实现的事实,不应外推为任意模型都需要第 24 层隐藏状态。正确的工程做法是把「模型特定的语义」保留在 stage input/output processor,把「如何交付该载荷」保留在 connector 和编排器中,避免把模型协议硬编码进通用队列。
9. async_chunk:重叠,而非无成本并行
该版本支持 async_chunk。对 Qwen3 的异步 Thinker-to-Talker 路径,处理器可以让 Talker 先得到用于准备的 prompt bookkeeping,而较大的上游载荷随后经 connector 交付。adapter 中的 construct_next_stage_streaming_input_prompt 会更新 prompt 记录与 block hash,用于下游的异步预热。
因此 async_chunk 的语义是尝试让下游准备工作与上游持续生成重叠,而不是承诺零拷贝、零等待或任何模型都能逐 token 流式消费。是否收益取决于 chunk 大小、连接器、下游 prefill、可用 KV 空间和模型处理器;应在目标模型与硬件上测量首个音频/视频片段以及最终完成时间。
10. 最终输出与取消不能只看 stage 0
OutputProcessor 既处理 stage 输出,也决定是否将其作为中间结果路由还是写入最终队列。异步入口的最终 handler 从面向请求的输出队列读取结果,再通过 _process_single_result 交给调用者。因而取消、超时和客户端断开都必须沿逻辑请求关联传播到仍在运行的 stage;只停止 Thinker 不能自动证明后面的语音或扩散作业已被释放。
公开架构文档展示了这种端到端控制流,但不提供一份跨所有 connector、所有模型和所有失败点的 exactly-once 或事务性保证。部署方应把重复输出、延迟到达的 chunk、下游拒收和取消竞态当作需要集成测试的状态,而非由 API 形状自动消除的问题。
11. 实验性全双工走的是另一条扩展路径
v0.26.0 将 MiniCPM-o 4.5 full duplex 标为 experimental preview。其 设计文档给出的链路是 WebSocket、会话处理器与 DuplexSession,经 DuplexRequestClient 和控制面进入扩展后的 StagePool,再经 MiniCPM stage、TTS/Token2Wav 和 realtime 投影回浏览器。
该文档只把 stage 0 的会话 KV 连续性、stage 1 TTS/Token2Wav、模型拥有的 listen/speak 决策、连续 PCM 与播放确认列为当前范围。它明确未承诺调度器原生的 KV append、确定性 VAD 打断、生产级多会话公平性与恢复、长会话有界 KV、视频输入或 A/V 同步。不要把 preview 的状态图当成生产会话 SLA。
12. 从哪几个文件开始读源码
阅读顺序可按控制流展开:先看 入口 了解用户拿到什么;再看 AsyncOmniEngine 和 Orchestrator 了解队列与循环;随后看 StagePool、Qwen3 pipeline 和 input processor,最后检查 connector adapter。这样能避免从某段模型适配代码误推全局调度语义。
下一章把这些结构落到调度、KV、connector 和扩散执行模式上:哪些状态可以跨 stage 交接,哪些仅是当前实现的 best-effort 优化,以及哪些并行组合在官方文档中明确不兼容。
13. 一手来源
| 来源 | 本页用途 |
|---|---|
| v0.26.0 release;tagged source | 版本、发布日期与实验性特性边界。 |
| Architecture Overview | 组件、模型类型与总架构。 |
| Async Omni Architecture | 请求队列、线程/进程和异步输出流程。 |
| Qwen3 pipeline;input processor | 三阶段和模型特定中间表示。 |
| MiniCPM-o full-duplex design | 实验性会话链路及明确未覆盖的能力。 |