Skip to content

第四章 工具系统——Agent 是怎样真正动手的

核心问题:OpenClaw 的工具系统到底是什么,它解决了什么问题,这套系统又是怎样被组织起来并真正跑起来的?


第一节 为什么 Agent 需要工具系统

这一节只回答一个问题:为什么 Agent 不能只靠“会回答”,还必须有一套真正能动手的工具系统。

1.1 为什么“知道怎么做”还不够

很多人第一次接触 Agent 时,都会产生一个直觉:“模型已经这么聪明了,它知道命令怎么写、文件该怎么改、网页该怎么查,那它离真正干活不是只差一点点吗?”

其实差得不止一点。

因为知道怎么做,和真的去做,中间还隔着一整层系统能力。

可以先看一个最简单的对比:

你说的话只有聊天能力时会发生什么有工具系统时会发生什么
“帮我找出项目里所有 TODO”它会告诉你可以用 rggrep它会真的去搜索,然后把结果带回来
“把测试跑一下,看看哪里挂了”它会建议你运行 npm test它会真的跑命令,再根据报错继续判断
“新建一个 Markdown 文档,写一版总结”它会先把内容写在聊天框里它会直接创建文件并写入

这就是工具系统最朴素、也最关键的意义:它让 Agent 不只是“给建议”,而是开始“接手动作”。

上一章讲过,Function Calling 解决的是“模型可以明确说出自己想调哪个工具、参数是什么”。但真正到 OpenClaw 这层,问题已经不只是“模型会不会吐出一个函数调用 JSON”,而是:

  • 系统里有没有这些工具;
  • 这些工具怎么被暴露给模型;
  • 哪些场景能用,哪些场景不能用;
  • 工具执行完以后,结果怎么回到下一轮判断;
  • 出错时是直接崩掉,还是把错误变成下一步线索。

所以第四章真正要讲的,不是“模型怎么调一个函数”,而是:

OpenClaw 怎样把“会动手”这件事,做成一整套可以长期运行的基础设施。

1.2 工具不是越多越强,关键是别让模型选懵

理解工具系统时,第二个特别重要的点是:工具不是越多越好。

模型选工具时,看不到工具源码,也不会像程序员那样先把实现读完再做决定。它真正看到的,主要是两样东西:

  1. 这是什么工具,它是干什么的;
  2. 这个工具接受什么参数,返回什么结构。

也就是说,工具名、描述和 schema,本身就是接口的一部分。 这时候问题就来了:

  • 工具太少,很多事情确实做不了;
  • 工具太多,而且功能重叠,模型就很容易选错;
  • 两个工具只要“看起来都能做这件事”,调用准确率就会明显下降。

所以一个健康的工具系统,真正追求的不是“数量最大化”,而是两件事:

  • 边界清楚:这个工具到底负责什么;
  • 分工正交:它和别的工具尽量不要重叠。

这也是为什么 OpenClaw 很强调“原语”这个思路。它不是先问“要不要给 Agent 一百个特化小工具”,而是先问:能不能先把最底层、最通用、最不容易混淆的动作抽出来?

所以在工具系统设计上的核心目标就是让模型能够轻松选出最合适的工具。

1.3 从四个原语到完整工具面

如果把工具系统压到最底层去看,很多任务其实都可以拆成几个很朴素的动作:

text
看一眼         → read
新建一个       → write
改已有的       → edit
让外部世界动起来 → exec

这四个动作,是理解 OpenClaw 工具系统时最容易抓住的四个底层原语。
但如果你看今天的官方 runtime,完整工具面早已不止这四个,整个体系更准确地说是按 section 和 profile 组织起来的:

层次更像什么例子
原语层最底层动作read write edit exec
运行时层更工程化的动作封装process apply_patch
当前官方工具面按 section / profile 组织的 built-in surfacememory_search sessions_* message cron image tts

这说明一件事:复杂能力不是靠“给每个场景单独做一个按钮”长出来的,而是靠少量稳定原语,再叠上更专业的扩展长出来的。

这里还要顺手分清另外三个词:

