Failover-Aware Model Fallback

Clawdbot Contributors· validated-in-production

问题

AI模型请求失败的原因多种多样,且通常难以明确。简单的重试逻辑无法区分以下三类情况:

  • 临时故障(超时、速率限制):此类故障通过带退避机制的重试可得到解决
  • 语义故障(认证错误、计费问题):此类故障重试毫无意义
  • 用户终止请求:此类场景下重试会浪费资源,还会引发用户不满

使用多模型或多服务商的Agent需要智能回退策略,既要契合故障的语义属性,避免陷入重试循环,又要提供清晰的诊断信息。

方案

基于智能回退链的语义错误分类 每一次失败都会被归类为特定的原因类型,回退行为会根据该原因量身定制。多模型回退链按请求配置,同时支持供应商专属白名单和冷却跟踪。

核心概念:

  • 错误分类:将失败映射为语义原因类型(timeout[超时]、rate_limit[速率限制]、auth[认证]、billing[计费]、format[格式]、context_overflow[上下文溢出])。
  • 基于原因的回退:不同原因触发不同的回退行为:
    • timeoutrate_limit:使用链中的下一个模型重试
    • authbilling:立即终止;重试无济于事
    • formatcontext_overflow:可调整请求后重试
  • 用户终止检测:区分用户主动终止与超时导致的终止。用户主动终止会立即重新抛出异常;超时则触发回退。
  • 多模型链{供应商, 模型}候选者的有序列表。每一次尝试都会使用下一个候选者,直到成功或候选者耗尽。
  • 供应商白名单:可选的供应商专属模型限制可避免回退到不兼容的模型。
  • 诊断跟踪:每一次失败尝试都会记录错误详情、原因、状态码以及供应商/模型信息,以便调试。

实现概要:

// 回退原因类型
type FailoverReason =
  | "timeout"
  | "rate_limit"
  | "auth"
  | "billing"
  | "format"
  | "context_overflow";

// 模型候选者
type ModelCandidate = {
  provider: string;
  model: string;
};

/**
 * 执行带模型回退的任务
 * @param params 配置参数
 * @returns 包含执行结果、使用的供应商/模型以及尝试记录的对象
 */
async function runWithModelFallback<T>(params: {
  candidates: ModelCandidate[];
  run: (provider: string, model: string) => Promise<T>;
}): Promise<{ result: T; provider: string; model: string; attempts: Attempt[] }> {
  const attempts: Attempt[] = [];

  for (const candidate of params.candidates) {
    try {
      const result = await params.run(candidate.provider, candidate.model);
      return { result, provider: candidate.provider, model: candidate.model, attempts };
    } catch (err) {
      // 分类回退原因
      const reason = classifyFailoverReason(err);
      // 认证或计费错误直接抛出,重试无效
      if (reason === "auth" || reason === "billing") {
        throw err;
      }
      // 用户主动终止则直接抛出,不触发回退
      if (isUserAbort(err)) {
        throw err;
      }
      // 记录本次失败尝试
      attempts.push({ provider: candidate.provider, model: candidate.model, error: err, reason });
      // 继续尝试下一个候选模型
    }
  }

  throw new Error(`所有模型执行失败: ${attempts.map(a => a.error).join(" | ")}`);
}

/**
 * 分类回退原因
 * @param err 捕获到的异常
 * @returns 回退原因或null
 */
function classifyFailoverReason(err: unknown): FailoverReason | null {
  const status = getStatusCode(err);
  if (status === 402) return "billing";
  if (status === 429) return "rate_limit";
  if (status === 401 || status === 403) return "auth";
  if (status === 408) return "timeout";

  const message = getErrorMessage(err).toLowerCase();
  if (message.includes("timeout") || message.includes("timed out")) return "timeout";
  if (message.includes("rate limit") || message.includes("too many requests")) return "rate_limit";
  if (message.includes("context window") || message.includes("context length")) return "context_overflow";

  return null;
}

用户终止与超时的区分:

/**
 * 判断是否为用户主动终止
 * @param err 捕获到的异常
 * @returns 是否为用户主动终止
 */
function isUserAbort(err: unknown): boolean {
  // 仅将明确的AbortError判定为用户主动终止
  // 基于消息的检查(如"aborted")可能会误判超时
  if (!err || typeof err !== "object") return false;
  const name = "name" in err ? String(err.name) : "";
  return name === "AbortError" && !isTimeoutError(err);
}

配置示例:

agents:
  defaults:
    model:
      primary: "anthropic/claude-sonnet-4-20250514"  # 主模型
      fallbacks:
        - "openai/gpt-4o"  # 第一回退模型
        - "google/gemini-2.0-flash"  # 第二回退模型

如何使用

  1. 定义回退链:针对不同用例(代码生成vs通用对话)指定备选模型的有序列表。
  2. 配置白名单:将回退范围限制为支持请求格式的模型(例如仅图像模型)。
  3. 错误分类:将供应商特定的错误代码映射为语义化原因,实现一致性处理。
  4. 追踪尝试过程:记录每次回退尝试的供应商、模型、错误信息及原因,提升可观测性。
  5. 处理耗尽场景:当所有候选模型均失败时,汇总错误信息以提供可执行的反馈。

需规避的陷阱:

  • 过度回退:过多回退链可能导致故障在供应商间连锁扩散,应采用指数退避策略。
  • 语义不匹配:回退模型可能具备不同的能力(视觉、工具调用),需按所需功能进行筛选。
  • 静默故障:部分错误(如格式类错误)表明请求不兼容,回退操作可能会以相同方式失败。

权衡

优点:

  • 韧性强:瞬时故障(如超时、速率限制)不会导致Agent阻塞。
  • 成本优化:当高端模型不可用时,可降级至更便宜的模型。
  • 诊断清晰:尝试历史可展示哪些模型失败及具体失败原因。
  • 尊重用户终止操作:可区分用户取消与超时场景,避免不必要的降级操作。

缺点/注意事项:

  • 延迟损耗:每次失败尝试都会在成功前增加往返耗时。
  • 输出不一致:不同模型的响应可能存在差异,会影响下游解析环节。
  • 成本累积:针对单个逻辑请求,降级链可能会产生多次API费用。
  • 配置复杂:管理白名单、降级链以及供应商特定行为会增加运维开销。

参考文献

关键词

:涵盖Clawdbot项目中模型降级编排、错误分类、错误原因判定三类核心故障处理代码文件,以及关联的扩展一致性工作会话可靠性模式参考文档。

直译

来源摘要

正在获取来源并生成中文摘要…

来源: https://github.com/clawdbot/clawdbot/blob/main/src/agents/model-fallback.ts

← 返回社区