Skip to content

第四章 工具系统——四块积木,无限可能

核心问题:为什么只给 Agent 四个工具,反而比给一百个工具更强大?


你有没有遇到过这种场景:问 ChatGPT "帮我找出项目里所有的 TODO 注释",它认真地回答你——"你可以用 grep -r TODO . 来查找",然后就停住了。

它知道怎么做,但它做不到。它被关在纯文本的牢笼里,只能说话,不能行动——一个博学的空想家,有无限的知识,却没有一双手。

工具系统解决的,正是这个问题。它让 Agent 从"告诉你怎么做"变成"替你去做"。但工具系统有一道设计上的难题:应该给 Agent 多少工具

OpenClaw 的答案出人意料——四个。


一、工具设计的两难困境

直觉上,工具越多越好。多一个工具,多一种能力,Agent 不就更强大了吗?

事实恰好相反。LLM 选择工具,靠的是工具的描述文本,而不是工具的代码。工具越多,描述空间越拥挤,边界越容易模糊。一旦两个工具功能相近,LLM 在选择时就开始犹豫——犹豫意味着错误率上升。

这里还有一个反直觉的推论:工具数量少,每个工具的描述空间反而更大,可以写得更精确。对比一下同一个 exec 工具在"四工具集"和"百工具集"中的描述质量——前者可以详细说明参数格式、适用场景、安全边界;后者不得不压缩描述,结果 LLM 理解不够准确,选错概率更高。工具数量的克制,直接带来了描述质量的提升,进而带来了决策准确性的提升。

工具数量与系统健康度之间,存在一个非线性关系:

工具集状态典型问题结果
工具太少能力不足,很多任务根本完成不了Agent 无能为力
工具适中边界清晰,各司其职准确率高,组合灵活
工具太多功能重叠,描述边界模糊选择混乱,准确率下降

更深的问题在于认知负担。工具集的健康度,不由工具数量衡量,而由工具间的正交性衡量——每个工具只做自己的事,不和别人重叠。

这就是 Unix 哲学的精髓:做一件事,把它做好;让程序之间能够协作。


二、四块积木:read / write / edit / exec

OpenClaw 继承了这个哲学,提炼出四个工具。

它们的分工来自一个简单的洞察:感知需要一个统一通道,行动有三种根本不同的语义——创造、修改、触发。如果用人类的感官和肢体来类比:

工具基础能力人类感官类比核心作用
read获取信息眼睛(感知世界)读取文件,理解现状
write创造内容笔(书写记录)创建新文件
edit修改内容橡皮+笔(编辑整理)精确修改已有文件
exec执行操作双手(触达世界)运行命令,触达外部
┌──────────────────────────────────────────────────┐
│                                                  │
│  感知世界 ──→  read(读取信息,理解现状)             │
│                     ↓                            │
│  思考推理 ←──  LLM(理解情况,制定计划)              │
│                     ↓                            │
│  改变世界 ──→  write(创建新文件)                   │
│               edit (修改现有文件)                 │
│               exec (执行命令,触达外部)            │
│                     ↓                            │
│  观察结果 ─────────────────────→ 回到感知           │
│                                                  │
└──────────────────────────────────────────────────┘

一个感知通道,三个行动通道——不是凑数,是刻意的分工设计。

你可能会问:既然 exec 能运行任何命令,为什么还要单独设计 readwriteedit?直接用 catecho >sed 不就行了?

这里有一道精妙的区别。exec 是万能工具,正因为万能,LLM 面对它时需要在脑海中构建完整的 Shell 命令,出错概率高。专用工具的价值在于:

场景exec 方式专用工具方式专用工具的额外保障
读文件cat file.txtread("file.txt")三层上下文保护,不会读爆窗口
写文件echo "content" > filewrite("file.txt", content)原子写入,语义明确是"全新创建"
改文件sed -i 's/old/new/g'edit("file.txt", old, new)精确匹配,找不到就报错而非误改
执行命令exec(command)命名清晰,可观测,可审计

约束即自由:工具的边界越清晰,LLM 的选择越准确。面对明确的 read 工具,LLM 做出正确决策的概率,远高于面对万能的 exec 后再自行组合命令。

read:感知世界,保护上下文