名字它主要负责什么
工具让 Agent 真正去读、写、改、执行、搜索、操作外部对象
技能告诉 Agent 某类任务更专业的做法
插件扩展系统能力面,比如新渠道、模型提供商、工具、技能、语音、图像生成、memory / context slot

可以把它们理解成:工具负责“我能不能动手”,技能负责“我知不知道怎么做得更好”,插件负责“系统能不能再长出新的能力”。

这里尤其要提醒一句:TOOLS.md 不是工具开关面板。

第三章已经讲过,TOOLS.md 更像工作区里的环境备忘录,负责补充项目路径、常用命令和环境约定;真正决定“模型能不能看见某个工具、能不能调用某个工具”的,是这一章要讲的工具策略、沙箱、审批和运行时装配机制。

如果把第一节收成一句话,就是:

工具系统解决的不是“模型会不会说怎么做”,而是“系统能不能把动作真的交到模型手里,而且交得清楚、稳妥、可控”。


第二节 工具系统是怎样跑起来的

这一节要把“工具从哪里来、怎么进 prompt、怎么被筛选、怎么被执行、结果又怎么回到下一轮判断”连成一条线。

2.1 工具不是一下子冒出来的

如果你直接看今天的 OpenClaw 工具页,很容易误以为:“这些工具就是在一个数组里全注册进去,然后模型就能调了。”

但真实情况比这个更分层,也更工程化。

这里先解释一下 Pi 是什么。

如果你去看当前源码,会发现 OpenClaw 下面接着一层叫 Pi 的底层 Agent 运行时。你可以先把它理解成:OpenClaw 借来承接 agent core 的一层底座。

对这一章来说,你不用把它当成另一个要单独学习的大系统。你只需要知道一件事:Pi 不只提供基础 coding tools,还承接了 models、tools、session runtime 这类更底层能力;而 OpenClaw 则在它上面接管了 system prompt、session / discovery、tool wiring 和 channel delivery。

从官方文档和当前源码来看,OpenClaw 今天的工具栈,大致可以理解成这样一条生长链路:

text
Pi agent core(models / tools / session runtime)
→ OpenClaw 接管 system prompt、session / discovery 与工具装配
→ 组合内置 tools、shared message tool 与 plugin 能力
→ 按 profile / policy / provider / sandbox / subagent 做工具筛选
→ 把工具定义翻译成模型能理解的格式
→ 真正交给 Agent 运行

这里有个很重要的变化必须讲清楚:

OpenClaw 不是简单“借来就用”,而是在继承这层底层骨架之后,对工具面做了明显重组。

最典型的就是 bash。在底层继承链里你还能看到它的影子,但到了 OpenClaw 自己的工具栈里,更常见、也更重要的其实是:

  • exec:真正执行命令;
  • process:管理后台进程和已有会话。

这比“给模型一个裸 bash 工具”更符合 OpenClaw 自己的安全、审批、后台会话和跨运行时设计。

所以第二节首先想让大家看懂的一件事是:

工具系统不是“静态清单”,而是一条分层拼接出来的装配链。

2.2 工具怎样进入模型视野

工具真正能被模型调用,不是因为“系统里注册过它”就结束了。还有关键的一步:模型必须在这次 run 里真的看见它。

官方文档对这一点讲得很清楚。工具会通过两条并行通道交给模型:

通道作用
prompt 里的 Tooling 说明告诉模型有哪些工具、该怎么理解和使用
模型 API 的 tool schema告诉模型这些工具的结构化接口、参数和调用格式

可以把它理解成:prompt 负责“讲人话”,schema 负责“讲接口”,二者缺一不可。

在源码里,这一层还有一个很关键的“翻译器”角色。运行时内部的工具对象,并不会直接原样扔给模型 API,而是会先经过适配层,把它们转成统一的 ToolDefinition 风格:

text
内部工具对象
→ 统一名称、描述、参数 schema
→ 包上执行函数
→ 转成模型侧认识的 ToolDefinition

