别改了主配置却不生效——OpenClaw 多模型路由机制深度解析

别改了主配置却不生效——OpenClaw 多模型路由机制深度解析

摘要

你有没有遇到这种情况:明明在 openclaw.json 里把默认模型改成了新的,飞书消息回复的却还是旧模型?或者换了模型发现"没反应",日志里却是另一个模型在跑?

这篇文章从一次真实的排查过程出发,拆解 OpenClaw 的模型选择完整链路:主配置 → Hook 路由 → Fallback 兜底,讲清楚每一层的优先级、运作时机,以及最容易踩的坑。


背景:一次"改了但没生效"的完整排查

某天把 OpenClaw 的默认模型从 openai-codex/gpt-5.4 切换到 openai/gpt-5.3-codex,重启后发了条消息,飞书侧依然沉默或者很慢。打开日志一看,gpt-5.3-codex 大量报 API rate limit reachedLLM request timed out,有些请求卡到 timeoutMs=600000(整整 10 分钟)才失败,看起来就像"没反应"。

但更诡异的是:明明有些请求最后成功了,用的却是 Bailian 的模型——说明系统没死,只是走了 fallback。

这就引出了一个问题:OpenClaw 的模型到底是怎么选的?哪一层的配置优先级最高?


OpenClaw 模型选择的三层结构

第一层:agents.defaults.model——默认主模型

这是大多数人第一个想到的配置点,位于 ~/.openclaw/openclaw.json

{
  "agents": {
    "defaults": {
      "model": {
        "primary": "openai/gpt-5.3-codex",
        "fallbacks": [
          "bailian/qwen3.5-plus",
          "bailian/MiniMax-M2.5"
        ]
      }
    }
  }
}
  • primary:系统在没有任何覆盖时优先选择的模型。
  • fallbacks:当 primary 报错(限流、超时、余额不足)时,按数组顺序依次尝试。

坑点一fallbacks 是静默接管的。如果 primary 失败,系统会自动换到下一个 fallback,日志里也只是多一条切换记录,飞书侧看到的是最终成功的那个模型。这会让你误以为"主模型生效了但很卡",实际上是"主模型一直在失败,fallback 在接活"。

坑点二:改完 primary 后必须重启 openclaw gateway 才能生效,修改配置文件本身不会热加载。

openclaw gateway restart
# 或者
openclaw models status --plain  # 验证当前实际使用的模型

第二层:model-router Hook——内容感知的路由覆盖

这是最容易被忽视、也最容易踩坑的一层。

OpenClaw 支持自定义 Hook,其中 model-router Hook 可以在每次请求到来时,根据消息内容动态决定使用哪个模型——它的优先级高于 agents.defaults.model.primary

Hook 文件默认在 ~/.openclaw/hooks/model-router/handler.js,以下是一个典型实现:

