从文本到多模态路由:在vLLM语义路由器中强化视觉信号
From Text to Multimodal Routing: Hardening Vision Signals in vLLM Semantic Router
vLLM Semantic Router (VSR) 将路由从 prompt 级扩展为请求级,通过 Signal-Decision 架构将文本与图像 embedding 等信号组合成可编程策略。在多模态路由中,部署的 `multi-modal-embed-small` 路径在 11 图像探针上出现 82% 的反转率,原因是 Candle 路径的池化头、图像归一化和预处理与 PyTorch 参考路径不匹配。修复后,20/20 图像余弦 ≥ 0.999 与参考对齐。该工作由 vllm-project/semantic-router 团队完成,相关 PR 为 #1927、#1928、#1943。
大多数路由系统从一个 prompt 开始,然后选择一个模型端点。vLLM Semantic Router (VSR) 做出了不同的选择:在请求到达服务模型之前,系统应该提取信号,将这些信号组合成决策,并使所选路径可观察、可审计和可编程。
这个想法始于文本。Iris 引入了 Signal-Decision 架构,将 VSR 从一个固定的领域分类器发展成一个更丰富的系统,其中意图、关键词、embedding、安全性、PII、语义缓存和插件都可以参与路由。Athena 进一步推动了同样的想法:Semantic Router 不仅是 vLLM 前面的一个快速分类器,更是混合模型和 agent 部署的系统级智能层。
下一个边界是多模态路由。一旦图像、截图、扫描件或文档页面进入请求,路由器就不再仅仅基于 prompt 进行推理。它是在基于请求证据进行推理。图像可能是使请求具有临床性、受监管性、安全敏感性、超出领域范围,或值得路由到更强的视觉语言模型的部分。一个只看到文本的路由器是在路由一个不完整的请求。
这篇文章是关于跨越这个边界的。重要的步骤不仅仅是添加一个图像编码器。重要的步骤是将视觉证据转化为一个可信的 VSR 信号,该信号可以在同一个决策框架内与文本信号组合。
下面的加固故事解释了为什么这种区别很重要。围绕 multi-modal-embed-small 部署的多模态路径看起来错误得很有信心。第一个解释似乎很明显:也许紧凑的视觉编码器不够强大。实际的问题更有发现价值,对生产系统也更重要:VSR 使用的 Rust/Candle 路径与同一模型的 PyTorch 参考路径不匹配。
多模态路由不是图像分类
纯文本路由已经处理了比主题匹配更多的事情。在 Signal-Decision 模型中,信号是独立的观察结果,决策以优先级和布尔逻辑组合这些观察结果,插件或模型引用定义了下一步应该发生什么。这种分离使得 VSR 能够表达像“安全敏感的代码审查获得更强的推理模型和越狱检查”这样的策略,而不是“计算机科学去编码模型”。
多模态路由保持了相同的形状,但将分析单元从文本 prompt 改变为完整的请求。文本可能是通用的,而图像承载着决定性的证据:
| 请求证据 | 纯文本路由器看到 | 多模态路由器应该看到 |
|---|---|---|
| "总结这个" + 护照图像 | 通用总结 | 身份证明文件,PII 风险,受限处理 |
| "这显示什么?" + 胸部 X 光片 | 模糊的视觉问题 | 临床图像,医学领域策略,有能力的 VLM 目标 |
| "找 bug" + 代码截图 | 编码请求 | 代码制品,可能的秘密泄露,安全审查路径 |
| 医学 prompt + 无关的汽车图像 | 医学文本 | 领域外视觉证据,澄清或拒绝路径 |
创新之处不在于 VSR 可以计算图像 embedding。创新之处在于图像 embedding 成为与文本意图、PII、越狱、领域、语义相似性、插件和模型选择相同的框架中的一个类型化信号。换句话说,多模态支持将 VSR 从 prompt 级路由转变为请求级策略。
这也是为什么信号正确性成为控制平面要求的原因。如果文本信号错误,策略可能会路由到错误的模型或跳过错误的插件。如果视觉信号是反相关的,问题就更糟了:路由器可能错误得很有信心,同时仍然为错误的决策留下一个干净、可重复的审计轨迹。
因此,参考一致性不仅仅是模型质量卫生。对于 VSR,它是一个控制平面不变量。部署的信号路径必须与参考模型路径含义相同,否则决策层就是在组合错误的证据。
当视觉信号错误得很有信心时
第一个症状不是一个小幅度的准确率下降。在一个涵盖三个垂直领域和 21 个候选标签的 11 图像探针上,部署的 multi-modal-embed-small (mmes) 路径在 11 张图像中有 9 张将错误的垂直领域排名最高。医学 X 光片得分更接近半导体候选者,而不是医学候选者。身份证明文件没有可靠地接近身份证明锚点。
这是一个 82% 的反转率。信号是反相关的,而不仅仅是嘈杂的。
对于路由器来说,这种失败模式比基准分数更重要。一个弱的分类器通常会产生不确定性。一个反转的分类器会在错误的方向上产生信心。在多模态策略层中,这可能比根本没有图像信号更糟糕。
暴露该问题的生产表面是围绕 multi-modal-embed-small 的图像模态路由工作,包括在 vllm-project/semantic-router PR #1881 中引入的 E2E 路由配置文件。一旦真实图像流经 Candle 绑定路径,差距就变得可见了。
诱人的解释:升级编码器
第一个假设很自然:也许紧凑的编码器对于路由任务来说不够强大。大约在同一时间,团队已经在探索 SigLIP2 系列和更大的 multi-modal-embed-large (mmEL) 方向。这使得编码器升级感觉像是一个明显的修复。
我们直接测试了这个假设:
- SigLIP2-base 在相同的 21 候选探针上得分 10/10。
- 通过 Hugging Face Transformers 的 SigLIP-base 也得分 10/10。
- mmEL,其视觉塔基于 SigLIP2,得分 10/10。
- 直接通过 PyTorch 参考路径加载的 mmes 模型卡也得分 10/10。
这个结果改变了调查的方向。编码器系列不是根本问题。即使是据称失败的 mmes 模型,在通过参考路径加载时也表现正确。
从编码器追踪中仍然有有用的学习。更大的 SigLIP2-so400m 变体在这个探针中显示出更强的分布外拒绝能力,比更小的变体更积极地抑制了一个意外包含的汽车引擎图像。当内存余量允许更大的视觉塔时,这可能对未来的防御性路由很重要。但这并不是生产信号反转背后的 bug。
改变调查方向的参考检查
决定性的测试很简单:通过两条路径在相同的护照固定装置上运行相同的 mmes 模型,并比较 embedding 行为。
PyTorch 参考路径针对相关的护照锚点返回余弦 0.7204。部署的 Candle 绑定路径在相同的图像和概念流水线上返回 0.1576。在相同的模型和固定装置上,这是一个 5-8 倍的幅度差距。
此时,调查不再是一个模型选择问题。有用的问题变成了:生产路径在哪里偏离了参考路径?
教训很简单:对于多模态路由,参考比较应该是第一个诊断,而不是最后一个。当生产 embedding 路径行为异常时,在假设模型本身太弱之前,先将其与模型卡的参考加载器进行比较。
这在 VSR 中尤其重要,因为 embedding 不仅仅是一个检索原语。它可以成为策略证据。如果该证据与参考模型的方向相反,那么每个下游层都可能在逻辑上正确,但在操作上错误。
实际出了什么问题
漂移来自 Candle 路径中的实现细节,而不是模型权重。三个修复将问题隔离到具体的层。
首先,池化头是错误的。candle-binding/src/model_architectures/embedding/multimodal_embedding.rs 中的 SigLIPVisionEncoder::forward 实际上是在做 BERT 风格的 mean + Linear + tanh 池化,而 SigLIP 使用注意力探针池化头。PR #1927 在 Candle 绑定中镜像了 SigLIP 的多头注意力池化行为。
其次,图像归一化路径不完整。Go 图像加载器产生 [0, 1] 范围内的 CHW float32 像素,而 SigLIP 期望等效于 (x - 0.5) / 0.5 的逐通道归一化。PR #1928 在 Rust 编码器路径中应用了该归一化。
第三,在池化和归一化修复之后,预处理仍然存在残余漂移。旧的 Go 端调整大小路径使用了 4-tap 双线性实现。PyTorch 参考路径通过 SiglipProcessor 使用 PIL 风格的图像预处理。PR #1943 使用 image crate 和 Catmull-Rom 滤波将图像解码、调整大小和 CHW float32 转换移入 Rust,以近似 PIL 双三次 + 抗锯齿行为。
这是跨语言服务栈中容易遗漏的一类 bug。Go 层、Rust FFI 层、Candle 模型实现和 PyTorch 参考都可能看起来各自合理,但最终仍然产生破坏路由的端到端不匹配。
验证状态
以下数字来自 #1927、#1928 和 #1943 的 PR 分支栈的测量结果。它们作为提议的加固路径的验证轨迹被包含在内。在所有三个 PR 合并之前,这些数字应被解读为分支栈验证,而不是已发布的生产行为。
在规范护照固定装置 (inrule_identifier_passport.jpg) 上的一个三向量隔离实验将模型前向漂移与预处理漂移分开:
| 比较 | 余弦 | 最大绝对差 | 隔离内容 |
|---|---|---|---|
| Python vs Candle-PIL | 0.999989 | 0.000911 | 仅模型前向 |
| Candle-PIL vs Candle-Go | 0.999916 | 0.001992 | 仅预处理 |
| Python vs Candle-Go | 0.999902 | 0.002120 | 完整分支栈流水线 |
第一行显示 Rust 模型前向路径可以在 fp32 噪声水平上匹配 PyTorch 参考。前两个修复后的残余漂移存在于预处理中,这就是为什么将预处理移过 FFI 边界很重要。
在一个涵盖身份证明、环境、代码、对抗性和分布外示例的 20 图像语料库上,分支栈测量结果为:
- 余弦:最小 0.999557,平均 0.999919,最大 0.999978
- 20 / 20 张图像余弦 >= 0.999 与 PyTorch 参考对比
- 修复前规范固定装置上的预处理余弦为 0.990145
重要的结果不仅仅是最终的余弦数值。而是隔离方法:将生产路径与参考路径进行比较,将模型前向漂移与预处理漂移分开,然后使生产路径在测试和服务中使用相同的预处理语义。
这对 VSR 意味着什么
一旦视觉路径变得可信,VSR 就可以将图像视为一等证据,而不是侧信道元数据。这种解锁比“将图像请求路由到图像模型”更大。它让文本和图像证据能够参与同一个 Signal-Decision 框架:
| 组合信号模式 | 示例决策 |
|---|---|
| 临床文本 + 临床图像 + PHI/PII 信号 | 路由到启用了隐私插件的受保护医学 VLM 路径 |
| 通用文本 + 身份证明图像 | 在模型调用前阻止、编辑或路由到身份文档处理策略 |
| 代码/安全 prompt + 代码截图 | 路由到安全专用模型,并对原始请求保持越狱检查 |
| 领域内文本 + 领域外图像 | 要求澄清或拒绝图像证据,而不是强制进行错误路由 |
这是 Iris 和 Athena 方向的自然延续。Iris 使路由决策可组合。Athena 通过添加更强的模型栈、模型选择、内存、重放和更丰富的信号处理,使路由器更具战略性。多模态路由将相同的架构从纯语言控制扩展到请求级控制。
与此工作相关的公开演示是 shrader.dev。今天它演示了策略模式的文本路由版本:领域相关性检查、隐私敏感路由以及在模型调用前的阻止结果。这个演示很重要,因为它展示了在添加图像之前的策略形状。
文本路由路径还说明了一个对多模态生产很重要的性能特性。分类器信号可以通过 runSignalDispatchers 并发运行,因此挂钟延迟受最慢的启用分类器限制,而不是所有分类器的总和。在一个代表性跟踪中,完整的分类决策在 CPU 上大约在 1.3 秒内完成。
该故事的多模态版本不是一个单独的产品路径。它是具有更大证据表面的同一个策略引擎。图像和文本信号应该通过相同的路由语义进行提取、验证、组合、重放和审计。
这就是为什么加固工作很重要。如果 VSR 要基于视觉证据进行路由,那么视觉信号路径必须可靠得令人乏味。它必须匹配参考模型,跨越跨语言服务边界,并在策略变得更具表达力时保持可测试性。
下一步是什么
当前的工作是落地和审查加固 PR,然后在多模态路由演进过程中将验证语料库保持在循环中。更大的方向是使参考驱动的检查成为 VSR 多模态服务故事的正常部分。
从那里开始,下一步是架构性的:
- 在与文本派生信号相同的决策层中暴露图像派生信号;
- 使多模态决策在重放、指标和调试工具中可见;
- 使模型选择同时考虑策略适配性和模态能力;
- 为安全关键信号(如 PII 和越狱)保留高保真检查;
- 将相同的框架扩展到 agent 工作流,其中工具调用、内存写入和模型调用通过一个决策层进行路由。
文本路由是第一个控制面。多模态路由是下一个。目标不是在路由器旁边构建一个一次性的视觉分类器,而是使请求的每个有意义的部分都可供同一个可编程路由大脑使用。
开始使用:
- 项目仓库:vllm-project/semantic-router
- 在线演示:shrader.dev
致谢
感谢 Huamin Chen 提供的 mmEL 指针,帮助打破了编码器升级的误诊;感谢维护者团队对 #1927、#1928 和 #1943 的审查;以及邀请撰写此文。还要感谢更广泛的维护者团队,感谢这个弧线所接入的多模态分类器工作、multi-modal-embed-small 模型卡以及这一切所基于的 Candle 绑定集成。