乐于分享
好东西不私藏

第三篇:工具系统——AI的手是怎么伸出去的

第三篇:工具系统——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
执行 Shell 命令
可配置安全级别(ask/approve/allow)
process
后台进程管理
启动、监控、终止长时间运行的进程

这里有一个细节值得关注:read 工具有自适应分页能力(代码在 src/agents/pi-tools.read.ts)。最大输出字节数动态计算:上下文窗口 Token 数 × 4 字节 × 20%,下限 50KB,上限 512KB。

为什么要这样设计?因为不同模型的上下文窗口大小差异很大(8k 到 200k+)。如果固定一个输出大小,对小窗口模型来说可能塞满整个上下文,对大窗口模型来说又浪费了容量。自适应的设计让工具在任何模型上都能高效工作。

第二类:通信工具——AI 的”嘴”

这是 OpenClaw 独有的工具,让 AI 能主动向各个渠道发消息。

message 工具是最核心的一个。它支持的操作根据当前所在渠道动态变化:

通用操作(所有渠道):send(发送)、reply(回复)、delete(删除)、react(添加 Emoji 反应)。

渠道专属操作:

• iMessagesendWithEffect(烟花等特效发送)

• Slackthread-reply(线程回复)、pin(钉住消息)

• Discordcomponents(添加按钮/下拉菜单)

• TelegramsendWithKeyboard(带键盘按钮发送)

sessions_* 工具族则更高级,让 AI 能跨会话通信:

• sessions_list:看自己有哪些对话

• sessions_history:读取某个对话的历史记录

• sessions_send:向另一个会话”发消息”(用于多 Agent 协作)

• sessions_spawn:生成一个子 Agent 去执行子任务

第三类:系统工具——AI 的”眼睛和手”

browser 工具:控制一个真实的浏览器实例。支持导航类(opennavigatetabs)、感知类(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)系统,控制在什么场景下哪些工具可以被使用。

策略系统分四层,优先级从低到高

优先级(低→高)
层级
作用范围
第 1 层(最低)
Global Policy(全局策略)
所有 Agent 共享的工具限制
第 2 层
Agent Policy(代理策略)
特定 Agent 的工具白名单/黑名单,如 work Agent 禁止 message
第 3 层
Group/Channel Policy(群组/渠道策略)
某个群组对话中限制特定工具,如禁止 cron
第 4 层(最高)
Subagent Policy(子代理策略)
spawn 深度越深,可用工具越少

每层策略支持三个字段:

{"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/*

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » 第三篇:工具系统——AI的手是怎么伸出去的

猜你喜欢

  • 暂无文章