官方文档还特别强调了一件事:如果一个工具既没有出现在 prompt 的工具说明里,也没有出现在模型收到的 schema 里,那模型就根本不可能调用它。

但“看见工具”还不是故事的全部。OpenClaw 今天的工具系统,做得非常像一套分层权限系统。工具不是固定整包发过去的,而是一层层筛出来的。

最常见的几层可以先压成这张表:

过滤层它在决定什么
tools.profile默认给这一类 Agent 什么能力包
tools.byProvider不同模型提供商看到的基础工具面可不可以不同
allow / deny + agent 级配置全局和某个具体 Agent 要不要进一步收紧
sandbox tool policysandboxed run 里还允许哪些工具出现
subagent policy子 Agent 是否应该少拿一些系统级能力

这里最重要的原则是:deny 的优先级更高。

这里还要特别分清一件事:sandbox 本身决定的是工具在哪儿跑,不是工具是否可见。 真正控制 sandboxed run 工具面的,是 sandbox tool policy

也就是说,就算某个 profile 本来包含这个工具,只要你在 deny 里明确禁掉,它最后就不会进模型视野。

OpenClaw 还支持工具组这种快捷写法,比如 group:fsgroup:runtimegroup:messaging。同时,对 subagent 还会额外收掉一批更危险、更容易造成越权协作的工具。

OpenClaw 真正做的是“按场景分发工具”,而不是“一刀切全发”。

2.3 一次工具调用到底怎么跑完

上面讲的是“工具怎么进来”。接下来更关键的问题是:模型选中一个工具以后,后面到底发生了什么?

把整个过程压缩一下,大致是这样:

text
模型决定调用工具
→ OpenClaw 接住这次调用
→ 参数校验和必要预处理
→ 真正执行工具
→ 把结果封装回本轮运行
→ Agent 再看着结果决定下一步

如果你已经读过第二章,这里应该会有一种熟悉感。因为工具调用并不是“脱离 Agent Loop 的外插动作”,而是 ReAct 循环里的一个正式步骤。工具结果不是任务的终点,它往往只是下一轮判断的新现场

可以拿几类最典型的工具来看。

第一类readwriteedit 这类文件工具。

它们不是把底层文件操作原样裸给模型,而是会先根据运行环境决定怎么包装:在 host 上走 host 侧文件工具,在 sandbox 中走 sandbox 侧文件工具。
这里要特别注意,workspace 更像默认工作上下文,而不是天然的硬隔离;真正的文件系统隔离,要靠 sandboxing、workspaceAccess 这类边界来实现。

这意味着文件工具从一开始就不是“无边界自由读写”,而是:先分清上下文,再谈真正的隔离边界。

第二类execprocess 这类运行时工具。

exec 负责真正把命令跑起来,背后还要处理很多细节:命令在哪跑、要不要 PTY、是前台还是后台、需不需要审批、能不能中止。

process 负责的是查看后台进程状态、拉取输出、终止已有进程、继续跟踪长任务。

这两个工具配在一起,才让 OpenClaw 不只是“能打一条命令”,而是开始拥有持续运行外部过程的能力。一个很常见的场景就是:

text
exec     启动开发服务器
→ 先返回一个仍在运行的 process session
→ Agent 继续做别的事
→ 需要时再用 process 查看日志或终止

第三类apply_patch 这类更工程化的修改工具。它不是每个场景都会出现,也不是所有模型提供商都会支持得一样好。它是 exec 下面的结构化改动 subtool,在 OpenAI / OpenAI Codex 模型上默认可用,也可以再通过 tools.exec.applyPatch 收紧模型范围或工作区边界。它更像是对“修改文件”这一层的专业扩展,而不是修改能力的起点。

把这些拼到一起以后,一次工具调用的真实运行感会更像这样:

text
调 read
→ 拿到文件内容
→ 调 edit 或 apply_patch
→ 再调 exec 验证
→ 把结果交回下一轮判断

看到这里,第四章和第二章其实就重新接上了:Agent Loop 解决的是“如何一轮轮推进”;工具系统解决的是“推进时到底拿什么去碰这个世界”。

