跳到主要内容

一次多模型路由策略的简化记录

· 阅读需 4 分钟
一介布衣
全栈开发者 / 技术写作者

补档说明:本文属于「AI 工程落地周记」系列,计划发布时间为 2025-10-05 16:10。当前先保留为草稿,后续补充真实案例、代码片段和复盘细节后再发布。

有一阵子我们把多模型路由做得越来越“聪明”:

  • 先按任务类型分
  • 再按风险等级分
  • 再按上下文长度分
  • 再按历史命中率分
  • 失败后还有二级 fallback

纸面上看,这套策略非常精细。真正上线后,问题却越来越明显:

  • 成本走势很难解释
  • 某个请求为什么走了某个模型很难追
  • 调一条规则,别的路径会不会被带偏不清楚
  • 出现效果抖动时,排查几乎像在查一个“规则黑箱”

后来我们做了一次很克制的重构:不是继续加规则,而是把路由策略砍掉一大半。结果反而更稳了。

复杂的不是模型数量,而是路由层的可解释性

多模型路由最容易让人上瘾的地方在于:每加一条规则,都像是在补一个洞。

例如:

  • 长上下文走大模型
  • 高风险走强模型
  • 结构化输出失败再回退一次
  • 某类短问答走便宜模型

局部看都合理,但当规则叠到一定程度后,系统的真实成本就不在模型上,而在路由本身的复杂性上。

因为你需要额外维护:

  • 规则优先级
  • 冲突处理
  • 命中日志
  • fallback 路径
  • 每条路径的评测与回归

这已经不是“选模型”了,而是在维护一个推理调度系统。

我们当时为什么决定简化

真正触发简化的不是某次大事故,而是这些持续的小信号:

fallback 比例解释不清
某些请求成本波动很大
线上 trace 太长但结论不明确
同样问题在两周内路由路径经常变

这些信号说明一个问题:路由规则已经开始吞噬团队的认知预算。

后来我们把它砍成了三层

我们最后把原来一大串判定逻辑收敛成三层:

第一层:默认模型

绝大部分请求先走一个性价比最好的默认模型。

第二层:明确升级条件

只有满足少数几个清晰条件才升级,例如:

  • 上下文超长
  • 高风险分类命中
  • 结构化任务且旧模型已知不稳定

第三层:单次 fallback

如果默认模型失败,允许一次受控 fallback,但不再做多级递归回退。

大致像这样:

function routeRequest(input: RequestContext) {
if (input.riskLevel === 'high') return 'strong-model'
if (input.contextTokens > 12000) return 'long-context-model'
return 'default-model'
}

function fallbackModel(primary: string, reason: string) {
if (reason === 'schema_parse_failed') return 'strong-model'
return null
}

这套逻辑不算“最聪明”,但它有一个特别大的优点:人能看懂。

简化之后实际改善了什么

1. 路径可解释

一个请求为什么走这条路,基本能一句话说明白。

2. 评测能对齐

路由分支少了之后,每条路径都更容易单独做评测和回归。

3. 成本更容易控

你终于能清楚知道:

  • 默认模型吃了多少流量
  • 升级条件触发了多少次
  • fallback 到底是正常保护,还是系统异常信号

4. 排障速度更快

以前排一个异常请求,先要理解一长串路由树。
现在路径短了,根因也更容易收敛。

我现在对多模型路由的一个偏见

我越来越倾向于认为:
多模型路由的上限,不是由你能写多少规则决定的,而是由团队能稳定理解多少条路径决定的。

一旦路径数超过人脑能长期掌控的范围,系统就会开始以“局部聪明、整体难管”的方式变差。

什么时候该加规则,什么时候该删规则

我现在会用两个问题判断:

  1. 这条规则能否稳定提升某一类明确场景?
  2. 这条规则的命中和收益能否被单独观测?

如果答案都不够清楚,我更愿意不加。
因为路由规则一旦上线,就不是一行 if,而是一条要长期被维护的行为分支。

总结

这次多模型路由策略的简化记录,最后留下的结论很直接:
路由不是越细越高级,很多时候越简单越可控,越可控才越接近真实收益。

对 AI 系统来说,真正有价值的不是把每个请求都“精细优化”到极致,而是用足够少、足够清楚、足够可观测的路径,把大部分请求稳定接住。