配置

模型故障转移

OpenClaw 分两个阶段处理故障:

  1. 当前提供商内的认证配置轮换
  2. 模型回退agents.defaults.model.fallbacks 中的下一个模型。

本文档说明运行时规则及其背后的数据。

运行时流程

对于普通文本运行,OpenClaw 按以下顺序评估候选项:

  • 解析会话状态

    解析活跃会话模型和认证配置偏好。

  • 构建候选链

    根据当前模型选择和该选择来源的回退策略构建模型候选链。已配置的默认值、cron 作业主模型和自动选择的回退模型可以使用已配置的回退;显式用户会话选择是严格的。

  • 尝试当前提供商

    使用认证配置轮换/冷却规则尝试当前提供商。

  • 在值得故障转移的错误上前进

    如果该提供商因值得故障转移的错误而耗尽,则移动到下一个模型候选项。

  • 持久化回退覆盖

    在重试开始前持久化所选回退覆盖,以便其他会话读取者看到运行器即将使用的同一提供商/模型。持久化的模型覆盖会标记为 modelOverrideSource: "auto"

  • 失败时窄范围回滚

    如果回退候选项失败,只在那些字段仍匹配该失败候选项时回滚由回退拥有的会话覆盖字段。

  • 耗尽时抛出 FallbackSummaryError

    如果每个候选项都失败,则抛出包含每次尝试详情的 FallbackSummaryError,并在已知时包含最早的冷却到期时间。

  • 这有意比“保存并恢复整个会话”更窄。回复运行器只持久化它为回退所拥有的模型选择字段:

    • providerOverride
    • modelOverride
    • modelOverrideSource
    • authProfileOverride
    • authProfileOverrideSource
    • authProfileOverrideCompactionCount

    这可以防止失败的回退重试覆盖更新的无关会话变更,例如尝试运行期间发生的手动 /model 更改或会话轮换更新。

    选择来源策略

    OpenClaw 会区分所选提供商/模型和选择原因。该来源控制是否允许回退链:

    • 已配置默认值agents.defaults.model.primary 使用 agents.defaults.model.fallbacks
    • 智能体主模型agents.list[].model 是严格的,除非该智能体模型对象包含自己的 fallbacks。使用 fallbacks: [] 可以显式声明严格行为,或提供非空列表以让该智能体选择加入模型回退。
    • 自动回退覆盖:运行时回退会在重试前写入 providerOverridemodelOverridemodelOverrideSource: "auto"。该自动覆盖可以继续沿已配置的回退链前进,并会被 /new/resetsessions.reset 清除。
    • 用户会话覆盖/model、模型选择器、session_status(model=...)sessions.patch 会写入 modelOverrideSource: "user"。这是精确的会话选择。如果所选提供商/模型在生成回复前失败,OpenClaw 会报告该失败,而不是从无关的已配置回退回答。
    • 旧版会话覆盖:较旧的会话条目可能有 modelOverride 但没有 modelOverrideSource。OpenClaw 会将这些视为用户覆盖,避免显式的旧选择被静默转换为回退行为。
    • Cron 负载模型:cron 作业的 payload.model / --model 是作业主模型,而不是用户会话覆盖。它使用已配置的回退,除非作业提供 payload.fallbackspayload.fallbacks: [] 会让 cron 运行保持严格。

    认证存储(密钥 + OAuth)

    OpenClaw 对 API 密钥和 OAuth 令牌都使用认证配置

    • 密钥位于 ~/.openclaw/agents/<agentId>/agent/auth-profiles.json(旧版:~/.openclaw/agent/auth-profiles.json)。
    • 运行时认证路由状态位于 ~/.openclaw/agents/<agentId>/agent/auth-state.json
    • 配置 auth.profiles / auth.order 仅是元数据 + 路由(不含密钥)。
    • 旧版仅导入 OAuth 文件:~/.openclaw/credentials/oauth.json(首次使用时导入到 auth-profiles.json)。

    更多详情:OAuth

    凭证类型:

    • type: "api_key"{ provider, key }
    • type: "oauth"{ provider, access, refresh, expires, email? }(某些提供商还包括 projectId/enterpriseUrl

    配置 ID

    OAuth 登录会创建不同的配置,以便多个账号可以共存。

    • 默认值:没有可用电子邮件时为 provider:default
    • 带电子邮件的 OAuth:provider:<email>(例如 google-antigravity:[email protected])。

    配置位于 ~/.openclaw/agents/<agentId>/agent/auth-profiles.jsonprofiles 下。

    轮换顺序

    当提供商有多个配置时,OpenClaw 会按如下方式选择顺序:

  • 显式配置

    auth.order[provider](如果已设置)。

  • 已配置配置

    按提供商过滤后的 auth.profiles

  • 已存储配置

    auth-profiles.json 中该提供商的条目。

  • 如果未配置显式顺序,OpenClaw 会使用轮询顺序:

    • 主键: 配置类型(OAuth 先于 API 密钥)。
    • 次键: usageStats.lastUsed(每种类型内最早优先)。
    • 冷却/禁用的配置会移动到末尾,并按最早到期排序。

    会话粘性(缓存友好)

    OpenClaw 会按会话固定所选认证配置,以保持提供商缓存预热。它不会在每个请求上轮换。固定的配置会被复用,直到:

    • 会话被重置(/new / /reset
    • 一次压缩完成(压缩计数递增)
    • 该配置处于冷却/禁用状态

    通过 /model …@<profileId> 手动选择会为该会话设置用户覆盖,并且在新会话开始前不会自动轮换。

    为什么 OAuth 可能“看起来丢失了”

    如果同一提供商同时有 OAuth 配置和 API 密钥配置,除非已固定,否则轮询可能会在不同消息之间切换它们。要强制使用单个配置:

    • 使用 auth.order[provider] = ["provider:profileId"] 固定,或
    • 通过带配置覆盖的 /model … 使用每会话覆盖(当你的 UI/聊天表面支持时)。

    冷却

    当配置因认证/速率限制错误(或看起来像速率限制的超时)失败时,OpenClaw 会将其标记为冷却并移动到下一个配置。

    哪些内容会进入速率限制 / 超时桶

    该速率限制桶比普通 429 更宽:它还包括提供商消息,例如 Too many concurrent requestsThrottlingExceptionconcurrency limit reachedworkers_ai ... quota limit exceededthrottledresource exhausted,以及周期性使用窗口限制,例如 weekly/monthly limit reached

    格式/无效请求错误(例如 Cloud Code Assist 工具调用 ID 验证失败)会被视为值得故障转移,并使用相同的冷却。OpenAI 兼容的停止原因错误,例如 Unhandled stop reason: errorstop reason: errorreason: error,会被归类为超时/故障转移信号。

    当来源匹配已知的暂时性模式时,通用服务器文本也可能进入该超时桶。例如,裸露的 pi-ai 流包装器消息 An unknown error occurred 会被每个提供商视为值得故障转移,因为 pi-ai 在提供商流以 stopReason: "aborted"stopReason: "error" 结束且没有具体详情时会发出它。包含暂时性服务器文本(例如 internal server errorunknown error, 520upstream errorbackend error)的 JSON api_error 负载也会被视为值得故障转移的超时。

    OpenRouter 特定的通用上游文本(例如裸露的 Provider returned error)仅在提供商上下文实际为 OpenRouter 时才会被视为超时。通用内部回退文本(例如 LLM request failed with an unknown error.)保持保守,不会单独触发故障转移。

    SDK retry-after 上限

    某些提供商 SDK 可能会在向 OpenClaw 交还控制权之前,为较长的 Retry-After 窗口休眠。对于基于 Stainless 的 SDK(例如 Anthropic 和 OpenAI),OpenClaw 默认将 SDK 内部 retry-after-ms / retry-after 等待上限设为 60 秒,并立即暴露更长的可重试响应,以便该故障转移路径可以运行。可使用 OPENCLAW_SDK_RETRY_MAX_WAIT_SECONDS 调整或禁用该上限;请参阅重试行为

    模型范围冷却

    速率限制冷却也可以按模型限定范围:

    • 当失败的模型 ID 已知时,OpenClaw 会为速率限制失败记录 cooldownModel
    • 当冷却限定在不同模型上时,同一提供商上的同级模型仍可被尝试。
    • 计费/禁用窗口仍会跨模型阻止整个配置。

    冷却使用指数退避:

    • 1 分钟
    • 5 分钟
    • 25 分钟
    • 1 小时(上限)

    状态存储在 auth-state.jsonusageStats 下:

    {
      "usageStats": {
        "provider:profile": {
          "lastUsed": 1736160000000,
          "cooldownUntil": 1736160600000,
          "errorCount": 2
        }
      }
    }
    

    计费禁用

    计费/额度失败(例如 “insufficient credits” / “credit balance too low”)会被视为值得故障转移,但它们通常不是暂时性的。OpenClaw 不会使用短冷却,而是将配置标记为已禁用(使用更长退避)并轮换到下一个配置/提供商。

    状态存储在 auth-state.json 中:

    {
      "usageStats": {
        "provider:profile": {
          "disabledUntil": 1736178000000,
          "disabledReason": "billing"
        }
      }
    }
    

    默认值:

    • 计费退避从 5 小时开始,每次计费失败后翻倍,并以 24 小时为上限。
    • 如果配置已经 24 小时没有失败,退避计数器会重置(可配置)。
    • 过载重试允许在模型回退前进行 1 次同提供商配置轮换
    • 过载重试默认使用 0 ms 退避

    模型回退

    如果提供商的所有配置都失败,OpenClaw 会移动到 agents.defaults.model.fallbacks 中的下一个模型。这适用于耗尽配置轮换的认证失败、速率限制和超时(其他错误不会推进回退)。没有暴露足够详情的提供商错误仍会在回退状态中精确标记:empty_response 表示提供商未返回可用消息或状态,no_error_details 表示提供商明确返回了 Unknown error (no error details in response),而 unclassified 表示 OpenClaw 保留了原始预览,但尚无分类器匹配它。

    过载和速率限制错误会比计费冷却更激进地处理。默认情况下,OpenClaw 允许一次同一提供商认证配置档案重试,然后不等待就切换到下一个已配置的模型回退。ModelNotReadyException 等提供商繁忙信号会归入这个过载类别。可通过 auth.cooldowns.overloadedProfileRotationsauth.cooldowns.overloadedBackoffMsauth.cooldowns.rateLimitedProfileRotations 调整此行为。

    当一次运行从已配置的默认主模型、cron 作业主模型、带显式回退的智能体主模型,或自动选择的回退覆盖开始时,OpenClaw 可以沿着匹配的已配置回退链继续尝试。没有显式回退的智能体主模型以及显式用户选择(例如 /model ollama/qwen3.5:27b、模型选择器、sessions.patch 或一次性 CLI 提供商/模型覆盖)是严格的:如果该提供商/模型无法访问或在生成回复前失败,OpenClaw 会报告失败,而不是从无关的回退模型回答。

    候选链规则

    OpenClaw 会根据当前请求的 provider/model 加上已配置的回退构建候选列表。

    规则
    • 请求的模型始终排在第一位。
    • 显式配置的回退会去重,但不会按模型允许列表过滤。它们被视为显式的操作员意图。
    • 如果当前运行已经位于同一提供商系列中的已配置回退上,OpenClaw 会继续使用完整的已配置链。
    • 如果当前运行所在提供商与配置不同,并且当前模型尚未属于已配置回退链,OpenClaw 不会追加来自另一个提供商的无关已配置回退。
    • 当没有向回退运行器提供显式回退覆盖时,已配置的主模型会追加到末尾,使链条在前面的候选项耗尽后可以回到正常默认值。
    • 当调用方提供 fallbacksOverride 时,运行器只使用请求的模型加上该覆盖列表。空列表会禁用模型回退,并阻止已配置主模型作为隐藏重试目标追加。

    哪些错误会推进回退

    会继续处理

    • 认证失败
    • 速率限制和冷却耗尽
    • 过载/提供商繁忙错误
    • 形态类似超时的故障转移错误
    • 计费禁用
    • LiveSessionModelSwitchError,它会被规范化为故障转移路径,避免过期的持久化模型造成外层重试循环
    • 仍有剩余候选项时的其他无法识别错误

    不会继续处理

    • 不是超时/故障转移形态的显式中止
    • 应留在压缩/重试逻辑内部的上下文溢出错误(例如 request_too_largeINVALID_ARGUMENT: input exceeds the maximum number of tokensinput token count exceeds the maximum number of input tokensThe input is too long for the modelollama error: context length exceeded
    • 没有剩余候选项时的最终未知错误

    冷却跳过与探测行为

    当某个提供商的每个认证配置档案都已处于冷却中时,OpenClaw 不会自动永久跳过该提供商。它会按候选项做出决策:

    按候选项决策
    • 持久认证失败会立即跳过整个提供商。
    • 计费禁用通常会跳过,但主候选项仍可按节流策略进行探测,以便无需重启也能恢复。
    • 主候选项可在接近冷却到期时进行探测,并带有按提供商设置的节流。
    • 当失败看起来是瞬时的(rate_limitoverloaded 或未知)时,即使处于冷却中,也可以尝试同一提供商的回退兄弟模型。当速率限制是模型级别且兄弟模型可能仍可立即恢复时,这一点尤其相关。
    • 瞬时冷却探测限制为每个提供商在每次回退运行中一次,这样单个提供商不会阻塞跨提供商回退。

    会话覆盖和实时模型切换

    会话模型更改是共享状态。活动运行器、/model 命令、压缩/会话更新,以及实时会话协调都会读取或写入同一会话条目的部分内容。

    这意味着回退重试必须与实时模型切换协调:

    • 只有显式的用户驱动模型更改会标记待处理的实时切换。这包括 /modelsession_status(model=...)sessions.patch
    • 系统驱动的模型更改(例如回退轮换、Heartbeat 覆盖或压缩)本身绝不会标记待处理的实时切换。
    • 用户驱动的模型覆盖会被视为回退策略的精确选择,因此无法访问的已选提供商会暴露为失败,而不是被 agents.defaults.model.fallbacks 掩盖。
    • 在回退重试开始前,回复运行器会将所选回退覆盖字段持久化到会话条目。
    • 自动回退覆盖会在后续轮次中保持选中状态,因此 OpenClaw 不会在每条消息上探测已知不良的主模型。/new/resetsessions.reset 会清除自动来源的覆盖,并将会话恢复到已配置默认值。
    • /status 会显示所选模型,并在回退状态不同时显示活动回退模型和原因。
    • 实时会话协调会优先使用持久化会话覆盖,而不是过期的运行时模型字段。
    • 如果实时切换错误指向活动回退链中的后续候选项,OpenClaw 会直接跳到该已选模型,而不是先遍历无关候选项。
    • 如果回退尝试失败,运行器只回滚它写入的覆盖字段,并且只在这些字段仍匹配该失败候选项时回滚。

    这可以防止经典竞态:

  • 主模型失败

    所选主模型失败。

  • 在内存中选择回退

    回退候选项在内存中被选中。

  • 会话存储仍显示旧主模型

    会话存储仍反映旧主模型。

  • 实时协调读取过期状态

    实时会话协调读取过期的会话状态。

  • 重试被切回

    重试在回退尝试开始前被切回到旧模型。

  • 持久化的回退覆盖会关闭这个窗口,而窄范围回滚会让较新的手动或运行时会话更改保持完整。

    可观测性和失败摘要

    runWithModelFallback(...) 会记录每次尝试的详细信息,用于日志和面向用户的冷却消息:

    • 尝试的提供商/模型
    • 原因(rate_limitoverloadedbillingauthmodel_not_found 以及类似故障转移原因)
    • 可选状态/代码
    • 人类可读的错误摘要

    结构化 model_fallback_decision 日志在候选项失败、被跳过或后续回退成功时,也会包含扁平的 fallbackStep* 字段。这些字段让尝试过的转换显式可见(fallbackStepFromModelfallbackStepToModelfallbackStepFromFailureReasonfallbackStepFromFailureDetailfallbackStepFinalOutcome),因此日志和诊断导出器即使在最终回退也失败时,也能重建主模型失败。

    当每个候选项都失败时,OpenClaw 会抛出 FallbackSummaryError。外层回复运行器可以用它构建更具体的消息,例如“所有模型都暂时受到速率限制”,并在已知时包含最早的冷却到期时间。

    该冷却摘要支持模型感知:

    • 会忽略与尝试的提供商/模型链无关的模型级速率限制
    • 如果剩余阻塞是匹配的模型级速率限制,OpenClaw 会报告仍阻塞该模型的最后一个匹配到期时间

    相关配置

    参见 Gateway 网关配置

    • auth.profiles / auth.order
    • auth.cooldowns.billingBackoffHours / auth.cooldowns.billingBackoffHoursByProvider
    • auth.cooldowns.billingMaxHours / auth.cooldowns.failureWindowHours
    • auth.cooldowns.overloadedProfileRotations / auth.cooldowns.overloadedBackoffMs
    • auth.cooldowns.rateLimitedProfileRotations
    • agents.defaults.model.primary / agents.defaults.model.fallbacks
    • agents.defaults.imageModel 路由

    参见 Models,了解更广泛的模型选择和回退概览。