公司动态

动态选择模型实战:多模型路由与调度策略详解

📅 2026/8/31 14:09:21
动态选择模型实战:多模型路由与调度策略详解
动态选择模型这个词在很多实际项目里并不叫“动态选择模型”而是叫模型路由、级联推理、条件模型选择或者多模型调度。它解决的问题其实很具体当系统里已经存在多个模型时怎么让每个请求自动选择最合适的那个模型来处理而不是所有请求都走同一个模型。对于做推荐、文本分类、OCR、客服机器人、内容审核这类场景的人来说这个方案最值得先理解清楚的是它不是简单地把多个模型都跑一遍再挑结果而是在请求进来之前就决定谁上场、谁跳过。这样做的好处是可以在精度、延迟、成本之间做动态权衡坏处是引入了一层额外的路由逻辑如果设计得不好可能比单模型更容易出问题。这篇文章按实际落地顺序拆一遍动态选择模型到底解决什么问题准备阶段需要什么条件单条请求怎么走通批量生产怎么接参数怎么调以及最常见的几个坑和排查链路。我按真实项目里最容易踩的地方来写不会只堆概念。1. 先想清楚动态选择模型解决的是精度、延迟还是成本问题很多人第一次接触动态选择模型第一反应是“是不是把多个模型做成一个大模型”。不是。动态选择模型的核心是引入一个决策层它根据输入样本的特征、当前系统负载、可用资源、业务要求从候选模型池里挑一个最合适的模型来执行推理。决策发生在请求进入模型之前不是发生在结果出来之后。1.1 单模型为什么不够用单模型方案之所以常见是因为简单。所有请求进同一个模型输出一致行为一致排查也相对容易。但实际业务里会遇到三个问题第一个是精度不够。文本分类里某些类别样本量少分类器很容易混淆OCR里打印体和手写体的难度差异很大推荐系统里冷启动用户和活跃用户的行为模式完全不同。一个模型很难在所有输入分布上都做到最优。第二个是延迟压力。大模型精度高但推理耗时长小模型速度快但精度相对低。如果所有请求都走大模型高峰期延迟会明显上升成本也会跟着涨。第三个是资源浪费。请求类型千差万别很多简单请求根本不需要大模型来处理。比如文本分类里类别非常明显的短句小模型已经能给出很高置信度没必要让大模型再跑一遍。这时候动态选择模型就有意义了。它把一个整体问题拆成两层底层是候选模型池负责实际推理上层是路由决策负责分发请求。1.2 动态选择模型不是传统的模型融合模型融合是把多个模型的结果组合起来比如投票、加权平均、Stacking。动态选择模型是只选一个结果不组合。这个区别很关键。模型融合适合你已经确定必须同时使用多个模型才能达到目标精度的场景但它的计算开销是成倍增加的因为每个请求都要跑完所有模型。动态选择模型适合你希望用最小代价达到业务精度要求的场景大部分请求可能只跑一个小模型只有少部分难样本才被路由到大模型。所以在设计之前就要明确一件事你做动态选择模型目标到底是省成本、降延迟还是提升整体精度。目标不同后面的路由策略完全不一样。如果目标是省成本那么只要大模型不跑就是好的如果目标是提升精度那么路由本身就必须是高精度的否则把难样本错误地分给小模型整体效果不但不会提升还会倒退。1.3 什么情况下不适合用动态选择模型这个也值得提前说。如果项目只有两个模型而且都是轻量级模型跑一次的成本都很低那引入路由层可能得不偿失。路由本身也需要计算它可能是规则、小模型也可能是一套查询逻辑都会带来额外延迟和维护成本。还有一种情况业务要求所有请求都必须经过同一个可解释性很强的模型不接受黑盒调度那动态选择模型也不适合。因为它意味着不同请求可能走不同模型行为不一致对解释和审计的要求更高。最好用动态选择模型的场景是模型池里存在明显的精度落差且请求分布呈现出“大部分简单、小部分难”的形态。这是最典型的收益空间。2. 落地前先把环境、模型池和评估基线准备好动态选择模型不是只做一个路由选择器它底下必须有一组可靠可用的候选模型还必须有评估基线。很多项目一开始就急着选路由策略结果候选模型本身问题一堆最后根本判断不了是路由的问题还是模型的问题。2.1 候选模型池的准备标准候选模型池至少要有两个模型通常包括一个基础模型和一个或多个高精度模型。基础模型要求速度快、成本低即便被错误路由到难样本上造成的损失也可控。高精度模型要求精度显著高于基础模型且推理耗时在可接受范围内。具体准备时要注意几点模型版本要固定不能出现“小模型昨天更新过一版大模型还是旧版本”的情况否则离线评估出来的路由策略上线后立刻失真。所有候选模型必须使用同一套输入输出规范。如果A模型接受纯文本B模型接受带特殊标记的文本路由层就要先做格式转换这会增加复杂度。每个模型最好能输出置信度分数。很多路由策略依赖模型自身置信度如果模型只返回标签不返回分数后面会非常被动。如果某个模型在特定类别上效果特别差要记录清楚。这些信息后面可以用来设计规则。2.2 路由决策需要哪些输入信息路由决策不是只能看样本文本。实际工程里可以用来做路由判断的信息很多大概分四类第一类样本特征。比如文本长度、是否包含特殊字符、图片分辨率、类别预测结果、模型置信度。这类信息在请求进来时就能拿到适合做实时路由。第二类请求元信息。比如用户ID、设备类型、渠道来源、业务类型。比如在客服系统里VIP用户的请求可能倾向于走更高质量的大模型普通用户请求优先走小模型保成本。第三类系统状态。比如当前服务负载、GPU排队队列长度、超时时间。如果大模型服务已经高负载路由层可以把一部分请求临时降级到小模型。第四类历史反馈。比如这个用户最近几天的点击行为、这个商家最近提交的内容质量分布。这类信息有时用于离线策略不一定适合在线实时获取。规则越复杂信息依赖越多路由层本身的开销和延迟就越高。所以一开始建议只用一个或两个信息源不要一上来把所有信号都接进去。2.3 先评测每个候选模型的上限和下限训练或部署路由策略之前要做一轮离线评测。评测方式很简单跑一遍验证集记录每个模型在每个样本上的预测结果、置信度和耗时。然后基于这份数据回答几个问题如果所有请求都走小模型整体精度是多少如果所有请求都走大模型整体精度是多少平均延迟是多少成本是多少走小模型时哪些样本的预测置信度很低低置信度样本里有多少其实被小模型预测错了如果用小模型置信度做阈值路由有没有一个阈值可以让整体精度接近大模型同时大模型调用比例控制在 20% 或 30% 以下这些问题的答案构成了动态选择模型的基线。后续无论用什么策略都要和“小模型全量”以及“大模型全量”这两个方案对比。这里有一个经验我一般不建议一开始就追求“整体精度超过大模型全量”的目标那是很难的。更现实的目标是通过动态路由让整体精度接近大模型同时成本或者延迟显著下降。如果业务确实需要精度超过大模型那通常需要引入更强的路由模型而不是简单用规则难度会大不少。3. 单条请求的动态路由是怎么走通的理解动态选择模型最好的方式是先看一次请求从进入到返回结果的过程中路由层到底在哪个节点上介入。这个流程跑通之后再做批量化和接口化。3.1 最小流程规则优先先看一个最简单的路由方案。假设模型池里有两个模型一个Fast小模型一个Large大模型。请求进来后系统执行对输入做标准化处理比如清洗文本、统一编码、裁剪图片。提取路由基础特征比如文本长度、类型标记、请求来源。先走规则判断。如果文本长度超过 1000 字直接路由到大模型因为小模型处理长文本时效果明显下降如果渠道是高风险审核直接路由到大模型。规则没命中的请求交给 Fast 模型处理。Fast 模型返回预测结果和置信度分数。如果置信度分数大于等于阈值比如 0.90直接把当前结果作为最终结果返回。如果置信度分数低于阈值说明 Fast 模型对这条请求不太有把握再把请求转发给 Large 模型处理。Large 模型返回结果后把该结果作为最终结果返回。这个方案里就出现了两个动态决策点一个是基于规则的直接路由一个是基于置信度的兜底路由。规则负责处理“一眼就知道不能走小模型”的样本置信度阈值负责处理“小模型虽然跑完了但不确定”的样本。伪代码可以是这样def route_request(text, meta): if len(text) 1000: return large_model.predict(text) if meta.get(risk_level) high: return large_model.predict(text) fast_result fast_model.predict_with_score(text) if fast_result.confidence 0.90: return fast_result.label else: return large_model.predict(text)这段代码相当简化但它足够说明动态选择模型的基本形态。3.2 为什么置信度阈值路由要先跑小模型很多人会问为什么不直接让路由模型判断“该走哪个模型”而是先跑小模型再看置信度因为置信度是一个非常有价值的信息来源。小模型即使在某些样本上是错的它给出的置信度也能反映它对该样本的把握程度。虽然置信度不等于正确率但趋势上低置信度样本的错误率通常更高。这样设计的好处是简单样本走小模型零额外决策开销只有小模型不太确定的样本才升级到大模型。从资源调度的角度看这是最节约的方式。坏处也很明显小模型跑完后如果置信度低会造成一次性无效推理增加了延迟。如果小模型的置信度普遍偏高哪怕它有大量错误也被高置信度放行了那这个阈值方案就不会有太大收益。所以在离线阶段一定要画一条置信度和错误率的关系曲线看看当前阈值下错误样本有多少能被拦住。3.3 动态选择模型里的回退策略回退策略是动态选择模型里最容易漏掉的部分。比如大模型服务超时了怎么办大模型本身返回异常怎么办路由层本身报错了怎么办。实际系统里我会建议每个请求都带一个 fallback 链。比如首选走 Large 模型但 Large 模型 3 秒内没有返回。当前请求自动用小模型补上。同时记录一条日志标明当前请求发生了降级以及降级原因。这个逻辑看起来简单但决定了系统在高峰期是否容易雪崩。如果没有回退策略路由层把所有难样本都转给大模型大模型因为负载高而超时调用方等着请求继续堆积最终大模型被打挂整体服务不可用。所以设计时一定要明确路由决策只是选择最优路径不保证所有路径一定成功。最优路径不可用时需要有可用的次优路径。4. 从单请求走向生产环境路由策略、参数设置和稳定性单请求跑通只是第一步。动态选择模型真正的复杂度出现在生产环境因为要处理批量请求、并发变化、模型版本更新、日志审计和异常恢复。这一节讲几个关键点。4.1 路由策略的两种形态生产环境里路由策略通常有两种形态。一种是规则型另一种是模型型。规则型最直白基于硬编码条件。优点是可解释性强上线快排查方便缺点是规则覆盖不了所有情况碰上复杂分布容易漏。模型型是训练一个轻量级分类器或者打分模型输入样本特征输出“该走哪个模型”。优点是能学到更复杂的模式比如某些用户群体、某些写法风格与模型性能之间的关系缺点是引入了额外的开发、训练和维护成本而且路由模型本身也可能有错误。选择规则还是模型主要看路由逻辑能不能用几行条件表达清楚。如果只是文本长度、渠道来源、置信度这三个维度规则足够。如果发现规则要写几十条而且相互覆盖那就该考虑训练一个路由模型了。4.2 核心参数到底怎么调动态选择模型的参数在不同实现里差异很大但有几个最常见的参数需要重点理解。置信度阈值 C 是最关键的一个。C 设置得高升级到大模型的请求就少成本低但整体精度可能偏低C 设置得低升级到大模型的请求变多精度提升但成本也上升。调参方法是先离线画出不同的 C 值下精度和成本的曲线再根据业务预算选择。不要凭感觉定。路由权重 W 在多规则场景中使用。比如文本长度规则和置信度规则同时生效时各自的优先级是什么是否互斥。一般建议规则之间设置优先级不要并行判断否则可能出现一个请求被多个规则指向不同模型的情况。超时时间 T 也很关键。给大模型设置超时时间比如 2000 毫秒。超过后立即走回退逻辑。T 太短会经常降级T 太长会拖慢整体响应。批量大小 B 在高并发场景下会用到。如果服务是批处理式的比如同时处理 32 条文本那么路由层既可以对每条样本单独决策也可以对整个批次统一决策。统一决策的好处是吞吐高坏处是粒度粗。参数表格可以这样列参数含义调整方向影响置信度阈值 C小模型置信度达到多少后直接返回调高则升级少、省成本精度可能下降路由优先级多条规则冲突时谁先生效按业务重要性排决定难样本去向超时时间 T高精度模型最大等待时间调大则降级少延迟可能上升批量大小 B一次路由决策覆盖的样本数调大则吞吐高路由粒度变粗降级开关是否允许临时走小模型关闭则稳定但易雪崩影响可用性4.3 日志结构与可观测性动态选择模型的日志比普通模型更复杂因为每一次请求都会产生两条相关信息路由决策信息和模型输出信息。没有日志几乎没法排查线上问题。我建议每条请求至少记录以下字段request_id全局唯一请求 ID。输入摘要比如文本长度、来源渠道、是否命中规则。route_type本次是用规则、置信度还是模型路由做的决策。selected_model最终选择执行推理的模型名称。fallback_used是否发生过降级。model_confidence所选模型的置信度分数。latency_ms路由阶段耗时、模型推理耗时分开记录。final_result最终输出内容或标签。这些日志有两个用途。一是日常排查比如某条请求被错误路由到了不合适的小模型可以通过 request_id 直接看到路由链路二是离线分析比如每周统计一次路由分布判断高精度模型调用比例是不是在持续升高。4.4 模型版本更新时的路由策略调整动态选择模型会带来一个特有麻烦某个候选模型升级后旧的路由策略可能失效。比如大模型从 v1 升级到 v2精度提高了原来 20% 的大模型调用比例现在可能只需要 15% 就够了或者小模型升级后置信度更准了原阈值 0.90 可以提高到 0.93。所以每次模型更新不能只评估模型本身的指标还要重新评估路由策略的参数。建议把路由策略配置做成可动态更新的比如放在配置中心或独立配置文件中不写死在代码里。这样模型更新后可以快速调整阈值和规则不用重新发布服务。有一次我遇到过这样的情况小模型更新后整体置信度都偏高结果大多数请求都直接命中阈值返回高精度模型调用比例从 30% 掉到 8%整体精度也下滑了。问题不在于小模型变差而在于置信度分布变了阈值没有跟着调整。这类问题如果没有日志极难定位。5. 批量任务、接口化和性能优化动态选择模型不止用于在线实时请求在离线批量任务里也很常见。比如每天对一批新文本做分类或者对图片库做审核打分。批量场景与在线场景的核心差别在于对延迟和并发的容忍度不同。5.1 批量任务怎么接入动态路由在线请求重视单条响应时间批量任务更重视整体吞吐和成本。批量任务接入动态路由时可以先对整批数据做一次预分析统计出高置信度样本和低置信度样本的占比然后分批处理。我一般会这样设计先把批量样本全部用 Fast 模型跑一遍并记录置信度。把所有样本按置信度排序。置信度高于阈值的样本直接采用 Fast 模型结果。置信度低于阈值的样本重新打包统一交给 Large 模型处理。输出时合并两部分结果并生成统计报表。这样做的好处是Large 模型可以一次性处理所有低置信度样本减少模型切换的开销便于批量推理时做显存和内存规划。5.2 接口化时的输入输出设计如果要把动态选择模型封装成 HTTP 接口建议输入包含两个部分待处理数据和可选路由标记。一个示例 JSON 请求{ data: { text: 今天天气不错适合出门走走。 }, meta: { channel: app, user_level: normal }, route: { force_model: , skip_route: false } }force_model字段用来强制指定某个模型适合灰度、A/B 测试和问题复现。skip_route字段用来跳过路由层直接使用默认模型适合内部调试。接口返回时除了预测结果还要把路由相关信息带出来{ code: 0, data: { final_label: positive, final_score: 0.96, route_info: { selected_model: large_model_v2, route_type: confidence_fallback, fast_score: 0.71, fallback: true } } }我会特别建议保留final_score和route_info因为下游业务可能需要用分数做二次阈值判断运维需要知道模型是否发生过降级。5.3 性能优化的常见方向动态选择模型的性能瓶颈往往不是模型本身而是路由层和资源调度层。第一个方向是降低路由判断开销。如果路由逻辑是规则型尽量用纯内存判断不要每次请求都查询外部数据库。比如渠道、用户级别这类元信息应该通过请求头直接传入而不是让路由层去查库。第二个方向是减少模型切换次数。模型切换通常意味着重新分配显存或者重新建立连接。如果服务里有多个模型同时加载要合理规划模型常驻策略。比如 Fast 模型始终常驻Large 模型只在有请求时加载但配置一个最短存活时间避免频繁加载卸载。第三个方向是并发控制。动态选择模型容易在大模型并发上踩坑。路由层把所有低置信度请求都转给大模型大模型并发数瞬间飙升导致每个请求都变慢。建议在路由层增加一个并发限制器当大模型当前并发数超过上限时临时走小模型或者排队等待。第四个方向是缓存。如果同样的输入会反复出现比如客服常见问题可以在路由层之前加一层缓存。命中缓存时直接返回历史结果根本不需要做任何模型推理。5.4 延迟统计要分开看动态选择模型的延迟不能只看平均耗时要看 P50、P95 和 P99。因为大多数简单请求走 Fast 模型P50 通常很低但低置信度升级到大模型的请求耗时可能是 Fast 模型的几倍P99 会显著拉高。如果 P99 过于严重可以考虑在路由层做“最多升级一次”的限制。比如一条请求从小模型升级到大模型后即使大模型输出的置信度也低也直接把大模型结果返回不再继续切换。这样能避免请求在模型池里来回跳造成最坏情况延迟不可控。6. 常见问题与排查链路动态选择模型的问题排查比单模型复杂因为一个问题可能出在候选模型、路由规则、参数阈值、服务中间件等多个环节。下面按排查顺序整理几个最常遇到的问题。6.1 现象整体精度不如预期先不要怀疑动态选择模型方案本身没用先看三张统计图路由分布图、置信度分布图、混淆矩阵。排查顺序看有多少请求走了小模型多少请求走了大模型。如果大模型调用比例很低说明阈值或者规则太松。看走小模型的请求里置信度分布如何。如果大量请求的置信度都压着阈值附近说明阈值定得不够稳。看走大模型的请求里最终结果是否正确。如果大模型调用比例很高但整体精度没有显著提升可能是路由过度保守把大量本应走小模型的样本升级了。如果是规则路由还要检查规则是否覆盖了错误样本。最容易出现的问题是规则写得太宽或太窄。比如规则“文本长度大于 50 就转大模型”如果业务里大部分文本长度都在 40 到 60 之间这条规则会把很多简单样本误转到大模型成本上升但精度没提升。6.2 现象线上耗时突然升高耗时升高可能有几个原因按概率从高到低排序大模型并发被占满请求在大模型队列里排队。路由层增加了额外网络请求比如查询某个远程配置。小模型失效导致所有请求都直接走了大模型。文本输入长度异常增大比如某段时间进来的文本长度是平时的十倍。排查时先看路由日志中 selected_model 的分布。如果 large_model 调用比例异常升高优先检查小模型服务和置信度阈值。如果大模型调用比例正常再看大模型服务本身的 P99 耗时。这里有一个比较容易踩的坑置信度阈值如果设置得太高高到大部分正常样本都达不到就会导致大量请求升级到大模型线上延迟随之飙升。遇到这个问题时先回看离线置信度分布确认阈值对应的样本占比是不是符合预期。6.3 现象结果在两套模型之间频繁跳跃同一个用户在相似输入下有时走小模型有时走大模型返回的结果可能不一致。这种“跳变”在业务侧很难解释。产生跳变的原因通常是路由特征本身不稳定。比如请求里带了用户等级用户等级近期发生变化或者文本长度对路由影响很大稍微改一个字就跨过长度阈值。解决办法有两个方向。一是让路由决策更稳定比如对文本特征做分桶长度在某个区间内不因为边界值导致跳变。二是在结果返回时附带路由信息业务侧能感知到结果来自哪个模型对不同模型的结果做不同处理。如果是置信度阈值路由导致的跳变可以考虑加入“迟滞区间”。比如当 Fast 模型置信度大于 0.92 时直接返回小于 0.88 时才升级中间区域延续上一次的路由决策。这个策略能明显减少短时间内的模型跳变但也会让系统表现得不如之前“敏感”需要结合业务取舍。6.4 现象模型池中某个模型突然不可用这是动态选择模型最有压力的一种情况。小模型挂了所有请求都只能走大模型延迟和成本可能双双升高大模型挂了低置信度请求没有兜底直接失败。建议在设计初期就做好几件事每个候选模型都提供健康检查接口路由层定期探测。路由层缓存健康状态不健康时自动摘除该模型并把请求转移给其他模型。所有模型都不可用时保留一个最后兜底方案比如返回默认结果或走一个最基础规则保证服务不彻底挂掉。模型恢复后不要立刻把流量切回先按 10% 比例慢慢回切观察几分钟避免复活的模型带着异常状态把线上请求打崩。6.5 排查链路总结我自己的排查顺序可以归纳成五步先看现象是精度问题、延迟问题、成本问题还是可用性问题。再看路由日志确认请求最终走了哪个模型是否发生了降级路由类型是什么。再看候选模型被选中模型的输入是否正常置信度分数是否异常模型服务自身耗时和错误率如何。再看参数配置置信度阈值、超时时间、并发上限、降级开关是否和线上状态匹配。最后看输入分布是不是输入数据本身发生了漂移导致原有路由规则不再适用。每一步都对应到具体日志和监控指标。没有日志动态选择模型几乎是不可运维的所以日志字段的设计一定要提前做好。7. 什么情况下应该放弃动态选择模型不是所有系统都应该用动态选择模型也不是所有业务都能从动态选择模型里受益。最后说几个我见过的反例。第一种情况模型池里只有一个模型效果显著好于其他模型。那动态选择模型没有意义直接全量用最好模型就行。第二种情况路由层本身需要复杂特征而这些特征获取成本高于模型推理成本。比如为了判断一条文本该走哪个模型必须先调用另一个接口获取用户画像这个接口本身就耗时几百毫秒那路由的收益已经被吃掉了。第三种情况业务无法接受结果来源不统一。比如某些合规场景要求所有同样输入必须得到同样输出动态选择模型会因为并发状况、阈值波动导致结果不稳定这类场景就应当谨慎使用。第四种情况团队没有日志系统和基础监控能力。动态选择模型的复杂度远高于单模型如果连基本的路由日志都没有出了问题基本靠猜那上线后会很痛苦。如果识别到这些情况更稳妥的做法是先保持单模型方案把资源投入到优化模型本身而不是在模型外层叠加调度逻辑。动态选择模型是一个看起来简单、实际落地时容易被低估的方案。它的核心收益不是来自某个模型本身而是来自“哪些请求该用哪个模型”的调度质量。先把离线评估做好再把单请求流程跑稳然后逐步加批量、加接口、加参数化配置最后再把监控和日志补齐。按这个顺序走比一开始就追求复杂路由策略要稳妥得多。