第三篇:工具系统——AI的手是怎么伸出去的
AI 是怎么真的”干事”的?
你让 AI 帮你发一条 Telegram 消息,它是怎么真的发出去的?你让它查天气,它是怎么打开浏览器的?
语言模型本身只会生成文字——它不能直接调用 API,也不能操作文件。让 AI 真正能干事的,是工具系统(Tool Use)。
理解了工具调用机制,你就理解了 OpenClaw 从”聊天机器人”变成”能干事的 Agent”的关键一步。
Tool Use 的底层机制
模型是怎么”使用工具”的?
很多人以为工具是 AI 内部的某种能力,其实完全不是。工具调用的本质是一次特殊格式的文本输出。
当我们给模型提供工具时,实际上是把工具的 JSON Schema 描述塞进了上下文,告诉模型:”你现在有这些工具可以用,如果需要,你可以输出一段特定格式的 JSON 来调用它们。”

关键点:模型本身不执行任何代码,它只是输出一段 JSON。真正执行工具的是 OpenClaw。执行结果再作为新的”用户消息”追加到上下文,模型看到结果后继续生成——这就是 Agent Loop 的本质。
OpenClaw 的工具全景
OpenClaw 把所有工具分为五大类,核心代码在 src/agents/pi-tools.ts 的 createOpenClawCodingTools() 中组装:

