多模型路由LLM Router模型路由AI GatewayNbility

多模型路由不是随机切换:质量、成本和延迟怎么一起决策

用三个任务和一份可运行的离线路由实验,拆解能力硬约束、质量门槛、成本、TTFT、健康度、缓存亲和与故障回退。

多模型路由不是随机切换:质量、成本和延迟怎么一起决策

“接入三个模型,然后随机挑一个”叫负载分发,不叫多模型决策。

真正的模型路由至少要回答四个问题:

  1. 这个请求允许送到哪些模型?
  2. 哪些候选模型达到任务的最低质量要求?
  3. 在合格候选中,成本、首 Token 延迟和健康度怎么取舍?
  4. 首选模型失败后,能否安全回退到另一个模型?

最重要的顺序是:

先用硬约束淘汰不合格模型,再在剩余候选里优化质量、成本和延迟。

如果把所有指标直接塞进一个加权公式,一个不支持图片、上下文不够或不符合数据驻留要求的便宜模型,仍可能因为价格得分很高而胜出。这不是“性价比路由”,而是把不可违反的约束误当成偏好。

本文提供一份可运行的离线决策实验、三个任务的路由规则和一个错误反例。文中的模型名称与指标都是用于验证算法的合成 Fixture,不是线上模型 Benchmark,也没有伪造真实供应商延迟或质量数据。

先区分三类“路由”

很多系统把不同层级都叫 Model Routing,容易导致策略混乱。

层级选择对象典型依据示例
部署负载均衡同一模型的多个端点权重、并发、RPM/TPM、延迟两个区域的同一模型部署
模型选择不同模型或模型层级任务能力、质量、成本、TTFTsmall / balanced / deep
故障回退主路径失败后的替代路径错误类型、幂等性、兼容性首 Token 前从主模型切到备选

LiteLLM 官方文档明确把同一 model_name 下的部署负载均衡与跨 model_name 的 fallback 分开;其部署策略包括 simple shuffle、least busy、usage、latency 和 cost based routing。Amazon Bedrock 的 Intelligent Prompt Routing 则是在同一模型家族内,根据 Prompt 预测响应质量并选择模型。

这两类能力都合理,但不能混为一个万能“智能路由器”。

正确的决策流水线

推荐把路由拆成五层:

请求分类
→ 硬约束过滤
→ 质量门槛
→ 多目标评分或规则排序
→ 同模型部署选择
→ 记录决策与回退链

约束过滤、加权评分与最终选择的路由流水线

第一层:硬约束

硬约束不应该参与加权,而应直接过滤:

  • 是否支持 tools、vision、audio、JSON Schema;
  • 上下文窗口是否足够;
  • 指定区域与数据驻留;
  • 租户是否有权访问;
  • 模型是否允许处理该数据等级;
  • 当前渠道是否启用且未触发用量上限;
  • 请求协议能否保真转换;
  • 是否要求固定模型版本或供应商。

形式上可以写成:

eligible(model, request) =
  capability_match
  AND context_fits
  AND tenant_allowed
  AND region_allowed
  AND channel_healthy

任何一项为 false,就不进入下一轮。

第二层:质量门槛

质量不只是一个全局分数。摘要、代码迁移、票据 OCR 和工具调用应使用不同评测集。

建议给每类任务维护独立门槛:

support_triage.accuracy >= 0.85
invoice_extraction.schema_pass >= 0.98
code_migration.tests_pass >= 0.90

这些值必须来自自己的离线评测、灰度流量或人工验收,不能照抄模型厂商的综合榜单。没有评测数据时,先使用显式静态规则,而不是假装有准确的自动质量分。

第三层:多目标评分

只在通过约束与质量门槛的候选中评分。例如把所有值归一化到 0..1

score =
  wq × quality
+ wc × (1 - normalized_cost)
+ wl × (1 - normalized_ttft)
+ wh × health
+ wa × cache_affinity

在真实系统里,建议把“延迟”和“容量”继续拆开:

  • TTFT 决定聊天、语音等交互场景的首字等待;
  • 总完成时间包括完整生成、工具循环、验证与重试,更适合长报告和代码迁移;
  • 限流余量应结合账户实际 RPM、TPM、并发和响应头,而不是硬编码公开示例;
  • 429 可能表示瞬时容量不足,不等于模型质量下降或永久故障。

本文 Fixture 为保持可读性,只把 TTFT 和健康度放入公式;生产策略应按任务增加总完成时间和限流余量,并对输入快照做版本化。

权重必须按任务变化:

任务质量成本TTFT健康度
客服工单分类0.250.350.300.10
EU 票据图片抽取0.450.150.200.20
大型代码迁移0.600.100.100.20

注意:表中的权重是本文离线 Fixture 的策略输入,不是行业标准。

第四层:部署选择

先选模型层级,再在同一模型的可用部署中选渠道。部署选择可以使用:

  • 优先级;
  • 权重;
  • least busy;
  • RPM/TPM 剩余量;
  • 实时或滑动窗口延迟;
  • 地区;
  • Prompt Cache 亲和;
  • 渠道健康与冷却状态。

