生成模型 :Claude Opus 4.6 (anthropic/claude-opus-4-6) Token 消耗 :输入 ~400,000 tokens,输出 ~32,000 tokens(本章合计)
故障转移的核心问题是:什么样的错误应该触发回退?什么样的错误应该直接报告给用户?OpenClaw 通过 FailoverError 类型和一套错误分类系统来精确控制故障转移的触发条件。
8.4.1 错误分类(src/agents/failover-error.ts)
FailoverError 类
FailoverError 是一个自定义错误类,携带了故障转移所需的全部上下文信息:
Copy // src/agents/failover-error.ts
export class FailoverError extends Error {
readonly reason : FailoverReason ; // 失败原因分类
readonly provider ?: string ; // 提供者标识
readonly model ?: string ; // 模型标识
readonly profileId ?: string ; // Auth Profile ID
readonly status ?: number ; // HTTP 状态码
readonly code ?: string ; // 错误代码
constructor ( message : string , params : {
reason : FailoverReason ;
provider ?: string ;
model ?: string ;
profileId ?: string ;
status ?: number ;
code ?: string ;
cause ?: unknown ;
}) {
super (message , { cause : params . cause } ) ;
this . name = " FailoverError " ;
// ...赋值
}
} FailoverReason 枚举了所有可能的故障原因:
resolveFailoverReasonFromError 函数负责将任意错误对象映射到 FailoverReason:
分类逻辑的优先级是:已有标记 > HTTP 状态码 > 网络错误代码 > 错误消息文本。这确保了即使来自不同 SDK 的错误格式不统一,也能被正确分类。
超时错误的检测尤其复杂,因为不同环境和 SDK 的超时错误表现形式各异:
超时与 AbortError 的区分至关重要——用户主动 /stop 产生的 AbortError 不应触发故障转移,而超时导致的 AbortError(如某些 HTTP 库将超时表现为 abort)应该触发。
普通错误可以被"提升"为 FailoverError:
如果一个普通错误可以被分类为某种故障原因,它就会被包装为 FailoverError,进入故障转移流程。如果无法分类(返回 null),说明这是一个不可恢复的错误(如配置错误),应该直接上抛。
8.4.2 认证错误、计费错误、上下文溢出错误的检测与处理
除了通用的错误分类外,OpenClaw 还针对几种特定错误类型实现了专门的检测和恢复策略。
认证错误通常发生在 API Key 失效、Token 过期或权限不足时。在 runEmbeddedPiAgent 中,认证错误触发 Auth Profile 轮换:
计费错误(HTTP 402)意味着用户的额度已用完。OpenClaw 对计费错误有特殊处理:
标记 Profile 进入长冷却期(计费错误的退避时间更长)
尝试切换到其他 Profile(可能有不同的计费账号)
如果所有 Profile 都是计费错误,尝试回退到其他模型
上下文溢出(Context Overflow)发生在对话历史超过模型的上下文窗口时。这种错误的恢复策略是自动压缩会话历史:
自动压缩通过总结对话历史的早期部分来释放 Token 空间。如果连续 3 次压缩都无法解决溢出问题(可能是单条消息本身就超过了上下文窗口),则向用户报告错误。
某些 LLM API 要求消息角色严格交替(user → assistant → user → ...)。如果历史中出现了连续的同角色消息,会导致角色顺序错误:
角色顺序错误不触发故障转移(因为换个模型也一样会失败),而是直接提示用户重试或开启新会话。
当用户发送的图片超过模型的限制时:
图片大小错误也不触发故障转移——用户需要压缩图片后重新发送。
8.4.3 故障转移日志与用户可见的错误消息
每次故障转移尝试都会被记录,包括:
describeFailoverError 函数将任意错误对象转换为结构化的错误描述:
当所有候选模型都失败时,系统汇总所有尝试的错误信息:
例如,一个典型的全部失败错误消息可能是:
这个汇总消息清楚地展示了每个候选模型的失败原因,帮助用户或管理员快速定位问题。
面向用户的错误消息经过精心设计,避免暴露内部细节:
"Context overflow: prompt too large for the model. Try again with less input or a larger-context model."
"Message ordering conflict - please try again. If this persists, use /new to start a fresh session."
"Image too large for the model (max NMB). Please compress or resize the image and try again."
专用的 BILLING_ERROR_USER_MESSAGE 常量
"LLM request unauthorized."
"LLM request rate limited."
所有用户可见的错误消息都附带了可行的操作建议 ——告诉用户接下来可以做什么,而不是仅仅报告问题。
FailoverError 是故障转移系统的核心类型,携带了故障原因(reason)、提供者、模型、HTTP 状态码等完整上下文。
错误分类 按四级优先级进行:已有标记 → HTTP 状态码 → 网络错误代码 → 错误消息文本,确保不同 SDK 的错误都能被正确分类。
超时与 AbortError 的区分 是关键——用户主动取消不触发回退,超时导致的中止触发回退。
特定错误类型 (认证、计费、上下文溢出、角色顺序、图片大小)各有专门的检测和恢复策略,不能一概而论。
全部失败时的错误汇总 展示了完整的失败链,用户可见的错误消息附带可行的操作建议。