ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

OpenClaw 工具调用完整链路拆解:从 AgentEvent 到 tool_result 的配置与验证

OpenClaw 工具调用完整链路拆解:从 AgentEvent 到 tool_result 的配置与验证 1. 一次工具调用卡住时先看这三个节点OpenClaw 的工具调用链路说到底是三个节点在接力AgentEvent、tool_call、tool_result。你如果正在接入 OpenClaw或者线上突然出现“模型说要调工具但没动静”“工具执行了但模型像没看见结果”这类问题八成是这三个节点里有一个断了。OpenClaw 是一个事件驱动的 Agent 运行时它和 OpenAI 那种流式delta.tool_calls的玩法不一样——模型一次性吐出结构化的tool_callsJSONOpenClaw 的适配层解析后创建tool_call类型的 AgentEvent工具执行完再封装成tool_result事件回灌给模型。整条链路是“事件总线”串起来的不是增量流。这篇文章面向正在接入或排查 OpenClaw 工具调用问题的开发者。我会把从模型生成工具调用、到 OpenClaw 解析、到执行、到结果回传的完整路径拆开给出可复制的配置骨架和逐步验证动作。你跟着做能定位到链路到底断在哪一环。适合谁已经跑通基础对话、准备接工具或正在被工具调用问题卡住的同学。下面所有配置和验证都基于本地源码路径C:\work\openclaw的目录结构来写你换成自己的路径即可。2. 前置准备TaoToken 接入与工具注册骨架在拆链路之前先把“模型从哪来”和“工具从哪注册”这两件事定下来。OpenClaw 本身不绑定模型供应商它通过适配层对接。我这边习惯用 TaoToken 做统一接入原因是它的 API 兼容 OpenAI 与 Anthropic 两种协议OpenClaw 的openai-transport-stream.ts和anthropic-transport-stream.ts都能直接对上省得为不同模型改适配代码。先拿 Key。打开控制台创建 API Key地址是 https://taotoken.net/console 创建完复制保存。如果你还没决定用哪个模型可以先去模型对话页面试一下工具调用能力地址 https://taotoken.net/chat 选一个支持 function calling 的模型发一句“帮我列出当前目录文件”看它会不会生成结构化的 tool_calls。这一步能提前排除“模型本身不支持工具调用”这个最容易被忽略的原因。拿到 Key 后在 OpenClaw 的模型配置里填上。OpenClaw 的模型适配层读取的是环境变量或配置文件我一般写成环境变量避免硬编码# Windows PowerShell $env:OPENCLAW_MODEL_BASE_URLhttps://taotoken.net/api $env:OPENCLAW_MODEL_API_KEYsk-你的Key $env:OPENCLAW_MODEL_NAMEclaude-sonnet-4-5 # macOS / Linux export OPENCLAW_MODEL_BASE_URLhttps://taotoken.net/api export OPENCLAW_MODEL_API_KEYsk-你的Key export OPENCLAW_MODEL_NAMEclaude-sonnet-4-5注意 base URL 用https://taotoken.net/api不要带多余路径适配层会自己拼/v1/messages或/v1/chat/completions。填错这里最常见的表现是 404而不是 401别被误导。工具注册这一侧OpenClaw 的注册中心是src/agents/openclaw-tools.ts里的createOpenClawTools()。所有工具在这里被创建并注册name是调用的唯一标识。你新增一个工具本质就是往这个注册表里加一项包含name、description、parameters三要素。系统提示注入则由src/agents/skills/workspace.ts的buildWorkspaceSkillsPrompt()完成它把可用技能和底层工具格式化成 XML 文本塞进 system prompt。也就是说模型能“看见”哪些工具取决于这一步注入了什么。3. 可复制配置把 tool_call 到 tool_result 串起来这一节是核心我把链路拆成四段每段给你可复制的配置或代码骨架。3.1 阶段一模型生成 tool_calls模型收到 system prompt含工具描述和用户请求后推理并生成工具调用。关键点OpenClaw 里模型的tool_calls是模型输出的文本内容的一部分不是框架事件。它被包在模型的content字段里一次性生成不是流式增量。这跟 OpenAI 的delta.tool_calls有本质区别排查时别拿 OpenAI 的经验套。你可以在src/agents/skills/skill-contract.ts的formatSkillsForPrompt()里确认 XML 格式是否正确。如果工具描述没注入进去模型根本不知道有exec这个工具自然不会生成 tool_calls。验证方法打印发给模型的完整 system prompt搜available_skills和工具名搜不到就是注入断了。3.2 阶段二OpenClaw 解析并创建 AgentEvent模型响应回来后适配层openai-transport-stream.ts或anthropic-transport-stream.ts接收完整响应再由openai-ws-message-conversion.ts这类转换器从响应文本里提取tool_calls对象。解析成功后系统创建一个tool_call类型的 AgentEvent结构如下{ type: tool_call, toolName: exec, toolCallId: call_abc123, arguments: { command: dir }, runId: run_xyz789 }这个事件被投递到 OpenClaw 内部事件总线。toolCallId是后续把结果对回去的关键runId用来串同一次运行的所有事件。排查时如果事件总线里没有tool_call说明解析环节失败重点看转换器有没有正确识别模型返回的 JSON 结构。3.3 阶段三执行工具事件分发由src/agents/pi-embedded-subscribe.handlers.tools.ts的handleToolExecutionStart()负责。它监听tool_call事件根据toolName在createOpenClawTools()生成的注册表里查找工具实现然后调用其执行函数。以exec为例最终落到bash-tools.exec.ts// 模拟执行逻辑 const result await exec({ command: dir });工具返回结果有三种形态这个区分很重要因为不同形态后续处理路径不同返回状态结构后续动作success{status:success,output:...}直接封装为 tool_resulterror{status:error,error:...}封装为 tool_result模型据此纠错approval-pending{status:approval-pending,approvalId:req_456}挂起等待审批后再继续参数标准化由src/agents/pi-embedded-runner/run/attempt.tool-call-normalization.ts处理核心调度在attempt.ts。如果你遇到“工具收到了参数但格式不对”先看这个标准化文件。3.4 阶段四结果回传模型handleToolExecutionEnd()接收工具最终结果封装成tool_result类型的 AgentEvent{ type: tool_result, toolCallId: call_abc123, result: { status: success, output: 文件1.txt\n文件2.txt }, runId: run_xyz789 }然后它把tool_result连同原始tool_call一起作为新的对话历史重新发给模型。模型基于这个新信息生成最终回复。注意toolCallId必须和tool_call事件里的一致否则模型对不上号会表现为“工具执行了但模型装没看见”。4. 验证请求逐步确认链路没断配置完别急着上复杂任务用最小请求逐段验证。我一般分四步走。第一步验证模型能生成 tool_calls。直接发一个明确需要工具的请求比如“列出当前目录下的文件”。在适配层加一行日志打印模型原始响应确认content里含tool_calls字段。没有就回到 3.1 检查 system prompt 注入。第二步验证 AgentEvent 创建。在事件总线上订阅tool_call类型打印事件体。用 curl 直接打模型接口做对照确认解析器没漏字段curl https://taotoken.net/api/v1/messages \ -H x-api-key: sk-你的Key \ -H anthropic-version: 2023-06-01 \ -H content-type: application/json \ -d { model: claude-sonnet-4-5, max_tokens: 1024, messages: [{role:user,content:列出当前目录文件}], tools: [{name:exec,description:执行命令,input_schema:{type:object,properties:{command:{type:string}}}}] }返回里如果stop_reason是tool_use说明模型侧没问题问题在 OpenClaw 解析。第三步验证工具执行。在handleToolExecutionStart()里打断点或加日志确认toolName能查到实现、执行函数被调用、返回值符合预期。这一步最常见的坑是工具名大小写不一致注册表里是exec事件里传成Exec查不到就静默失败。第四步验证结果回传。订阅tool_result事件确认toolCallId与tool_call匹配然后看模型最终回复是否用上了工具输出。如果模型回复里没有工具结果检查回传的历史里tool_result有没有正确挂到对应tool_call下。5. 本篇常见错排查报错一模型不生成 tool_calls。先确认模型支持 function calling去 https://taotoken.net/chat 用同样 prompt 试一次。再检查buildWorkspaceSkillsPrompt()是否把工具描述注入了 system prompt。最后看formatSkillsForPrompt()的 XML 有没有格式错误导致模型解析不了。报错二有 tool_call 事件但工具没执行。九成是toolName在注册表里查不到。打印注册表所有name和事件里的toolName逐字对比注意大小写和连字符。另一个可能是handleToolExecutionStart()没订阅到事件检查事件总线订阅是否在工具注册之后才建立。报错三工具执行了但模型没反应。检查tool_result的toolCallId是否和tool_call一致。不一致的常见原因是转换器在解析时重新生成了 ID而不是复用模型给的。还要确认回传历史时tool_result和tool_call的配对顺序正确顺序错了模型会忽略。报错四approval-pending 卡住不继续。这是审批流没走完不是链路断了。检查approvalId对应的审批请求有没有被处理处理完要主动触发继续否则事件总线一直在等。报错五参数格式不对。看attempt.tool-call-normalization.ts的标准化逻辑模型给的参数类型可能和工具 schema 不匹配比如数字给成了字符串。标准化层负责兜底转换如果它没覆盖你的场景就得手动补规则。6. 把链路跑通之后链路跑通后你会发现 OpenClaw 这套事件驱动设计的好处每个节点都是可观测的断在哪一环一目了然。我建议你在接入阶段就把tool_call和tool_result两个事件都打上日志带上runId和toolCallId线上出问题直接按 runId 捞全链路。长期做编码类 Agent 或需要多轮工具调用的场景可以考虑用 Coding Plan 来管理额度和并发地址是 https://taotoken.net/coding-plan 接入方式不变还是那套 base URL 和 Key。工具注册和适配层的细节文档在 https://taotoken.net/doc 遇到协议对不上的时候翻一下比猜快。
返回列表