这一步不应重新把一个“不兼容的模型”塞回候选池。

三个任务怎么路由

离线实验定义了三个匿名模型层级:

模型层级ToolsVisionContext区域定位
fast-small32Kglobal低成本、低延迟
balanced128KEU能力和成本折中
deep-reasoning256Kglobal高质量、高成本、高延迟

质量、成本、TTFT 和健康指标都是合成数据,只用来验证相同输入一定得到相同路由结果。

三个任务在硬约束和权重下选择不同模型层级

任务一:客服工单分类

需求:

  • 8K 上下文;
  • 需要调用工单工具;
  • 不需要图片;
  • 用户等待在线结果;
  • 单次价值较低,量大。

规则:

必须支持 tools
质量达到分类门槛
成本和 TTFT 权重高于最高质量

离线结果:

候选分数
fast-small0.8410
balanced0.6845
deep-reasoning0.4265

选择 fast-small。这不是因为“小模型永远适合客服”,而是在已经通过此任务质量门槛之后,它的成本和延迟优势才有意义。

任务二:EU 票据图片抽取

需求:

  • Vision;
  • 20K 上下文;
  • 数据必须留在 EU;
  • 输出进入财务流程。

硬约束先过滤:

  • fast-small:缺少 Vision,且不满足 EU;
  • deep-reasoning:不满足 EU;
  • balanced:唯一合格。

选择 balanced,分数为 0.7835。即使其他模型在某个综合榜单更强或更便宜,也不应参与排序。

任务三:大型代码迁移

需求:

  • 100K 上下文;
  • 需要工具;
  • 质量权重最高;
  • 允许较高延迟,但仍控制成本。

fast-small 因 32K 上下文被淘汰。剩余结果:

候选分数
balanced0.8250
deep-reasoning0.7900

这说明“质量权重最高”也不等于永远选最昂贵模型。balanced 的合成质量略低,但在这个 Fixture 中,它的成本和 TTFT 优势仍让总分更高。

如果真实评测显示 balanced 无法通过迁移测试门槛,它会在第二层被淘汰,届时才选择 deep-reasoning

错误反例:全局选择最便宜模型

错误实现:

selected = min(models, key=lambda model: model.cost)

在本文 Fixture 中,它永远选择 fast-small,结果是:

  • 客服分类:可能合适;
  • EU 票据:没有 Vision,也不满足区域约束;
  • 代码迁移:32K 上下文装不下 100K 请求。

先选最便宜模型会撞上能力和合规硬约束

同类错误还有:

  • 先按平均延迟选择,再检查模型是否支持工具;
  • 用全站统一权重处理所有任务;
  • 把 429 的模型直接换成语义不兼容的便宜模型;
  • 把模型质量榜单分数当作自己的任务成功率;
  • 忽略缓存亲和,在多个部署间随机打散长前缀;
  • 把失败后的模型切换算作同一次“负载均衡”,不记录降级。

可运行的离线实验

实验脚本只使用 Python 标准库,核心结构如下:

def eligible(model, task):
    reasons = []
    if task["tools"] and not model.tools:
        reasons.append("tools")
    if task["vision"] and not model.vision:
        reasons.append("vision")
    if model.context_k < task["context_k"]:
        reasons.append("context")
    if task["region"] and model.region != task["region"]:
        reasons.append("region")
    return reasons


def score(model, weights):
    return (
        weights["quality"] * model.quality
        + weights["cost"] * (1 - model.cost)
        + weights["latency"] * (1 - model.ttft)
        + weights["health"] * model.health
    )

真实上线时,应把合成字段替换为:

  • 每类任务版本化的离线评测结果;
  • 实际 usage 与供应商价格换算的成本;
  • p50/p95 TTFT 与总生成时间;
  • 429、5xx、超时和中断后的健康统计;
  • 可用上下文、工具、模态与区域能力目录;
  • Prompt Cache 的命中和亲和信息。

每次决策至少记录:

{
  "policy_version": "router-2026-07-20",
  "task_class": "invoice-vision-eu",
  "eligible_models": ["balanced"],
  "rejected": {
    "fast-small": ["vision", "region"],
    "deep-reasoning": ["region"]
  },
  "selected_model": "balanced",
  "selected_channel": 17,
  "fallback_chain": ["balanced-backup"],
  "decision_reason": "only candidate satisfying vision+EU"
}

这样才能回答“为什么这次没有走更便宜的模型”。

静态规则、加权评分、级联分别什么时候用

静态规则

适合:

  • 任务类型清楚;
  • 合规要求严格;
  • 缺少可靠质量数据;
  • 模型数量较少;
  • 希望决策容易审计。

例如:

EU invoice + vision → eu-vision-balanced
code migration > 64K → long-context-code pool
support classification → fast-tool pool

静态规则并不落后。错误的“智能评分”通常不如诚实的规则表。

加权评分

适合:

  • 候选都已满足硬约束;
  • 有稳定、同口径的质量和性能数据;
  • 需要连续调整成本/延迟权衡;
  • 能做影子评估与回放。

风险包括归一化漂移、权重互相补偿和指标延迟。必须版本化权重和输入快照。

