先讲一个场景。某企业内部Agent在生产环境跑了大半年,某天深夜核心模型服务商侧发生故障,调用超时率从0.1%一路飙到40%。团队紧急启用“备用模型”,结果发现备用模型的输入输出格式完全不同,下游业务方写的解析逻辑全部失效,加上铺天盖地的上游限流,故障整整持续了四个小时才恢复。
这其实是企业Agent建设中最容易被低估的一块:模型路由与容灾。很多人觉得“备了一个模型就能切换”,可真到故障发生时才发现,模型路由根本不是把请求从一个地址改到另一个地址那么简单。它涉及模型网关的流量调度、健康检查与探活机制、超时与重试策略、熔断与降级逻辑、请求上下文与状态同步、成本与预算约束、以及多模型切换后的语义一致性校验,牵扯的是一整套系统工程。
这篇文章基于我自己的实际落地经验来聊一聊,企业Agent场景下模型路由与容灾到底该怎么设计、怎么配置、怎么排查。内容核心围绕“为什么不能只配备用模型”展开,适合正在做Agent基础设施、模型网关层、或者负责AI服务稳定性保障的同学参考。
1. 企业Agent的模型路由与容灾,为什么“备用模型”远远不够
1.1 你所面对的故障,远不止“服务不可用”
在单体模型调用时代,容灾的惯用思路确实简单:主模型挂了,把流量切到备用模型。但这个思路默认了几个前提,而这些前提在企业级Agent场景下几乎都不成立。
第一个被忽略的前提是:故障并不仅仅是“连不上”。我在实践中遇到过各种各样的情况,比如模型服务商返回200但内容全是乱码,模型服务商返回200但推理速度慢到超时,模型服务商在某些Prompt下反复返回空内容,还有限流导致的429时有时无。单纯“切到备用模型”解决不了这些问题,因为系统根本没有意识到主模型已经“事实上故障”了。
第二个被忽略的前提是:备用模型必须和主模型“等量齐观”。企业Agent通常不是单点调用模型,而是把模型嵌入到复杂的业务流程中——结构化输出解析、工具调用、上下文记忆、Prompt模板、敏感信息过滤、后置校验等等。换了模型以后,这些环节全部可能出问题。比如主模型输出的JSON结构比较稳定,备用模型同一个Prompt下可能会换Key、换枚举值、甚至直接输出自然语言。下游解析人肉返工,故障没有消失,只是换了一种形式。
第三个被忽略的前提是:模型路由影响的不只是“这一次请求”。Agent场景下,多轮对话状态、记忆内容、工具调用链、知识库检索结果,都可能被路由策略直接影响。切到备用模型后,上下文格式是否兼容?历史消息截断策略是否需要调整?工具调用参数schema是否一致?这些都是“备用模型”方案解决不了、又真实影响线上质量的问题。
所以说,模型路由与容灾的真实目标不是“故障时切走”,而是“故障时尽量无感地切换,故障后快速恢复”,这需要一套完整的模型网关能力和容灾流程来支撑。
1.2 模型路由与容灾的本质:把模型调用当作基础设施来治理
把模型调用当作普通第三方API来对待,是很多Agent项目难受的根因。普通API有明确的签名、稳定的SLA,但模型调用是多变的:同一个模型不同版本、同一个Prompt不同温度、同一个请求不同时间,返回结果都可能不同。这种不确定性本身就要求你在路由层做比普通API更复杂的治理。
我的理解是,模型路由与容灾本质上要解决四个问题。
第一,流量分发能力。在多模型、多版本、多供应商并存的情况下,让每次请求能按策略被分发到正确的模型实例上。
第二,故障感知能力。能实时识别模型实例的健康状态,不只是通不通,还包括快不快、稳不稳、准不准。
第三,故障应对能力。当模型实例出现异常时,自动执行重试、降级、熔断、切流等动作,且过程对业务方尽量透明。
第四,质量保障能力。切换后仍能保证Agent业务的核心质量——结构化输出可解析、语义不过度漂移、状态不丢失。
这四个能力,落到技术架构上,就是模型网关、健康检查机制、路由策略引擎、容灾切换编排这四块。下面我会分别展开。
2. 模型路由层的整体架构设计
2.1 优先在企业内部收敛一个模型网关
很多人问我的第一个问题是:模型路由到底该做在哪一层?直接写在业务代码里行不行?我的答案是:短期可以,长期不建议。一旦接入的模型数量超过两个、调用量达到一定规模,写在业务逻辑里的路由代码就会变成灾难——每个业务团队都要自己维护供应商对接、超时配置、重试逻辑,出问题时互相不知道对方切到了哪个模型,线上乱成一锅粥。
推荐的做法是在企业Agent中收敛一个独立的模型网关层,对外提供统一的模型调用协议,例如一个兼容通用对话接口规范的路由入口。业务方只依赖网关,不感知背后具体是哪个模型、哪个供应商。网关内部再拆成四个子模块:供应商适配层、路由策略引擎、健康检查与探活模块、容灾编排模块。
供应商适配层解决“格式差异”问题。不同模型提供商的接口风格、超时时间、错误码、限流策略千差万别,适配层负责把这些差异收敛成网关内部统一的模型调用抽象。在适配层做格式归一化非常关键。之前有团队直接在两套供应商API之间做切换,响应字段一个叫choices一个叫output,业务方写了两套解析代码,故障期间切换后立刻出现大面积解析报错。如果适配层在一开始就统一了内部响应结构,这类问题根本不会出现。
路由策略引擎和健康检查模块是路由与容灾的两大核心,我会单独在下面的小节展开。容灾编排模块则负责把故障发现、切换决策、流量迁移、回切评估串成一条完整的链路。
2.2 路由层必须统一收敛的核心能力
在模型网关里,有几个核心能力是必须内置的,否则后续容灾根本无从谈起。
第一个是超时管理。模型调用不像普通API那样“超时就是失败”这么简单。模型推理耗时长,容易受排队影响,超时时间设置太短会误伤正常请求,设置太长又会拖垮下游。实践中我会针对不同模型、不同业务场景分别配置超时策略。比如,内部知识库问答场景,允许较长的推理时间,首字时间超过某个阈值就降级到备用模型;而外部用户交互场景,对延迟更敏感,超时阈值应更短。网关层面必须把超时配置做成可针对模型和场景动态调整的,而不是写死在代码里。
第二个是重试与幂等控制。模型调用天然适合在超时或网络抖动时重试,但重试又容易放大流量。我在网关里会内置重试次数和退避策略,同时用请求ID串联一次服务的多次重试,避免业务层重复计费。有些模型接口不支持幂等,重试前必须在网关层做保护,例如同一上下文短时间内的重试只放行一次。
第三个是灰度与动态切换能力。路由策略的调整不能靠改代码发版实现,要能在配置中心中动态修改。模型权重、优先级、备用策略这些参数,随时可能需要调整。没有动态配置能力,容灾就只能停留在“理论上可行”。
第四个是可观测性。模型网关必须记录每一次路由决策、模型选择、延迟、错误、重试情况。否则故障发生时你连最初哪一次调用开始异常、哪些流量被切到了哪个模型都说不清楚,排障会非常痛苦。
2.3 一个最小可落地的模型网关配置示例
这里我给一个简化的网关配置参考,基于常见实践,大致长这样:
gateway: providers: - name: provider_a type: openai_compatible base_url: https://api.internal.example.com/v1 protocol: openai models: [agent-main, agent-fast] - name: provider_b type: custom base_url: https://internal-model.example.org/generate protocol: http_json models: [agent-backup] routes: - id: agent_chat_route match: app: agent-chat scene: multi_turn_chat strategy: priority_failover candidates: - model: agent-main provider: provider_a weight: 100 - model: agent-backup provider: provider_b weight: 0 failover: enable: true conditions: error_rate: 5% p95_latency_ms: 3000 backup_models: - model: agent-backup provider: provider_b timeout: connect_ms: 500 read_ms: 5000 overall_ms: 30000 retry: max_attempts: 2 backoff: exponential initial_delay_ms: 300注意这个配置里的两层路由思路:正常状态下流量全走主模型,但failover条件里同时挂了“错误率”和“延迟”两类指标。这个配置的作用是让网关在错误率或延迟超标时,自动把后续流量切到备用模型。后面我会再展开具体如何设计这些阈值,这里先让大家对整体配置结构有个直观感受。
3. 路由策略设计:不只是“默认优先,故障切换”
3.1 路由策略的几个维度
很多团队说起路由策略,第一反应就是“主模型优先,挂了切备用”。这个策略够用,但远远不够精细。在Agent场景里,我建议按以下几个维度综合设计路由策略,效果会好得多。
按业务重要性路由。核心业务链路(比如支付助手、客服售后)对稳定性要求极高,优先选最稳定的模型,哪怕贵一点;非核心业务(比如内部知识问答、辅助写作)可以优先选成本更低的模型,稳定性要求相对低。这种策略的本质是把路由决策与业务SLA绑定,而不是一刀切。
按请求上下文路由。多轮Agent对话要根据上下文长度、语言类型、是否需要工具调用等特征,动态选模型。比如,上下文很短、只需要简单问答的场景,用它跑得又快又便宜;上下文很长、需要复杂推理的场景,则切换到更强的模型上去。这个维度在真实Agent系统中非常实用。
按成本预算路由。企业部署Agent必然要考虑单次调用成本。网关可以把模型价格配置化,路由时综合考虑效果、稳定性、成本,在满足约束的前提下选择性价比更高的模型。例如,某个场景下模型A和模型B效果接近,但模型A价格是模型B的三倍,就可以在低峰期将部分流量切到模型B,降低成本。
按供应商风险路由。完全依赖单一供应商是容灾的大忌。理想情况是至少接入两家供应商的模型,并且在路由策略层做一定的流量分散。不需要平均分配,但至少要保证备用供应商处于“随时可接管”的状态——定期真实调通、定期验证格式、定期比对输出质量,而不是只在配置中心写一个永远不用的URL。
3.2 优先级故障切换与加权轮询的取舍
模型路由常见的两种基础策略是优先级故障切换和加权轮询。优先级故障切换的目标是“尽量用最优模型,故障时切走”;加权轮询的目标是“多模型并行分摊流量,避免单点”。
优先级故障切换的优点是实现简单、模型质量有保证、排障直观。缺点是切换是“后知后觉”的——已经出故障了才切,切换期间可能有部分请求受损;而且主模型恢复后,要不要回切、什么时候回切,需要额外设计。
加权轮询的优点是天然分散风险,某个供应商故障时只有对应比例的流量受损,不会全量崩溃。缺点是如果备用模型质量明显不如主模型,轮询会持续削弱整体效果;而且统一轮询无法做到“核心业务走好模型、边缘业务走便宜模型”这种差异化调度。
真实场景中,我的建议是混合使用:核心链路用优先级故障切换,非核心链路用加权轮询,把不同策略的适用边界分清楚。
这里贴一个简化的路由策略代码片段,演示优先级故障切换的思路:
public class PriorityFailoverRouter : IModelRouter { private readonly IModelHealthChecker _healthChecker; private readonly IModelInvoker _invoker; public async Task<ModelResponse> RouteAsync(ModelRequest request) { var candidates = GetCandidates(request.Scene); foreach (var candidate in candidates) { // 先检查健康状态,避免盲目请求 var health = await _healthChecker.CheckAsync(candidate); if (health.IsHealthy) { try { return await _invoker.InvokeAsync(candidate, request); } catch (ModelUnavailableException) { // 记录失败并继续下一个候选 await _healthChecker.ReportFailureAsync(candidate); } } } throw new AllModelsUnavailableException(); } }这个代码的逻辑很简单:遍历候选模型,跳过不健康的,优先调用排在前面的,调用失败就切换到下一个。真实环境里,这个Router还需要扩展:什么时候判定不健康、重试几次才切换、是否并发调用多个模型选出最优结果。后面几节会把这些细节补上。
3.3 语义路由:把请求分类后再选择模型
除了传统的基于可用性、成本的策略,企业Agent中还有一个常被忽略但收益明显的维度:语义路由。简单说,就是根据用户请求的内容和意图,把请求分类,然后按分类结果选择最适合的模型。
举个例子。企业内部Agent接收到的请求千差万别:“帮我查一下上个月销售报表”是数据分析场景;“根据这份合同拟一封催款函”是文本生成场景;“把这段会议录音整理成纪要”是音视频处理场景(可能还涉及外部工具);“解释一下transformer的原理”是知识问答场景。这些场景对模型的能力要求差异很大,有的需要强工具调用,有的需要长文本理解,有的只需要轻量生成。如果所有请求都堆到同一个最强模型上,成本和延迟都不可控;如果只用一个轻量模型,复杂场景又不够用。
语义路由的常见做法是,在网关或Agent接入层内置一个轻量的意图分类模块(可以是一个更便宜的小模型,也可以是一套规则分类器),先判断请求属于哪个场景,再由路由策略决定背后的模型。
def semantic_route(request): scene = classify_scene(request.text) if scene == "tool_call": return "agent-main-tool-v2" if scene == "long_context": return "agent-main-long" if scene == "simple_qa": return "agent-fast-lite" return "agent-main"这个策略的价值不在于“分类”本身,而在于它让模型路由真正开始服务于业务效果和成本控制。在实际Agent项目里,把语义路由和容灾结合,还能做到“轻度故障时,优先保核心场景”——例如模型出现部分能力退化时,让低价值场景先切到备用模型,核心场景继续留在主模型上观察。
3.4 预算感知路由:让成本成为路由决策的约束条件
长时间做企业Agent的同学都会遇到一个问题:模型调用成本每个月都在涨,财务开始问“这个模型钱花到哪里去了”。预算感知路由就是在这个背景下出现的。
预算感知路由的基本思路是:给每个业务线、每个场景设置预算上限或单次调用成本上限,路由算法在满足业务约束的前提下,选择成本最优的满足质量与稳定性要求的模型组合。落地时先把模型的输入输出价格配置到网关中,然后设置成本约束,再让路由策略在候选集中寻找满足条件的组合。
我认为预算感知路由不必一开始就做成复杂的优化算法,可以先从“按比例分流量”做起。例如:主模型效果更好但价格高,备用模型价格便宜但效果略次,那就设定一个8:2或9:1的流量比例,大部分请求走主模型,小部分请求走备用模型。观察一段时间,如果备用模型的质量、延迟、稳定性都达标,再把比例调高。这个方案的好处是实施门槛低,也能把成本曲线平滑下来,不会突然爆单。
4. 容灾流程的完整链路:发现、切换、恢复
4.1 故障发现:健康检查与探活机制
模型容灾的第一步不是“切流量”,而是“发现异常”。异常发现太慢,切换就没有意义;异常发现太快,又容易误伤正常请求。所以健康检查机制的阈值设计在容灾中极其重要。
健康检查分两个层次:基础探测和业务探测。
基础探测包括TCP连通性、接口响应码、响应延迟等。这是最基本的检查,一般几秒到几十秒探测一次。但基础探测的局限很明显:接口通不代表模型输出可用。我见过太多“网关显示服务正常,但用户已经骂翻了”的情况。原因就是模型返回了200,但内容质量极差、回复为空、或者结构化输出无法解析。
所以要引入业务探测:定期用一组固定的探测用例调用模型,自动校验输出是否符合预期。例如,固定询问一个知识类问题,检查回答中是否包含关键实体;或者给一个固定的工具调用Prompt,检查返回参数是否满足约定的JSON结构。这类探测模拟真实业务请求,能发现基础探测发现不了的问题。
4.2 健康检查的参数设计参考
这里给一组我在实践中常用到的健康检查配置参数,供参考(具体数值需要根据你的业务场景调整):
| 参数 | 推荐初始值 | 说明 |
|---|---|---|
| 探测频率 | 30秒一次 | 太频繁会浪费成本,太稀疏会导致故障感知延迟 |
| 超时时间 | 5秒 | 超过则视为探测失败 |
| 连续失败次数 | 3次 | 连续失败3次,标记为不健康 |
| 恢复探测间隔 | 60秒 | 标记不健康后,每60秒重试一次恢复检测 |
| 错误率阈值 | 5% | 滑动窗口内错误率超过阈值触发切换 |
| P95延迟阈值 | 3000毫秒 | 超过阈值触发切换 |
这里有个经验:健康检查的“误杀”比“漏报”更可怕。误杀会导致不必要的切换,而切换本身会带来上下文不一致、效果波动等副作用。所以阈值的设定宁可保守一点,也不要太灵敏。切换触发前多看几秒、多收集一点证据,这对整体稳定性反而是更好的。
4.3 容灾切换的编排流程
健康检查发现异常后,容灾编排模块开始工作。完整的流程可以拆为四步。
第一步是状态判定。把健康检查、错误率、延迟等输入汇总,由编排模块判断是否真的需要切换。这里我建议引入“多指标确认”:单一指标异常先观察,两个以上指标同时异常才触发切换。例如,错误率超过阈值但延迟正常,可能是偶发网络问题;如果错误率和延迟同时恶化,基本可以确认模型侧出了问题。
第二步是切换决策。决策要明确几件事:切到什么模型、切换的流量比例是多少、哪些场景优先切。我的建议是“先切一部分流量试探,再全量切换”。比如,先切10%流量到备用模型,观察备用模型的表现——错误率是否正常、输出格式是否稳定、延迟是否符合预期。如果一切正常,再逐步放大比例。这个过程可以在几分钟内完成,叫作灰度切流。全量切换看起来更快,但一旦备用模型有问题,二次故障对业务的打击是双倍的。
第三步是流量迁移。迁移时要注意请求上下文的一致性问题。如果主模型和备用模型的结构化输出格式、工具调用方式、Token计数方式都不同,切流前必须先确认下游解析逻辑兼容。网关层面可以在切换时对结构化输出做一层“格式归一化代理”——把备用模型的输出转换成主模型格式,从而让下游无感知。当然,这条路只适合结构比较接近的模型,模型能力差异过大时还是需要下游适配。
第四步是恢复与回切判定。主模型恢复后,不要立刻回切,建议先观察一段时间确认稳定,再逐步回切。这点我踩过很多坑:主模型刚恢复时通常还不够稳定,立刻回切导致二次故障,比第一次故障更伤用户体验。回切也应采用灰度方式,先切一部分流量验证,稳定后再全量恢复。
4.4 请求重放与状态补偿
容灾切换中还有一个容易被忽略的细节:切换期间正在处理中的请求怎么办?
当一个请求正在主模型上执行,同步容灾系统触发切换,主模型的响应在几秒后返回了——但此刻网关已经切到备用模型,这个响应要不要交给业务方?如果直接丢弃,用户可能在前端看到“请求失败”;如果接住这个迟到响应,又要保证它与后续请求的多轮上下文一致。这个场景在Agent对话类业务里尤其常见。
常用的方案是给请求加一个“可接受延迟窗口”。只要响应在窗口内返回,仍然正常返回给业务方;超过窗口还没返回,网关主动断开,并触发一次在备用模型上的重试。同时,必须在网关中对重试请求做幂等处理,不能因为重试导致业务侧重复记账或重复触发工具调用。
另一个需要考虑的点是,在切换期间出现部分成功的消息(例如主模型已经生成了部分回复内容、然后发生错误),是否需要补偿提示给用户。在Agent产品里,建议给前端返回一个“服务繁忙/已切换通道”的状态标识,避免用户在下游自行猜测。
5. 落地实践中的踩坑实录与排障思路
5.1 我在模型路由与容灾建设中踩过的一些坑
第一个坑是“接了备用模型但没有真实流量验证”。团队在配置中心配好了备用模型,但从未在低峰期把部分流量手动切过去跑过。真出故障时一切到备用模型,立刻发现备用模型对某类中文Prompt的处理存在严重的质量问题,但已经来不及调整。从那以后,我养成了一个习惯:备用模型必须定期通过灰度流量真实跑一遍,哪怕只有1%的流量,也要确保持续有真实数据验证其可用性。
第二个坑是“健康检查只会看HTTP状态码”。某个供应商在内部系统出问题时会返回200,同时响应体里带着错误标记,而且延迟飙到几十秒。按HTTP状态码检查一切正常,实际上业务已经被拖垮了。后来我把健康检查升级为“业务语义校验”——不仅看状态码,还看响应内容、延迟、结构化输出完整度。这个改动大大提升了故障感知速度和准确度。
第三个坑是“切换后没有考虑速率限制差异”。主模型供应商给我们的并发额度很高,备用模型的并发额度很低。切换后流量瞬间涌向备用模型,直接把备用供应商打爆,限流响应满天飞。后来我在路由策略中为备用模型单独配置了“最大并发限制”和“排队策略”,切流时先控制速率,再逐步放开。
第四个坑是“回切时没有灰度,导致二次故障”。主模型恢复后直接全量回切,结果主模型处理请求的延迟还没完全恢复,全量回切导致大量请求超时。这个教训前面已经提到,回切必须和切换一样谨慎,同样是灰度逐步推进。
5.2 常见问题速查表
我整理了一份模型路由与容灾的常见问题速查表,适合贴在团队Wiki里随时查阅:
| 问题现象 | 可能原因 | 排查思路与建议 |
|---|---|---|
| 切换备用模型后出现大量解析报错 | 备用模型输出格式与主模型不一致 | 在网关做格式归一化,定期用真实流量比对输出结构 |
| 故障已发生但监控未告警 | 健康检查只看HTTP状态码,未关注业务质量 | 升级为业务语义探测,监控响应内容与延迟 |
| 切换后备用模型被打爆 | 备用模型额度不足,未做并发限制 | 在路由策略中配置备用模型最大并发与排队策略 |
| 主模型恢复后回切不稳定 | 回切未做灰度,核心链路直接被拉低 | 回切采用灰度,先观察再全量 |
| 多轮对话切换后上下文丢失 | 主备模型对上下文格式处理不一致 | 在网关层做上下文格式转换,切换前校验状态兼容性 |
| 重试导致重复计费 | 模型接口未做幂等控制 | 网关层用请求ID串联重试,短时间只放行一次同一请求 |
| 备用模型长期未使用,真故障时不可用 | 缺少定期演练与灰度流量验证 | 定期在低峰期切1%流量到备用模型,保持真实可用 |
5.3 给准备上容灾方案的团队几个建议
如果你所在的团队正准备搭建企业Agent的模型路由与容灾能力,我有几个实际建议,都是从教训里来的。
第一,先把可观测性做实,再谈路由与容灾。没有完整的日志与监控,任何容灾方案都是盲人摸象。至少要把每次调用的模型、供应商、延迟、错误、重试、路由决策全部记录下来。
第二,别追求“绝对不失败”,追求“失败时伤害最小化”。模型供应商不可能永远稳定,容灾方案的目标不是消灭故障,而是把故障影响范围控制在可接受范围内。灰度切流、优先级保障、快速回切,都比“追求100%可用”更实际。
第三,容灾方案一定要定期演练,而且要模拟真故障。不要只在脑内推演,要真的在低峰期制造一次模型故障,把整个团队从监控告警到切换执行到恢复确认走一遍。第一次演练一定会发现一堆问题——配置错了、告警没人看、备用模型没权限,这些都是平时发现不了的。
第四,成本要与稳定性放在一起考虑。多模型并行、备用模型常驻、健康检查频繁调用,这些都会带来成本。你需要在成本约束下设计方案,而不是“只要能稳定,多贵都行”。我一般的做法是:给每个场景设定成本上限,把成本作为路由约束之一参与决策,这样预算可控,稳定性也够用。
6. 最后再分享一点实际体会
做了这么久的企业Agent基础设施,我最大的感受是:模型路由与容灾不是一个“配一次就完事”的静态任务,而是一个持续迭代的过程。模型供应商的能力在变,业务场景在变,流量特征在变,今天的最优路由策略过三个月可能就不再适用。
我现在的习惯是:每两周复盘一次模型网关的运行数据,看错误率、看延迟分布、看路由策略命中情况,主动调整一次配置。每次调配置都写变更记录,定期做一次故障演练。这些工作看起来繁琐,但正是它们保证了我负责的Agent系统在最不愿意出故障的时刻,真的能抗住。
如果你正在规划企业Agent的模型路由与容灾,我的核心建议就一句话:不要只想着“配置一个备用模型”,先把路由、健康检查、灰度切流、回切、可观测性这串链路完整打通,你的系统才算真正有了容灾能力。