# 工具系统 **一个工具就是 Agent 能伸出去的一只手。** 把语言模型单独放在那里,它只是一个包在文本里的模式匹配器。它不知道现在几点。它不知道你的文件里写了什么。它不能搜索网页、执行命令、看一份 PDF、把任务交给另一个 Agent、打开一个浏览器。它只能**谈论**做这些事。 工具是 MateClaw 解决这件事的方式。每一个工具是一个 Agent 被允许调用的具体操作——读文件、搜网页、执行 shell 命令、从 PDF 抽文字、把任务委托给另一个 Agent。Agent 判断需要某个工具时,发出一次**工具调用**,运行时执行它,结果作为**观察**回到 Agent 下一步推理里。 **二十个内置工具**开箱即用。无限多个可以通过 MCP 服务、自定义技能脚本、或者你自己写的 `@Tool` Spring bean 加进来。 --- ## 一次工具调用实际发生了什么 ``` Agent 判断需要一个工具 │ ▼ 发出工具调用:{"name": "WebSearchTool", "args": {"query": "..."}} │ ▼ ┌─────────────────────┐ │ 工具注册表 │ ← 按名字查工具 └─────────────────────┘ │ ▼ ┌─────────────────────┐ │ Tool Guard │ ← 基于规则的检查:allow / deny / 审批 └─────────────────────┘ │ ┌────┴────┐ │ │ ▼ ▼ 允许 审批挂起 → 用户决定 → 允许 / 拒绝 │ ▼ ┌─────────────────────┐ │ 执行(带超时) │ ← 异步,按工具单独设超时 └─────────────────────┘ │ ▼ 结果 → 观察 → Agent 下一步推理 ``` Tool Guard 是守门员。超时是**每个工具独立**的(这样一个慢工具冻不了整个回合)。在一次 Action 阶段里,Agent 同时调多个独立工具时它们可以**并发执行**。 这整套对 Agent 的 prompt 是**不可见**的。 --- ## 工具注册的三条路 **1. 内置工具。** MateClaw 出厂带的二十个工具,启动时自动注册到工具表里。 **2. MCP 服务。** 说 Model Context Protocol 的外部进程动态暴露工具。MateClaw 通过 `tools/list` 发现它们。见 [MCP 协议](./mcp)。 > **每 Agent 的 MCP 工具范围(1.4.0+,#117)**:当一个 Agent **没有勾选任何具体的 MCP 工具行**时,已启用的 MCP 工具会**自动并入**它的工具集;一旦它勾选了某些具体 MCP 工具,就**只限定在这个集合**内。只绑技能 / 内置工具的 Agent 仍保留对全部 MCP 工具的访问。 **3. 技能脚本。** 技能包可以带可执行脚本,运行时被包装成工具。见 [技能系统](./skills)。 工具发现是**黑名单式**的——默认所有可发现的工具都会被注册,需要排除哪个就显式排除。这样新加进来的工具不会因为白名单遗漏被默默忽略。 --- ## 渐进式工具披露(1.4.0+) 工具一多,系统 prompt 就会被几十个完整的工具 schema 撑大——哪怕这次任务只用得上一两个。**渐进式披露**把工具分成两层,让 prompt 跟着**任务**走,而不是跟着**工具总数**走。 | 层级 | 系统 prompt 里怎么呈现 | 能不能直接调 | |------|------------------------|--------------| | **核心层(CORE)** | 始终完整广播,带完整 schema | 开箱即用 | | **扩展层(EXTENSION)** | 只列一份压缩目录——名字 + 来源 + 一行说明,完整 schema 隐藏 | 先用 `enable_tool` 激活才能调 | **默认分层**:生成类工具(`image_generate`、`music_generate`、`video_generate`、`model3d_generate`)和 `browser_use` 默认放进**扩展层**;其余全部是**核心层**。 - **页面控制**——Tools 页面分「核心 / 扩展」两栏,内置工具和渠道工具每行有一个层级开关;MCP / ACP 工具的层级是锁定的。 - **持久化**——层级存在 `mate_tool.disclosure_tier` 和 `mate_mcp_server.disclosure_tier`。 - **配置**——`mateclaw.tools.disclosure.mode`,默认 `progressive`;设成 `legacy` 则恢复"全部广播"的老行为。 **为什么这么做**:不让上下文被白白撑爆——系统 prompt 的体积应该跟当前任务的需要成正比,而不是跟你装了多少工具成正比。 --- ## 二十个内置工具 | 工具 | 作用 | 危险 | |------|------|------| | `DateTimeTool` | 获取任意时区的当前日期时间 | — | | `WebSearchTool` | 通过搜索引擎链搜索(Serper / Tavily / DuckDuckGo / SearXNG) | — | | `ReadFileTool` | 读文件 | — | | `WriteFileTool` | 写内容到文件 | ⚠️ | | `EditFileTool` | 查找替换编辑 | ⚠️ | | `ShellExecuteTool` | 执行 shell 命令 | ⚠️ | | `FileTypeDetectorTool` | 检测 MIME 类型和编码 | — | | `DocumentExtractTool` | 从 PDF / DOCX / XLSX 抽文字 | — | | `WorkspaceMemoryTool` | 读写 Agent 的工作空间记忆 | — | | `SkillFileTool` | 读取和管理 `SKILL.md` 文件 | — | | `SkillScriptTool` | 执行技能脚本 | ⚠️ | | `SkillManageTool` | 创建 / 编辑 / 删除技能包 | ⚠️ | | `BrowserUseTool` | 驱动无头浏览器 | ⚠️ | | `DelegateAgentTool` | 把任务委托给另一个 Agent(支持并行) | — | | `MateClawDocTool` | 读取内置项目文档 | — | | `ImageGenerateTool` | 文生图 / **图生图(1.3.0+)** | — | | `VideoGenerateTool` | 文生视频 / 图生视频 | — | | `DocxRenderTool` | **1.3.0+** Markdown → .docx(Word 文档) | — | | `XlsxRenderTool` | **1.3.0+** Markdown 表格 → .xlsx(Excel) | — | | `PptxRenderTool` | **1.3.0+** Markdown(Marp 风格 `---` 分页) → .pptx | — | | `PdfRenderTool` | **1.3.0+** Markdown → 出版级 PDF(中文字体内嵌) | — | | `CronJobTool` | 创建和管理定时任务 | ⚠️ | | `DatasourceTool` | 管理外部数据源连接 | ⚠️ | | `SqlQueryTool` | 对已连接数据源执行 SQL 查询 | ⚠️ | | `send_file` | **1.4.0+** 把服务器上已有文件作为原生 IM 附件投递(#199) | — | | `enable_tool` | **1.4.0+** 在本次会话里激活一个扩展层工具 | — | | `load_skill` | **1.4.0+** 按需加载某个技能的 `SKILL.md` | — | 此外还有 [多模态创作](./multimodal) 的音乐生成工具 `MusicGenerateTool`。以及 [LLM Wiki](./wiki) 的 14 个 Wiki 工具:`wiki_read_page`、`wiki_read_many`、`wiki_list_pages`、`wiki_search_pages`、`wiki_semantic_search`、`wiki_compile_page`、`wiki_trace_source`、`wiki_create_page`、`wiki_delete_page`、`wiki_archive_page`、`wiki_unarchive_page`、`wiki_related_pages`、`wiki_explain_relation`、`wiki_enrich_page`。 ### 内容工作室工具(1.8.0+) 七个内置工具支撑 [内容工作室](./content-studio) 场景(公众号 / 小红书图文创作与发布): | 工具 | 做什么 | 危险 | |------|--------|------| | `wechat_article_extract` | 把 `mp.weixin.qq.com` 文章清洗成 `{标题, 作者, 时间, 正文, 图片}`(SSRF 限该 host) | — | | `gzh_package` | 打包公众号图文(内联 HTML + 封面);跑合规扫描 + 落台账 | — | | `gzh_publish` | 把文章推进微信**草稿箱**(`draft`);可选 `publish` 走审批 | ⚠️ | | `xhs_package` | 打包小红书笔记;硬校验 ≥3 张竖版卡片;扫 + 记 | — | | `xhs_publish` | 尽力而为的浏览器辅助上传(走审批) | ⚠️ | | `content_item` | 内容日历:`check_recent`(选题指纹去重)、`record`、`mark_published` | — | | `compliance_scan` | 服务端词库扫描(极限词 / 诱导词 / 承诺收益词);可选 `extraBannedWords` | — | ### DateTimeTool 返回给定时区的当前日期时间。没有意外。 ``` 输入:{"timezone": "America/New_York"} 输出:"2026-04-11T14:30:22" ``` ### WebSearchTool 通过**供应商链**搜索——DuckDuckGo 和 SearXNG 作为无 Key 的 fallback,Serper 和 Tavily 在你有 Key 时启用。在 `设置 → 系统设置 → 搜索服务` 里配置,**改完即生效,不需要重启**。 ``` 输入:{"query": "AgentScope Java 最新版本", "freshness": "month", "count": 5} 输出:"AgentScope Java 2.0 发布..." ``` 特性: - **供应商链**——主 provider 失败时链式 fallback 到下一个 - **高级参数**——`freshness`、`language`、`count` - **结果缓存**——近期查询被缓存 - **安全包装**——结果返回前先净化 - **原生搜索 + 工具搜索共存**——自带搜索的模型用原生搜索,工具搜索作为 fallback ### ShellExecuteTool 跨平台 shell 执行。Linux/macOS 用 `/bin/sh -c`,Windows 用 `cmd.exe /D /S /C`。**每一次调用都过 Tool Guard。** 安全设计: - **超时**——默认 60 秒,硬上限 300 秒 - **输出上限**——stdout 和 stderr 各自上限 10,000 字节 - **文件支撑输出**——写到临时文件,不是管道 - **结构化结果**——`{exitCode, stdout, stderr, timedOut}` - **危险模式检测**——`find -delete`、`rm -rf /`、管道 bash 下载触发更高级别审批 ### ReadFileTool / WriteFileTool / EditFileTool 读是安全的。写和编辑都过 Tool Guard。 ### DocumentExtractTool PDF、DOCX、XLSX 之类变成纯文本。扫描件在可用的地方降级到 OCR。 ### Office 文档生成(1.3.0+) 四个新工具,把 Markdown 直接渲染为可下载的 Office 文件——**不 fork 子进程,不依赖 npm**。生成的字节缓存在内存里,返回一个一次性下载链接: | 工具 | 适用 | 关键能力 | |---|---|---| | `DocxRenderTool.renderDocx` | 报告 / 备忘录 / 合同 / 简历 | 标题(# ## ###) / 加粗(**text**) / 列表 / 表格 / 图片(PNG/JPG/GIF/BMP/SVG → PNG) | | `DocxRenderTool.renderDocxFromFile` | 同上,但 markdown 在工作区文件里 | 用于 LLM 不想把已经写好的大段 markdown 当 tool 参数再发一次 | | `XlsxRenderTool.renderXlsx` | 财务表 / 数据导出 / 模板 | Markdown 表格语法 → 多 sheet(用 `## SheetName` 切分) | | `PptxRenderTool.renderPptx` | 演讲稿 / 项目方案 / 简报 | Marp 风格 `---` 分页;`16:9`(默认)/ `4:3` 比例 | | `PptxRenderTool.renderPptxFromFile` | 同上,markdown 在文件里 | 内容大于 5KB 时优选 | | `PdfRenderTool.renderPdf` | 出版级文档 / 周报 / 制式文件 | 1in 边距 / 智能分页 / 页码 / 封面页 / 中英混排(CJK 字体内嵌) | ::: tip 跟原有 `skills/docx` 的关系 现成的 `skills/docx` skill **保留**——它擅长的是**编辑已有 .docx**(tracked changes / 复杂 XML 操作)和首次安装时跑 `npm install docx`。新四个工具专门处理"从零创建"路径,**没有 npm 启动延迟**。Agent 首选这四个 RenderTool;要修已有 .docx 才转回 skill。 ::: ### ImageGenerateTool —— 1.3.0 起支持图像编辑 v1.2.0 时这个工具只能"文生图"。v1.3.0 起新增 `image` / `images` 两个参数,支持**多图输入的图像编辑**。详见 [多模态创作](./multimodal#image-edit)。 ### WorkspaceMemoryTool 让 Agent 读、写、编辑自己的工作空间记忆文件——`workspace/{agentId}/` 下面的任何 `.md`。见 [记忆系统](./memory)。 ### BrowserUseTool 驱动一个浏览器。每次调用都过 Tool Guard。 **按引用交互(1.8.0+)。** 工具把页面读成一份紧凑的**无障碍树快照**,每个可交互元素拿到一个稳定的 `ref` 句柄,点击 / 输入 / 选择都针对 **`ref` 指向的元素**而非截图坐标——一次操作能挺过页面重排而不落空。使用**真实**浏览器会话时加上**隐私护栏**,并保留一个受控的 CDP(Chrome DevTools Protocol)逃生舱应对安全路径够不着的场景(按需启用,非默认)。 ### DelegateAgentTool —— Agent 之间委托 一个 Agent 可以把子任务交给另一个 Agent: - **`delegateToAgent(agentName, task)`**——按名字调用指定 Agent,在隔离会话里执行任务 - **`listAvailableAgents()`**——列出所有可用 Agent ``` 用户:搜一下 Spring AI 的新闻,让 Writer 总结一下 Agent A:[调 WebSearchTool] [调 delegateToAgent(agentName="Writer", task="总结:...")] [收到 Writer 的回复] 合并后回复用户 ``` 安全: - **递归上限**——委托最多嵌套 3 层 - **隔离会话**——被委托的 Agent 跑在自己的会话里 - **结果截断**——委托结果上限 4000 字符 ### MateClawDocTool 读取内置的 MateClaw 项目文档。让 Agent 回答"MateClaw 里 X 是怎么工作的"这种问题时,**去查真文档**而不是猜。 ### enable_tool —— 激活扩展层工具(1.4.0+) `enable_tool(toolName)` 把一个**扩展层**工具激活,使它在**本次会话剩余的回合**里完整可调。 - **会校验**——只有在 Agent 的有效工具集里的工具才能激活。 - **下一回合生效**——激活在同一个 ReAct 循环的**下一次推理**时生效(Agent 先看到完整 schema,再发真正的调用)。 - **会话级,不持久化**——激活只对当前会话有效,不写库;新会话回到默认分层。 ### load_skill —— 按需加载技能(1.4.0+) `load_skill(skillName, filePath?)` 在需要时才把某个技能的 `SKILL.md` 加载进来——不传 `filePath` 读主文件,传了就读技能包内的子文件。 - **走消息历史注入**——加载的内容是注入到**消息历史**里,而不是系统 prompt,这样 **prompt 缓存保持稳定**(系统 prompt 不变,缓存不失效)。 - **后续回合保持**——已加载的技能在之后的回合里**钉住**,不用反复加载。 - **配置**——`mateclaw.skill.disclosure.load-skill-tool.enabled`,默认开启。 详见 [技能系统](./skills)。 ### send_file —— 把已有文件作为原生附件投递(1.4.0+,#199) `send_file(filePath, fileName?)` 读取服务器上**一个已经存在的文件**,把它作为**原生 IM 附件**投递——不是一条文本下载链接。 - **进生成文件缓存**——文件被放进生成文件缓存,渠道适配器(飞书 / 钉钉 / Telegram)**自动识别并投递**。 - **任意常见文件类型**,上限 **20 MB**。 - **跟 `ReadFileTool` 的区别**——`ReadFileTool` 把文件**抽成文本**喂给 Agent 推理;`send_file` 把文件**原样发给用户**。 ### ReadFileTool —— 超长行分页(1.4.0+,#190) 针对单行特别长的文件,`ReadFileTool` 新增可选的 `startColumn`(在 `startLine` 内的 1-based 字符偏移),用来**从一行的中间续读**它的尾部。 - 截断时**始终返回** `nextStartLine`; - 当这一行还有剩余没读完时,**额外返回** `nextStartColumn`。 把两者回填到下一次调用,就能把一个巨大的单行文件分段读完。 --- ## Tool Guard —— 权限层 Tool Guard 是 MateClaw 不让强工具干蠢事的机制。它是**基于规则的**,不是一个扁平的"危险 / 不危险"清单。每条规则说:*对这个工具,带这些参数,在这个上下文里,做 X*——X 是 `allow`、`deny`、或 `require_approval`。 核心几张表: - **`mate_tool_guard_rule`**——单条规则 - **`mate_tool_guard_config`**——全局配置 - **`mate_tool_guard_audit_log`**——每一次受守护的调用一条记录 示例规则:*`ShellExecuteTool`,命令以 `ls`、`cat`、`grep`、`find` 开头时允许。其他情况要求审批。* ```yaml mateclaw: tool: guard: enabled: true default-policy: require_approval rules: - tool: ShellExecuteTool arg-pattern: "^(ls|cat|grep|find)\\s" action: allow - tool: WriteFileTool action: require_approval ``` 或者在 `设置 → 安全与审批` 里可视化管理。规则判定为需要审批时,运行时会在 `mate_tool_approval` 持久化一条记录并把 Agent 回合挂起。完整机制在 [安全与审批](./security)。 ### 声明式 Hook 系统 Tool Guard 规则是一种更通用机制的特例——**声明式 Hook 系统**。5 个生命周期钩子覆盖工具调用和 LLM 调用的全部关键时刻: | Hook | 触发时机 | 典型用途 | |------|----------|----------| | `before_tool` | 工具执行前 | 参数脱敏、注入上下文、额外校验 | | `after_tool` | 工具执行后 | 结果过滤、审计记录 | | `before_llm` | LLM 调用前 | prompt 增强、缓存命中检查 | | `after_llm` | LLM 返回后 | 输出过滤、token 统计 | | `on_error` | 错误发生时 | 告警、降级策略 | Hook 在进程内执行,可以改参数、改结果、脱敏、加审计日志。你可以用 Hook 做 Tool Guard 之外的事——比如在每次 LLM 调用前注入安全策略,或者在工具返回后自动脱敏敏感字段。 --- ## 执行:并发、隔离、有界 - **并发执行**——一个回合里独立的工具调用并发跑。Guard 检查是顺序的,执行在安全的地方并发。 - **每工具超时**——每个工具有自己的超时。默认:快工具 30s,shell/browser 60s,生成类 300s。 - **段隔离**——回合中间需要审批时,段在审批边界处分裂。 - **观察截断**——结果超长会被自动截断。 - **错误隔离**——单个工具失败不会中止整个回合。 --- ## API 管理 ```bash # 列出所有工具 curl http://localhost:18088/api/v1/tools \ -H "Authorization: Bearer YOUR_JWT_TOKEN" # 启用 / 禁用 curl -X PUT "http://localhost:18088/api/v1/tools/1/toggle?enabled=false" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" # 设置内置或渠道工具的披露分级 curl -X PUT http://localhost:18088/api/v1/tools/1/disclosure-tier \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" \ -d '{"tier": "core"}' ``` 当前 REST API 管理工具行、启用状态和披露分级。内置工具的直接执行走 Agent runtime,不存在 `/tools/{name}/test` 端点。 --- ## 自定义工具 ### 路线 1:`@Tool` Spring bean ```java @Component public class FactorialTool { @Tool(description = "Calculate the factorial of a number") public String factorial( @ToolParam(description = "The number to compute factorial for") int n) { long result = 1; for (int i = 2; i <= n; i++) { result *= i; } return String.valueOf(result); } } ``` - Spring `@Component` - 每个 `@Tool` 方法变成一个可调用的工具 - 每个参数上用 `@ToolParam`——这是 LLM 读的描述 - 返回值就是 Agent 看到的观察 - **工具做任何危险的事情时,为它加一条 Tool Guard 规则** 重启后工具就活了。 ### 路线 2:技能脚本 不想写 Java?把行为打包成一个技能包,带 `SKILL.md` 和脚本。见 [技能系统](./skills)。 ### 路线 3:MCP 服务 能力已经以 MCP 服务形式存在?加个服务配置就行。见 [MCP 协议](./mcp)。 --- ## 2.1.0:渐进式工具桥与行动完成约束 工具很多时,MateClaw 先暴露轻量目录,再按当前任务需要展开具体 schema。渐进式工具桥减少上下文占用,也避免一次把数百个参数塞给模型;显式启用后的工具名会缓存和规范化,长循环里不重复扫描 MCP 热路径。 行动型请求还增加了完成约束:当用户要求“发送、创建、删除、查询外部系统、打开网页执行”等真实动作时,如果运行账本没有记录成功的实质性工具调用,系统会要求模型再尝试一次;仍未调用时以 `action_unverified` 收尾,工具已尝试但失败时以 `action_failed` 收尾,而不是声称“已完成”。当前约束验证的是“存在成功的实质性调用”,并不做工具结果与用户目标之间的语义等价证明。只读解释和无需工具的回答不受影响。 `browser_use` 在 2.1.0 加固了 ref 生命周期、导航安全、会话门、等待条件和快照:页面变化后旧 ref 会明确失效,导航与等待结果返回可诊断状态,避免点错旧元素或多个浏览器会话互相覆盖。 主动消息工具 `list_channel_sessions` / `send_channel_message` 只向当前工作空间内已验证的渠道会话推送;使用方式见 [多渠道接入](./channels)。 --- ## 下一步 - [技能系统](./skills)——建立在工具之上的更高层能力 - [MCP 协议](./mcp)——外部工具提供者 - [安全与审批](./security)——Tool Guard 规则、审批流程、审计日志 - [多模态创作](./multimodal)——生成类工具