2.4 Skills 和安全护栏,为什么也在这一章

到了这里,还有两块必须补上:Skills安全护栏

很多人一看到 Skills,会先把它当成“提示词系统的事情”。这样理解不算错,但只说了一半。因为 Skills 在 OpenClaw 里干的,不只是“加一点提示词”,而是:

让 Agent 在需要时,临时拿到某个领域的专业打法,再去配合工具真正动手。

从当前官方文档和源码来看,Skills 至少有三件事值得记住:

  1. 技能不是全文常驻,系统通常只先注入一个紧凑索引;
  2. 真正需要时,模型再用 read 去读对应的 SKILL.md
  3. 技能来源可以有多种:bundled、~/.openclaw/skills~/.agents/skills、workspace 下的 .agents/skillsskills/,plugin 也可以携带 skills,而工作区里更靠后的路径通常优先级更高。

这说明一件事:Skill 的真正触发动作,仍然是工具调用。

也可以用一句更短的话记住它和工具的关系:

机制它主要改变什么
工具改变 Agent 能不能做这件事
技能改变 Agent 知不知道这件事更好的做法

工具系统一强,最自然的担心就是:“那它会不会乱执行?”

OpenClaw 的回答不是回避这个问题,而是把安全直接做进工具系统里。最常见的几层护栏,都在这里列出来了:

护栏它管什么
工具策略这个 Agent 到底能不能看见某个工具
sandbox工具在哪个运行边界里工作
exec approvalshost 上执行高风险命令前是否需要确认
safeBins给少量低风险只读命令开窄门
elevated在被允许的前提下临时提升执行边界
loop detection防止模型在工具上原地空转、反复重试

这里有一个比较另类但是很值得注意的点,是 loop detection。它看起来像“性能优化”,但其实也很重要,因为很多真实风险并不是“一下子做错一件大事”,而是:

text
同样的工具
→ 同样的失败
→ 再来一遍
→ 再失败
→ 在错误的路径上越跑越久

综上,OpenClaw 的工具系统不是“工具 + 说明书”这么简单,它是一整套“工具装配、工具暴露、工具过滤、工具执行、工具回传、工具护栏”共同组成的运行机制。


第三节 理解以后我们该怎么用

前两节讲的是原理,这一节只讲一件事:知道原理以后,我们该怎样更稳地设计、配置和使用这套工具系统。

3.1 先分清你缺的是工具、技能,还是规则

很多人在开始配置 Agent 时,最容易犯的错误不是“配少了”,而是把三种完全不同的问题混在一起解决

更稳的第一步,应该是先问自己:我现在缺的,到底是能力、知识,还是默认行为约束?

可以先用这张速查表:

现象更可能缺什么
它根本不能读、写、跑命令、搜网页工具
它能做,但做得不专业、不成体系技能
它老是在不该动手的时候动手,或者输出习惯不对规则 / 配置

举几个很典型的例子:

你的问题更合适的解法
“它没法启动本地测试”看工具策略里有没有 exec / process
“它会搜,但不会做系统化文献检索”补一份检索 skill
“每次删除文件前我都想让它先确认”改默认规则,并配合 approvals / policy
“它不知道我的项目入口文件在哪里”写进 TOOLS.md 或其他工作区配置

一句话说,就是:

text
缺手脚   → 补工具
缺打法   → 补技能
缺边界   → 改规则

3.2 从小而稳的工具集起步,再按场景分边界

理解了上面的区别以后,下一步就很自然了:不要一开始就想着“全给”,而要先想着“先给哪一小组最值钱”。

这是因为工具系统的代价,不只有安全风险,还有认知成本。

工具越多:

  • 模型要分辨的边界越多;
  • prompt 和 schema 开销越大;
  • 配置和排错也越复杂;
  • 你自己之后都更难判断“它为什么选了这个工具”。

所以更稳的做法通常是:

  1. 先从最贴近任务的一组默认 profile 起步;
  2. 再用 allow / deny 做小幅裁剪;
  3. 真遇到明显缺口,再补具体工具。

