一个团队定过一份很干净的SLA:智能体响应时间低于8秒,达标率99.5%。后来他们统一路由的那款前沿模型,在高峰时段开始限流。他们的"故障转移"方案,是三次重试加指数退避。 纸面上,SLA守住了。实际体验里,用户等来的是24秒的响应,而且有时候还是失败。那三次重试不是故障转移,是同一个请求被反复重放,指望那堵墙自己挪开。 在监控面板上,重试和故障转移长得一模一样——"请求失败→再试一次"。但它们是两种完全不同的操作。 重试假设系统只是短暂不可用,任务本身完好无损。对数据库连接来说,这个假设成立。对一个执行到一半的智能体来说,它不成立。 你把整段对话重新发出去的那一刻,在途状态就被丢掉了——那个只写了一半的工具调用、已经检索到的文档、智能体已经选定的分支,全部作废。你为第一次尝试的token付了钱,又为重放的token付了一次。延迟变成三倍。而如果模型是真的宕了、不只是慢,每一次重试都撞在同一堵墙上。 所以真正的故障模式不是"生成失败",是状态连续性失败。任务已经积累了上下文,而重试把它扔了。 解决办法不是在客户端加一个 retries=3。办法是逐个定义子任务里"等价"到底指什么,并让降级模型消费同一份交接上下文,而不是"从头再来"。 这需要三样大多数单模型架构没有的东西: 一份故障转移策略,得写清楚主模型是谁、降级梯队有谁、每一级的"等价"标准是什么、状态是否随任务一起走: - 主模型:前沿模型 - 降级第一梯队:中档指令模型,等价标准是"能处理同一套工具调用schema",携带状态 - 降级第二梯队:小模型,等价标准是"退化为摘要,保留上下文",携带状态 - 主模型不可用时:路由到第一个有能力接手的模型,而不是重试主模型 当一个接口背后挂着25个以上模型的目录时,"等价"就不再是纸上概念——你手上真的有一个梯队可以切过去,而不用把任务丢掉。 整个调用链是这样的:任务需要下一步,路由器带着交接上下文去调主模型;主模型返回429或超时;路由器带着同一份交接上下文去调降级模型;降级模型把续写结果交回任务,状态得以保留。用户看到的是一次尝试,不是一次重放。 SLA只有在任务活下来时才有意义。 "99.9%可用性"如果故障转移会把任务弄丢,这个数字就毫无意义。一次重试在三倍延迟之后返回、并且从零开始,这不叫成功——用户等了、付了钱,拿到的是一个重做。 SLA数字是绿的,体验是红的。 真正的故障转移衡量的是任务完成,不是请求返回。降级模型必须能接着主模型停下的地方往下走——这正是接口抽象重要的原因。没有这层抽象,你做的不是故障转移,是重启。 代码逻辑应该长这样:对任务按能力排序遍历模型目录,每个模型都拿任务的交接上下文去调用;遇到不可用就继续下一个,上下文不变;全都不可用才抛出"没有可用模型"。 路由器不重试模型,它把任务推进到下一个能接住其上下文的模型。 在你给某一步加上 retry_on_failure 包装器之前,先问自己:这一步里,"等价"是什么意思?你的降级方案是携带状态,还是只是重跑一遍? 大多数号称"有韧性"的大模型系统,其实是加了更好日志的重试循环。韧性是一份降级方案必须履行的契约。

打开网易新闻 查看精彩图片