级联路由

级联不是故障重试,而是:

先调用低成本模型
→ 用确定性验证器检查结果
→ 不合格才升级到更强模型

适合有强验证器的任务:JSON Schema、单元测试、规则校验、OCR 字段完整性。若验证器只是另一个模糊的 LLM Judge,升级决策本身也需要评测。

级联总成本为:

cheap_cost + escalation_rate × expensive_cost

不要只展示首个模型的价格。

回退策略不能只看失败

模型或渠道回退至少分三类:

类型例子建议
同模型、同协议部署切换某区域连接失败首 Token 前可切换,风险较低
同能力模型切换主模型 429,备选支持同样 tools/schema先验证协议与质量门槛,记录降级
跨能力降级Vision 模型切到纯文本模型默认禁止,除非业务显式允许

LiteLLM 把部署重试、cooldown 和跨模型 fallback 分开,是一个有用的边界。上一篇LLM Gateway 与普通 API Gateway 的对比也说明:流式首 Token 已发送后,透明重放可能造成重复文本、损坏工具参数和重复计费。

更详细的 429、退避与故障切换状态机会在 #107 单独做故障复盘,本篇不把“路由”扩张成所有可靠性问题。

Prompt Cache 会改变最优路径

如果两个渠道都提供同一模型,最短延迟的渠道不一定是总成本最低的渠道。稳定前缀已经在渠道 A 建立缓存时,下一次请求随机切到 B,可能失去缓存读取折扣和 TTFT 收益。

因此可以把缓存亲和作为:

  • 软偏好:A 健康时提高分数;
  • 有限硬约束:短 TTL 会话窗口内固定渠道;
  • 降级条件:A 错误或用量上限后清除亲和并切换。

Nbility 当前代码已经有渠道亲和:先尝试缓存中的 preferred channel,确认渠道启用、路径、模型和分组仍可用;成功请求后记录亲和。候选失效时是否保留、清理或禁止重试由配置决定。

这不等于 Nbility 当前已经实现本文的质量/成本/TTFT 自动加权模型选择。当前代码可验证的能力是:

  • Token 模型权限和分组准入;
  • ModelMapping
  • 渠道启用与用量上限过滤;
  • 优先级分层;
  • 同优先级按权重随机选择;
  • Retry 时下降到下一优先级;
  • 渠道亲和;
  • 记录请求模型、上游模型、渠道与计费。

质量评分器和按实时 TTFT/成本自动选不同模型,应当作为上层策略服务或明确配置,而不能写成现有产品能力。

Nbility 的优先级与权重到底表示什么

当前 GetRandomSatisfiedChannel 的实际顺序是:

  1. 按 group、model 和 request path 获取渠道;
  2. 跳过达到用量上限的渠道;
  3. 收集可用优先级并从高到低排序;
  4. 首次请求选择最高优先级;
  5. 同一优先级按 weight 做加权随机;
  6. Retry Index 增加时进入下一优先级。

所以可以用:

  • 优先级表达主渠道与备用渠道;
  • 权重表达同一层渠道的流量比例;
  • Model Mapping让应用别名映射到上游真实模型;
  • 分组表达价格、权限或服务等级边界;
  • 亲和维持会话或缓存路径。

但不要把 weight=80 解读为“质量占 80%”。它是同优先级候选的流量权重,不是多目标决策权重。

上线前的门禁

  • 先定义任务分类,而不是先选模型
  • 能力、上下文、权限、区域作为硬约束
  • 每类任务有独立质量评测和最低门槛
  • 成本使用实际输入/输出/缓存结构估算
  • 延迟同时看 TTFT 与总生成时间
  • 健康度区分 429、额度不足、5xx 和超时
  • 同模型部署均衡与跨模型选择分开
  • 回退前验证 tools、schema、模态和上下文兼容
  • 首 Token 后不透明重放完整流
  • 缓存亲和有清除和故障旁路策略
  • 每次决策保存 Policy Version 与拒绝原因
  • 新策略先做离线回放、影子流量和小比例灰度
  • 业务成功率变差时能快速回滚

结论

多模型路由的核心不是“随机切换三家模型”,也不是把质量、成本和延迟放进一个看起来精确的公式。

正确顺序是:

  1. 用能力、上下文、权限和合规做硬过滤;
  2. 用任务级评测设置质量门槛;
  3. 只在合格候选中优化成本、TTFT、健康和缓存亲和;
  4. 选定模型后再做同模型渠道负载均衡;
  5. 把故障重试与跨模型降级分开;
  6. 记录每次决策,持续用真实结果更新策略。

如果暂时没有质量数据,先从 Nbility 的模型别名、分组、优先级、权重和渠道亲和构建可解释的静态策略,而不是伪造一个“智能路由分”。随着真实日志与任务评测积累,再把评分器放到稳定模型入口之前。可在 Nbility 查看统一模型接入能力,或通过工单中心申请小额测试额度。

官方与第一方资料

相关文章

用 Nbility 跑通你的 Agent 工作流

获取 API Key,统一接入 OpenAI 兼容模型和开发工具。

管理 API Key