const CODE_PATTERNS = [
  /```/,
  /\b(code|coding|script|bash|shell|terminal|command|cli|sql)\b/i,
  /\b(debug|traceback|报错|调试|修复|排查)\b/i,
  /\b(config|配置|api key|token|gateway|hook|plugin)\b/i,
  /\b(function|class|import|python|javascript|json|yaml|docker)\b/i,
  /\b(openclaw|cron|workflow|自动化|脚本|代码)\b/i,
];

const GENERAL_PATTERNS = [
  /\b(总结|摘要|日报|翻译|润色|改写|整理|头脑风暴)\b/i,
  /\b(summary|summarize|rewrite|translate|brainstorm)\b/i,
];

export default async function modelRouter(event) {
  const text = extractLatestUserText(event?.messages);

  if (shouldUseCodex(text)) {
    return { modelOverride: 'openai/gpt-5.3-codex' };  // ← 覆盖 primary
  }

  if (shouldPreferGeneral(text)) {
    return { modelOverride: 'openai/gpt-4o' };
  }

  return { modelOverride: 'openai/gpt-4o' };  // ← 默认也是覆盖 primary
}

这就是为什么"改了 primary 却不生效":只要 model-router Hook 存在且命中了规则,它返回的 modelOverride 就会覆盖 primary

举个具体例子:你把 primary 改成 zai/glm-4.5-air,但发送的消息里包含"帮我调试这个配置"——CODE_PATTERNS 命中,Hook 直接把请求路由到 gpt-5.3-codexglm-4.5-air 根本没有机会。


第三层:fallbacks——失败兜底链

当上面某一层选出的模型请求失败(429 限流、504 超时、余额耗尽),fallback 链才启动:

primary 失败 → fallbacks[0] → fallbacks[1] → ... → 全部失败才算真正失败

常见的失败触发条件:

  • API rate limit reached(超过 RPM/TPM 限制)
  • LLM request timed outtimeoutMs 设置过长导致假死)
  • You exceeded your current quota(账单余额不足,会被 OpenClaw 包装成 rate limit 提示)

坑点三You exceeded your current quota 这个错误会被 OpenClaw gateway 统一包装成"⚠️ API rate limit reached"推送到飞书。如果你看到对话忽然变得很慢、偶尔恢复,大概率是 fallback 在接管,而不是 primary 本身在工作。

排查方式是直接看 gateway 错误日志:

tail -f ~/.openclaw/logs/gateway.err.log | grep -E "rawErrorPreview|modelOverride|fallback"

完整的排查 SOP

遇到"改了模型没生效"或"模型行为和预期不一致"时,按这个顺序排查:

Step 1:确认 primary 是否真的改对了

# 查看当前运行时实际使用的模型
openclaw models status --plain

# 直接用 jq 确认配置文件里的值
cat ~/.openclaw/openclaw.json | python3 -m json.tool | grep -A5 '"primary"'

注意:agents.defaults.model.primary 是生效字段,不是 models.providers.xxx.defaultModel 这类字段(后者仅用于 UI 展示)。

Step 2:检查 model-router Hook 是否存在且覆盖了你的期望

# 查看 hook 文件
cat ~/.openclaw/hooks/model-router/handler.js

# 如果 hook 里的返回值硬编码了某个模型,你改 primary 是不会生效的
# 需要同步修改 hook 里所有的 modelOverride 返回值

如果你不需要内容感知路由,最简单的做法是直接删除或禁用这个 hook:

// openclaw.json 里

{
  "hooks": {
    "model-router": {
      "enabled": false
    }
  }
}

Step 3:从日志里确认实际发出请求的模型

# 找最近几条请求用了哪个模型
grep "modelOverride\|primary\|fallback" ~/.openclaw/logs/gateway.err.log | tail -30

Step 4:验证 fallback 是否在静默接管

如果 primary 一直 timeout 但 fallback 能正常返回,你看到的现象就是"有时能用、有时卡死"。此时需要:

  1. 确认 primary 的实际可用性(直接用 curl 测一下接口是否通)
  2. 临时把 primary 换成稳定的模型,把原来的放进 fallback

配置最佳实践

方案一:不需要内容感知路由

直接配好 primaryfallbacks,禁用 model-router hook。简单、可预期。

{
  "agents": {
    "defaults": {
      "model": {
        "primary": "custom-127-0-0-1-8317/xianyu-qwen3.6-plus",
        "fallbacks": [
          "custom-127-0-0-1-8317/xianyu-MiniMax-M2.7-highspeed"
        ]
      }
    }
  }
}

方案二:内容感知路由 + 主配置一致

如果你需要不同类型的消息用不同模型,那 hook 和 primary 必须同步维护——改了一个另一个也要跟着改,否则会出现预期外的路由结果。

建议在 hook 里加注释:

// 同步修改:agents.defaults.model.primary 应该与此保持一致
return { modelOverride: 'openai/gpt-5.3-codex' };

方案三:配置热改后记得重启

openclaw gateway restart

# 验证新配置
openclaw models status

小结

OpenClaw 的模型选择链路按优先级从高到低是:

model-router Hook (modelOverride)
    ↓ 如果 hook 未命中或 hook 被禁用
agents.defaults.model.primary
    ↓ 如果 primary 请求失败
agents.defaults.model.fallbacks[0, 1, ...]

最核心的一条经验:改了 primary 之后,先检查有没有 model-router hook,再检查日志里实际发出请求用的是什么模型。这两步能解决 90% 的"改了没生效"问题。

posted @ 2026-04-16 15:29  难删亦删  阅读(22)  评论(0)    收藏  举报