LLM 的上下文窗口是有限资源。把一个 10MB 的日志文件直接读进来,上下文就满了,Agent 会"忘记"自己在做什么。

read 用三层机制来保护上下文:

第一层:预算感知
  计算当前上下文剩余空间
  文件超出预算 → 触发截断

第二层:智能截断(按文件类型差异化)
  代码文件 → 保留头部(import + 函数签名)
  日志文件 → 保留尾部(最新的错误最有价值)
  配置文件 → 尽量完整(配置项相互依赖)

第三层:分页支持
  明确告知还有多少内容未读
  Agent 可发起第二次调用继续读取

分页机制里有一个容易被忽视的细节:它不是"能读大文件",而是"主动告知还有多少没读"。这种透明度让 Agent 能做出知情决策,而不是基于被截断的信息过度自信。

write:原子性创建

write 只做一件事:创建新文件。

最重要的特性是原子写入——先写入临时文件,成功后再重命名为目标文件。重命名在操作系统层面是原子操作,要么完成,要么不完成,不存在中间损坏状态。

这条"只创建新文件"的限制是刻意的保护。它防止了因文件名拼写错误意外覆盖已有内容的场景,也让工具调用历史里每一次 write 都保持清晰的语义——全新创造,而非替换。

edit:精确修改,失败安全

edit 的设计哲学可以用一句话概括:宁可报错,不可误改

它要求同时提供旧内容和新内容,在文件中搜索精确匹配,找到才替换,找不到就返回错误。这与 sed 截然不同——sed 会替换所有匹配的字符串,可能误改多处;edit 找不到唯一匹配时直接报错。

报错不是坏事。当 edit 报告"找不到指定内容",这条错误本身传递了两个高价值信息:文件当前内容与 Agent 的记忆不一致,或者提供的旧内容片段不够精确。这两个信息都直接指向下一步——重新 read 文件,再重试。

好的错误信息不是障碍,是导向下一步的线索

exec:通向外部世界的桥

exec 是四个工具中权力最大的一个。能运行任何 Shell 命令,触达几乎任何外部系统——测试套件、数据库、构建脚本、服务管理。凡是命令行能做的,exec 都能做。

两个值得关注的技术特性:

PTY(伪终端)支持——模拟真实终端环境,处理颜色代码、实时输出、交互式提示。没有 PTY,许多程序会检测到非终端环境并改变行为,比如缓冲所有输出直到结束,或拒绝启动交互模式。

一个具体场景:Agent 运行 npm init 创建新项目。这个命令会弹出交互式问答——"Package name: (my-project)"、"Version: (1.0.0)"……。如果没有 PTY,Agent 的 LLM 看不到这些提示,程序永远卡住。PTY 让 Agent 能看到终端的实时输出,读取提示内容,然后输入正确的回答继续流程。

后台进程模式——像开发服务器这样持续运行的命令,可以在后台启动后立即返回,Agent 随时可以查看输出或终止它。这让 Agent 能在服务运行的同时继续处理其他任务。

后台进程的完整生命周期是:启动 → 后台运行 → 随时查看输出 → 随时终止。实际场景:Agent 用 npm run dev 启动开发服务器后立即拿到进程 ID,随即继续处理用户的下一个请求;需要时再通过进程 ID 检查服务器日志或将其终止——服务器一直在跑,Agent 的主线程从未被占用。

工具核心能力关键设计
read感知世界,获取信息三层防御,保护上下文
write创造新文件原子写入,语义清晰
edit精确修改已有文件失败安全,错误有导向
exec执行命令,触达外部PTY 支持,后台进程

三、组合的力量:四个工具如何完成复杂任务

四个工具各自能做的事情,看起来都很简单。它们真正的价值在于组合

这就像编程语言里的基本类型——整数、字符串、布尔值本身都极其简单,但由它们组合出的数据结构和算法可以表达任意复杂的计算。工具的原子性不是局限,而是组合的前提。

来看一个具体例子:「找出所有 TODO 并生成可提交的清单」。

步骤 1  exec(grep -r "TODO" . --include="*.ts")
          → 搜索所有 TypeScript 文件中的 TODO

步骤 2  read(src/complex-module.ts)
          → 读取包含 TODO 的文件,确认上下文

步骤 3  write(TODO-report.md)
          → 生成按模块分类的 TODO 清单

