跳转到内容

Agno 错误分类驱动的多模型故障转移

Agno 错误分类驱动的多模型故障转移

学习目标

本章将分析 Agno 的模型故障转移系统:

  • FallbackConfig 的三类错误分别路由
  • ModelProviderError.classify() 自动分类
  • 不掩盖不可重试客户端错误的设计原则
  • Deepcopy 防止多 Agent 间共享状态

前置知识

建议先阅读:

下文假设你已理解上述概念,直接聚焦 Agno 的具体实现。


项目实践

按错误类型分别路由

Agno 的 FallbackConfig 将故障转移分为三类,每类独立配置:

# 伪代码:FallbackConfig
FallbackConfig(
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(...), # 激活通知
)

关键设计:每类错误可以配置不同的回退模型。例如:

  • 限流错误 → 切换到另一个提供商的便宜模型
  • 上下文溢出 → 切换到支持更大上下文窗口的模型
  • 通用错误 → 切换到已知稳定的模型

错误分类优先级

回退模型的查找遵循严格优先级:

关键设计点

  1. 特定错误类型优先(限流 → on_rate_limit,溢出 → on_context_overflow)
  2. 未分类的 ModelProviderError 尝试自动分类
  3. 通用 5xx/网络错误回退到 on_error
  4. 401/403/400 等不可重试错误直接抛出,不使用 on_error 掩盖

ModelProviderError.classify() 自动分类

如果错误初始没有被明确分类,ModelProviderError.classify() 会尝试自动分类:

# 伪代码:自动分类
@classmethod
def 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,在回调中记录失败次数,达到阈值后动态从回退列表中移除该提供商。

参考来源