Agno 错误分类驱动的多模型故障转移
Agno 错误分类驱动的多模型故障转移
学习目标
本章将分析 Agno 的模型故障转移系统:
- FallbackConfig 的三类错误分别路由
- ModelProviderError.classify() 自动分类
- 不掩盖不可重试客户端错误的设计原则
- Deepcopy 防止多 Agent 间共享状态
前置知识
建议先阅读:
- 多模型适配架构 — 统一抽象层与认证策略
下文假设你已理解上述概念,直接聚焦 Agno 的具体实现。
项目实践
按错误类型分别路由
Agno 的 FallbackConfig 将故障转移分为三类,每类独立配置:
# 伪代码:FallbackConfigFallbackConfig( on_error=[Claude(id="claude-sonnet-4-20250514")], # 通用错误(5xx/网络) on_rate_limit=[OpenAIResponses(id="gpt-4o-mini")], # 限流错误(429/529) on_context_overflow=[Claude(id="claude-sonnet-4-20250514")], # 上下文窗口溢出 callback=lambda primary, fallback, error: notify_team(...), # 激活通知)关键设计:每类错误可以配置不同的回退模型。例如:
- 限流错误 → 切换到另一个提供商的便宜模型
- 上下文溢出 → 切换到支持更大上下文窗口的模型
- 通用错误 → 切换到已知稳定的模型
错误分类优先级
回退模型的查找遵循严格优先级:
关键设计点:
- 特定错误类型优先(限流 → on_rate_limit,溢出 → on_context_overflow)
- 未分类的 ModelProviderError 尝试自动分类
- 通用 5xx/网络错误回退到 on_error
- 401/403/400 等不可重试错误直接抛出,不使用 on_error 掩盖
ModelProviderError.classify() 自动分类
如果错误初始没有被明确分类,ModelProviderError.classify() 会尝试自动分类:
# 伪代码:自动分类@classmethoddef classify(cls, error: ModelProviderError) -> ModelProviderError: if error.status_code == 429 or error.status_code == 529: return ModelRateLimitError(...) if "context_length_exceeded" in error.message: return ContextWindowExceededError(...) return error # 保持原样分类依据:
- HTTP 状态码(429 → RateLimit)
- 错误消息中的关键词(context_length_exceeded → ContextOverflow)
- 提供商特定的错误模式
不掩盖不可重试错误
Agno 的设计原则:配置 bug 不应该被回退模型掩盖。
# 伪代码:不掩盖 4xx 错误if isinstance(error, ModelProviderError) and error.is_retryable is False: # 401(认证失败)、403(权限不足)、400(请求格式错误) # 这些是开发者需要修复的配置问题,不应该被回退掩盖 raise error动机:如果 API Key 过期(401),回退到另一个模型可能暂时”修复”问题,但开发者不知道认证已失效。长期来看,这会导致隐蔽的生产问题。
Deepcopy 防止共享状态
FallbackConfig.resolve_models() 对每个回退模型执行 deepcopy:
# 伪代码:深拷贝回退模型for fm in raw_list: resolved_model = get_model(fm) resolved_model = deepcopy(resolved_model) # 防止共享 resolved_model.model_type = ModelType.MODEL resolved.append(resolved_model)动机:如果同一个 FallbackConfig 被多个 Agent 共享,修改一个 Agent 的模型参数(如 temperature)不应该影响其他 Agent。Deepcopy 确保每个 Agent 有独立的模型副本。
问题与规避
1. 回退链过长导致延迟
如果主模型和多个回退模型都失败,总延迟 = 各模型延迟之和。
规避:
- 每类错误只配置一个回退模型(而非列表)
- 设置合理的超时时间
- 使用
callback监控回退激活频率,及时调整配置
2. 回退模型的上下文窗口更小
如果主模型有 200k 上下文窗口,回退模型只有 8k,上下文溢出的回退可能再次失败。
规避:在 on_context_overflow 中选择支持更大上下文窗口的模型。如果所有可用模型的窗口都不够,需要在应用层面实现上下文压缩。
3. 回调函数的异常
callback 函数如果抛出异常,会影响回退流程。
规避:Agno 的 callback 在回退模型选择后调用,不影响重试。但回调函数本身应该做好异常处理(如 try/except 包裹通知逻辑)。
设计取舍
为什么分类错误而非统一回退?
优势:针对性更强——限流切换到另一个提供商,上下文溢出切换到大窗口模型 代价:配置复杂度更高 替代方案:单一回退列表——配置简单但不够精准
为什么不用熔断器模式?
Agno 当前没有实现熔断器(连续失败后暂停使用某个提供商)。
替代方案:可以结合 FallbackConfig 的 callback,在回调中记录失败次数,达到阈值后动态从回退列表中移除该提供商。