如果是写代码或本地自动化这种典型场景,通常会从 coding 这一类配置起步;如果只是让 Agent 主要做消息处理、渠道回复,那更偏 messaging 的能力边界往往就够用了。

同时,不要只按“这个系统需不需要这些工具”来想,而要按“这个 Agent 在这个场景里需不需要这些工具”来想。因为 OpenClaw 很多时候不是只有一个 Agent。你可能同时有主 Agent、只负责消息发送的辅助 Agent、只负责局部搜索的子 Agent、只在某个 surface 下工作的渠道 Agent。这些角色的风险边界,本来就不一样。

可以先看一个很粗的分法:

Agent 类型更适合什么能力边界
主 Agent可以更完整,但仍然要按任务收敛
子 Agent倾向更轻、更局部,少拿系统级能力
消息型 Agent以会话、发送、读取为主,不必给太多本地执行权限
只读分析型 Agent可以读、搜、看,但不一定要给写和执行

把这个原则再压缩一下,其实就是一句很简单的话:

  • 能局部化的能力,就不要全局化。
  • 能只读解决的任务,就别先给写入。
  • 能先在 sandbox 做的事,就别先放到 host。

3.3 最后把“能用”和“可控”一起设计

很多系统做到这里,会犯一个常见错误:前半段只想着“先让它跑起来”,后半段再回头补安全和可控。

但工具系统不是很适合这么做,因为对 OpenClaw 这类可执行 Agent 来说,高影响风险通常都会在工具调用阶段被放大。

等它已经接上外部命令、文件写入、网页或渠道操作、后台运行和多 Agent 协作之后,你再回头补边界,代价通常会更高。

更稳的做法,是从一开始就把“能用”和“可控”绑在一起想。

这时候最值得养成的四个习惯是:

  1. 默认按最小权限来给;
  2. 把高风险动作和确认机制一起设计;
  3. 把 sandbox 当默认工作区,而不是补丁;
  4. 不要乱扩大 safeBins 和 elevated。

这里还要额外提醒一句:第三方 skill 也不要天然当成“无害说明书”。

因为 skill 虽然自己不一定直接执行代码,但它完全可能把模型一步步引向高风险动作。所以你在设计工具系统时,最好把“技能会怎么引导工具使用”也一起考虑进去,而不要把第三方 skill 当成天然无害的说明书。

3.4 第四章最该带走的那句话

如果前面这几节都读完了,第四章最后最值得带走的,不是一串工具名,也不是某个配置项的细节,而是一种更稳的看法:

一个成熟的工具系统,重点从来不是“给 Agent 尽可能多的能力”,而是“用少而清楚的原语做骨架,用按需扩展的能力做上层,再用分层边界把整套系统管住”。

也就是说:

text
真正好的工具系统
不是越多越强
而是越清楚越能长期变强

这句话其实和第二章、第三章是完全接得上的。

  • 第二章告诉我们:系统要能持续推进;
  • 第三章告诉我们:系统要有稳定默认状态;
  • 第四章告诉我们:系统还得真的有手脚,而且这些手脚不能乱伸。

本章小结

这一章其实就讲清楚了三件事。

第一,工具系统解决的是“从会说到会做”的那一步。 没有它,Agent 最多只是个会给建议的聊天对象;有了它,Agent 才开始真的能读、写、改、执行,并把结果带回下一轮判断。

第二,OpenClaw 的工具系统不是一份静态清单,而是一条运行链。 工具会从底层骨架一路经过装配、注入、筛选、执行、回传和护栏,最后才真正出现在一次 run 里。

第三,学会这套机制以后,最重要的不是疯狂加工具,而是先分清问题类型,再按场景分配能力边界。 缺工具就补工具,缺专业打法就补 skill,缺默认行为约束就改规则;能少给就少给,能分层就分层,能进 sandbox 就先进 sandbox。

如果把第四章压成一句话,就是:

Agent 的工具系统,真正厉害的地方不在“会多少招”,而在“每一招都知道什么时候该出、什么时候不该出”。

下一章: 第五章 消息循环