OpenClaw 中 Claude 模型工具调用频繁失败的解决办法
问题描述
最近在使用 OpenClaw(开源 AI Agent 框架)时,发现了一个令人头疼的问题:Claude 模型(无论是 Sonnet 还是 Opus)在调用系统工具时频繁失败,报错 Tool XXX not found。
具体表现:
- 让 AI 搜索信息时,它会调用
WebSearch而不是正确的web_search - 抓取网页时,它会调用
WebFetch而不是web_fetch - 同样的错误在
MemorySearch、SessionsList等工具上反复出现 - 模型会连续重试多次,每次都用错误的名字,白白消耗大量 token
- 最终只能 fallback 到
exec+curl曲线救国
这不是偶发问题——Sonnet 和 Opus 都会犯同样的错,几乎每个新 session 都会出现。
初步排查:不是缓存问题
一开始我怀疑是 OpenClaw 的 system prompt 缓存导致模型"记忆"了错误的工具名。
但检查后发现:AGENTS.md、TOOLS.md 等配置文件是作为 system prompt 的一部分每次完整注入的,不存在缓存错乱的问题。而且 system prompt 里已经明确列出了所有正确的工具名(全小写 + 下划线),甚至加了 ⚠️ 警告。
模型就是不听。
根因分析
Claude 模型的训练数据中,函数/工具名通常使用 PascalCase(如 WebSearch、ReadFile),这是 AI 工具调用的一个常见约定。
但 OpenClaw 的工具注册名使用的是 snake_case(如 web_search、web_fetch)。
OpenClaw 内部有一个 normalizeToolName 函数,会对工具名做处理:
// dist/agents/tool-policy.js
export function normalizeToolName(name) {
const normalized = name.trim().toLowerCase();
return TOOL_NAME_ALIASES[normalized] ?? normalized;
}
它做了两件事:
trim()+toLowerCase()— 所以WebSearch会变成websearch- 查
TOOL_NAME_ALIASES别名表
问题出在别名表:
const TOOL_NAME_ALIASES = {
bash: "exec",
"apply-patch": "apply_patch",
};
只有两条规则!websearch 没有映射到 web_search,所以 toLowerCase() 之后的 websearch 直接被当作最终工具名——然而并不存在这个工具。
关键差异:这不是单纯的大小写问题,而是下划线丢失的问题。
WebSearch → toLowerCase() → websearch ≠ web_search
解决方案
在 TOOL_NAME_ALIASES 中补全所有带下划线的工具名的无下划线变体:
const TOOL_NAME_ALIASES = {
bash: "exec",
"apply-patch": "apply_patch",
// camelCase / no-underscore aliases
// (normalizeToolName lowercases first, so WebSearch → websearch → web_search)
agentslist: "agents_list",
applypatch: "apply_patch",
memoryget: "memory_get",
memorysearch: "memory_search",
sessionshistory: "sessions_history",
sessionslist: "sessions_list",
sessionssend: "sessions_send",
sessionsspawn: "sessions_spawn",
sessionstatus: "session_status",
webfetch: "web_fetch",
websearch: "web_search",
};
修改文件路径:
<openclaw_install_dir>/dist/agents/tool-policy.js
修改后重启 Gateway 即可生效:
openclaw gateway restart
原理图解
模型输出: WebSearch
↓ normalizeToolName()
↓ trim().toLowerCase()
→ "websearch"
↓ TOOL_NAME_ALIASES["websearch"]
→ "web_search" ✅ 找到工具,正常执行
注意事项
- 这个修改会在
openclaw update后被覆盖,因为改的是dist/下的编译产物。建议向 OpenClaw 官方提 PR 将其合入主线。
- 如果你自定义了额外的带下划线的工具,也需要在别名表里补上对应的无下划线版本。
- 这个问题不仅影响 Claude,理论上任何倾向于 PascalCase 命名的模型都可能遇到。
写在最后
这个 bug 的表面现象是"AI 工具调用失败",但本质是 AI 模型的命名习惯与框架的命名约定不匹配。框架已经做了 toLowerCase() 的兼容,但漏掉了下划线分隔符的差异。
一个 15 行的别名表,解决了每次对话都可能浪费几千 token 的问题。
希望这篇文章能帮到同样遇到这个问题的 OpenClaw 用户。如果你觉得有用,也欢迎去 OpenClaw GitHub 给这个改动点个 👍。
环境:OpenClaw latest · Claude Opus 4.5 / Sonnet 4.5 · macOS (Apple Silicon)
评论