逐类拆解:
第一类:编码工具——AI 的”文件柜”
这是从 pi-coding-agent 继承来的基础工具,让 AI 能读写文件、执行命令。
|
|
|
|
|---|---|---|
| read |
|
|
| write |
|
|
| edit |
|
|
| exec |
|
|
| process |
|
|
这里有一个细节值得关注:read 工具有自适应分页能力(代码在 src/agents/pi-tools.read.ts)。最大输出字节数动态计算:上下文窗口 Token 数 × 4 字节 × 20%,下限 50KB,上限 512KB。
为什么要这样设计?因为不同模型的上下文窗口大小差异很大(8k 到 200k+)。如果固定一个输出大小,对小窗口模型来说可能塞满整个上下文,对大窗口模型来说又浪费了容量。自适应的设计让工具在任何模型上都能高效工作。
第二类:通信工具——AI 的”嘴”
这是 OpenClaw 独有的工具,让 AI 能主动向各个渠道发消息。
message 工具是最核心的一个。它支持的操作根据当前所在渠道动态变化:
通用操作(所有渠道):send(发送)、reply(回复)、delete(删除)、react(添加 Emoji 反应)。
渠道专属操作:
• iMessage:sendWithEffect(烟花等特效发送)
• Slack:thread-reply(线程回复)、pin(钉住消息)
• Discord:components(添加按钮/下拉菜单)
• Telegram:sendWithKeyboard(带键盘按钮发送)
sessions_* 工具族则更高级,让 AI 能跨会话通信:
• sessions_list:看自己有哪些对话
• sessions_history:读取某个对话的历史记录
• sessions_send:向另一个会话”发消息”(用于多 Agent 协作)
• sessions_spawn:生成一个子 Agent 去执行子任务
第三类:系统工具——AI 的”眼睛和手”
browser 工具:控制一个真实的浏览器实例。支持导航类(open、navigate、tabs)、感知类(snapshot 获取页面结构、screenshot 截图、console 获取控制台日志)、交互类(act 点击/输入、dialog 处理弹窗、upload 文件上传)、输出类(pdf 保存页面为 PDF)。
nodes 工具:控制配对的移动设备节点(iOS/Android)。支持设备感知(camera_snap 拍照、camera_clip 录像、location_get 获取位置)、系统操作(notifications_* 管理通知、run 执行系统命令需审批)、通知推送(notify 发系统通知到设备)。
canvas 工具:控制 A2UI 实时可视化画布。支持基础操作(present 展示、hide 隐藏、navigate 切换页面)、动态执行(eval 在画布上执行 JavaScript)、状态管理(a2ui_push 推送 UI 状态、a2ui_reset 重置 UI)。
第四类:调度工具——AI 的”日程表”
cron 工具:创建和管理定时任务。支持 list(查看所有任务)、add(创建,支持 cron 表达式)、update(修改)、remove(删除)、run(立即执行)、wake(发送唤醒事件)。
这个工具有一个有意思的设计细节:当 AI 创建定时任务时,如果没有明确指定”消息发给谁”,系统会自动从当前会话 Key 推断送达目标——也就是说,任务触发后会默认回复到你现在所在的对话。
gateway 工具:管理网关配置,仅限所有者使用。支持 restart(重启网关)、config.get(查看配置)、config.apply(应用新配置)、update.run(执行自更新)。
第五类:渠道专属工具
除了通用的 message 工具,每个渠道还可以注册自己独有的工具。比如:
• discord_*:创建频道、管理角色、发 Embed 消息
• slack_*:管理工作区、操作工作流
• telegram_*:管理群组、设置成员权限
这些工具在非对应渠道的对话中不会出现,避免模型产生”在 Telegram 调用 Discord 工具”这类混乱。
工具的生命周期:从组装到执行
理解了有哪些工具,再来看工具是怎么”工作”的。
第一步:工具组装
每次 runEmbeddedAttempt() 启动时,都会调用 createOpenClawCodingTools() 组装一套当前可用的工具列表。
这里有一个重要概念——工具不是全局固定的,而是每次推理时按场景动态生成的。
组装过程:
1. 加载基础编码工具(pi-coding-agent 提供)
2. 加载 OpenClaw 专属工具:消息工具(根据当前渠道动态配置)、会话工具(根据可见性配置)、浏览器/节点/画布工具、Cron / Gateway 工具
3. 应用 Policy 过滤(详见下节)
4. 参数规范化:抹平不同模型对参数名的差异(Claude Code 期望 file_path,pi-agent 期望 path,统一处理)
5. 包装(Wrapping):挂载 before_tool_call Hook(插件扩展点)、AbortSignal(支持中途取消)、循环检测(防止 AI 反复调用同一工具陷入死循环)
第二步:模型调用工具
模型收到带有工具 Schema 的上下文,判断需要调用工具时,输出类似这样的结构:
{"type": "tool_use","id": "call_abc123","name": "browser","input": {"action": "navigate","url": "https://weather.com"}}
pi-agent-core 拦截这个输出,交给对应的工具执行。
第三步:工具执行与结果返回
工具执行完毕,结果以”工具结果消息”的形式追加到上下文:
{"type": "tool_result","tool_use_id": "call_abc123","content": "页面标题:北京天气预报\n明日:晴,25℃,东南风3级..."}
上下文更新后,模型再次被调用——这就是 Agent Loop 的一次完整迭代。
Policy 系统:谁能用什么工具
OpenClaw 有一套完整的工具策略(Policy)系统,控制在什么场景下哪些工具可以被使用。
策略系统分四层,优先级从低到高:
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
每层策略支持三个字段:
{"tools": {"allow": ["read", "write", "browser"], // 白名单(支持 glob)"deny": ["gateway", "cron"], // 黑名单(优先于白名单)"profile": "agent-default" // 使用预设策略组}}
黑名单永远优先于白名单——如果一个工具同时出现在 allow 和 deny 中,它会被拒绝。
几个特殊的权限控制
1. ownerOnly(仅限所有者)
部分工具标注了 ownerOnly: true,只有消息发送者是 Gateway 所有者时才能使用:cron(创建定时任务影响整个系统)、gateway(重启/修改网关配置)、nodes(控制配对的设备)。
2. 消息提供商限制
某些工具在特定消息来源下被自动禁用。例如 voice 模式(语音消息)下,tts 工具会被禁用——避免 AI 用 TTS 工具”说话”的同时系统也在播放语音。
3. 子代理深度限制
当 AI 用 sessions_spawn 生成子 Agent 时,子 Agent 的工具集会被自动收窄,且无论配置如何,以下工具对子 Agent 永远不可用:gateway(防止修改系统配置)、cron(防止创建定时任务)、sessions_send(子 Agent 通过固定的 announce 链与上级通信)、memory_search(上下文通过 spawn 提示传递,不需要自己检索)、whatsapp_login(交互式设置类工具,不适合自动化场景)。
这些限制的设计逻辑很清晰:子 Agent 是执行特定子任务的”工人”,不应该拥有”管理员”级别的权限。
Sandbox(沙箱):工具的安全边界
工具系统的最后一道防线是沙箱(Sandbox)。
当沙箱启用时,文件系统工具不再直接操作宿主机文件,而是通过一个 FsBridge(文件系统桥接) 访问容器内的隔离环境。沙箱关闭时,read 等工具直接读写宿主机文件系统;沙箱开启后,所有文件操作经过 FsBridge 转发到容器内的隔离文件系统。
沙箱同时还控制:
• 工作区访问级别:rw(读写)或 ro(只读)
• 浏览器隔离:沙箱内的浏览器只能访问容器内部的 bridge URL
• 工具策略叠加:沙箱可以在已有策略之上再叠加额外的工具限制
对于大多数个人使用场景,沙箱默认是关闭的——工作区是 AI 的”默认工作目录”而非硬隔离边界。绝对路径可以访问到工作区之外的任何地方(当然前提是 AI 决定这样做)。
工具系统全貌:从组装到执行

小结
工具系统最反直觉的一点:模型本身从不”执行”任何东西。它只是输出一段 JSON,告诉 OpenClaw”我想调用这个工具”,真正的执行发生在 OpenClaw 侧。这个分工让 AI 的能力边界完全由 OpenClaw 决定——工具加什么,AI 就能做什么。
Policy 系统则是这个能力边界的”闸门”:同一套工具,在不同场景(群组/子代理/渠道)下开放的范围不同。理解了 Policy 的四层优先级,就理解了为什么 AI 在某些场景下”不能”做某件事。
下一篇,我们向上一层,看 Gateway——这个本地 WebSocket 控制平面是如何把所有组件协调在一起的。
*本文基于 OpenClaw 2026.3.1 版本源码分析,核心文件:src/agents/pi-tools.ts、src/agents/pi-tools.policy.ts、src/agents/sandbox.ts、src/agents/tools/*
夜雨聆风