更复杂的任务同样只用这四个工具。重构一个函数:

exec  → 搜索函数的所有引用位置
read  → 读取函数定义和调用上下文
edit  → 修改函数签名和实现
edit  → 逐处更新调用方
exec  → 运行测试套件
read  → 确认测试结果

这个工具链不是预先编程的,而是由 LLM 根据任务目标在运行时动态生成。每一步完成后,返回值进入对话历史,成为下一步推理的依据——这正是 ReAct 循环在工具层面的直接体现。

组合能力的层次是递进的:

原子操作  →  单个工具调用(read / write / edit / exec)

工具链    →  多工具顺序调用,完成有内在逻辑的任务片段

单 Agent  →  工具链动态编排,完成完整任务

多 Agent  →  多个 Agent 分工协作,各自调用工具集

四个积木,叠出无限高度。


四、exec 的安全护栏

能力越大,风险越高。exec 能运行任何命令,这意味着它也能运行 rm -rf /

OpenClaw 的设计哲学是:不限制工具的能力,而是在外层定义边界。工具专注功能,安全专注边界,两者解耦、各司其职。这样在开发阶段可以放宽限制快速迭代,生产部署时再收紧到最小权限,工具本身的代码不需要变动。

三层安全架构,从粗到细:

层级配置项可选值作用
Security 模式tools.exec.securitydeny / allowlist / full定义基本权限边界
Ask 模式tools.exec.askoff / on-miss / always何时需要人工确认
安全命令白名单tools.exec.safeBinsjq, head, tail只读安全命令,无需额外审批

Security 模式决定"能做什么"——deny 全部拒绝,allowlist 只允许白名单命令,full 不限制。

Ask 模式决定"做之前问不问"——off 直接执行,on-miss 命令不在白名单时询问,always 每次都问。

safeBins 是一个细粒度的补充——对于 jqheadtail 这类纯读取的工具,可以单独放行,不需要为每次查看文件内容都触发一次确认提示。

建议从保守配置起步,随着对 Agent 行为建立信任,再逐步开放——这与 chapter2 中讲的"渐进式建立信任"是同一个原则。


五、Skills:按需加载的上层扩展

四个工具解决了"能做什么",但还有另一个维度:知道怎么做好

一个懂代码审查的 Agent 和不懂的 Agent,使用的工具集完全相同——区别在于它是否知道:应该优先检查安全漏洞,其次是性能问题;某种写法是反模式;某个框架有特定最佳实践。这不是工具问题,是知识问题

这就是 Skills(技能)机制的用途。

技能是一个 Markdown 文件,包含某领域的专业知识、检查清单、决策指引。它不添加新工具,而是告诉 Agent 如何用已有工具把特定领域的任务做得更专业。

技能不预先加载进上下文,而是 Agent 在任务执行中判断需要时,通过 read 主动读取——上下文里只有当前用得到的知识:

工具扩展                    技能扩展
────────────────────       ────────────────────
增加 Agent 能做的事         增加 Agent 知道的事
通用性高                    专域性强
内置于运行时                按需从文件动态加载
改变执行能力                改变决策质量
更新需要修改代码             更新只需编辑 Markdown

这种设计有一个直接好处:技能更新不需要重启系统。编辑 Markdown,保存,Agent 下次读取时自然获得最新版本。知识与运行时解耦,维护成本极低。


小结

四个原语工具,通过 LLM 的动态编排,能够完成任意复杂的本地计算任务。秘密不在工具本身,而在于每次调用的返回值都会流回 ReAct 循环,成为下一步推理的依据——工具既是 Agent 的双手,也是它的感知系统。

工具/机制解决的问题关键设计
read感知世界,保护上下文三层防御(预算/截断/分页)
write创造新内容原子写入,语义清晰
edit精确修改已有内容宁可报错,不可误改
exec触达外部世界三层安全护栏,PTY 支持
Skills扩展领域知识按需加载,维护零成本

少即是多——简单性保证正交性,正交性保证组合性,组合性才是真正的超能力。

四个积木之所以够,不是因为它们功能强大,而是因为它们足够正交——每一块只做自己的事,不和别人重叠,所以可以自由组合,组合出的能力边界没有天花板。


第五章 消息循环