0

ch-08

约 15000 字DraftOpenClaw Book

第 8 章 · 工具体系深度实践

Agent 的能力边界,就是它的工具边界。没有工具的 Agent 只会"说话";有了工具的 Agent 才能"做事"。OpenClaw 的工具体系是三层架构——内置工具是"手脚",技能(Skill)是"说明书",插件(Plugin)是"扩展包"。

本章你将学到:

  • 理解 OpenClaw 三层工具架构的设计哲学
  • 掌握内置工具的配置、安全控制和高级用法
  • 能独立编写 Skill,教会 Agent 新技能
  • 能编写和发布 Plugin,为 OpenClaw 扩展新能力

8.1 三层架构:工具、技能、插件

在上一章,你了解了会话管理——Agent 如何在有限记忆中保持连贯。本章转向"能力层":Agent 到底能做什么?

OpenClaw 的工具体系分三层,各有分工:

┌─────────────────────────────────────────────────────────────┐
│                      插件层 (Plugin)                         │
│  可安装的扩展包,注册新工具/通道/模型提供商/语音等             │
│  例如:@openclaw/voice-call, @openclaw/matrix               │
│  来源:npm / ClawHub / 本地目录                              │
├─────────────────────────────────────────────────────────────┤
│                      技能层 (Skill)                          │
│  SKILL.md 文件,注入系统提示词,教会 Agent 如何使用工具       │
│  例如:gemini、peekaboo、summarize                           │
│  来源:内置 / ~/.openclaw/skills / workspace/skills         │
├─────────────────────────────────────────────────────────────┤
│                      工具层 (Tool)                           │
│  Agent 可调用的类型化函数,发送给模型 API                     │
│  例如:exec、browser、web_search、read、write               │
│  来源:OpenClaw 内置 + 插件注册                              │
└─────────────────────────────────────────────────────────────┘

用一个比喻来理解:

  • 工具是 Agent 的"手脚"——能执行操作(读文件、运行命令、搜索网页)
  • 技能是 Agent 的"说明书"——告诉它什么时候用哪个工具、怎么用
  • 插件是 Agent 的"扩展包"——可以给 Agent 装上全新的手脚和说明书

没有技能的 Agent 拥有工具但不知道什么时候用;没有插件的 Agent 只能用内置能力。三者协同,才是完整的工具体系。

8.2 内置工具全览

OpenClaw 开箱即用的工具覆盖了 Agent 工作中的核心场景:

工具 功能 关键参数
exec / process 运行 Shell 命令,管理后台进程 command, workdir, background, timeout
browser 控制 Chromium 浏览器(导航、点击、截图) profile, target, snapshot/click/type
web_search 搜索网页 query, count, country, freshness
web_fetch 抓取网页并提取可读内容 url, extractMode, maxChars
read / write / edit 工作空间文件读写编辑 文件路径、内容
apply_patch 多文件补丁(OpenAI 模型) 工作区路径
message 跨所有通道发送消息 target, text, channel
canvas 驱动节点 Canvas present/eval/snapshot
nodes 发现和操作配对设备 discover/target
cron / gateway 管理定时任务、重启网关 定时表达式
image / image_generate 分析或生成图像 provider, prompt
sessions_* 会话管理、子 Agent list/history/send/spawn
tts 文字转语音 text, provider

8.2.1 工具配置:允许与拒绝

你可以通过配置精确控制 Agent 能用哪些工具:

{
  tools: {
    allow: ["group:fs", "browser", "web_search"],  // 只允许这些
    deny: ["exec"],                                  // 禁止 exec
  },
}

deny 优先级高于 allow——即使一个工具同时在两个列表中,它也会被禁止。

8.2.2 工具配置文件(Profile)

除了手动指定 allow/deny,OpenClaw 提供了几种预设配置文件:

配置文件 包含的工具 适用场景
full 所有工具(默认) 完全信任的本地环境
coding 文件 I/O、运行时、会话、记忆、图像 编程助手,不需要消息功能
messaging 消息发送、会话列表/历史/发送/状态 客服机器人,不需要文件访问
minimal 只有 session_status 最低权限,只做对话
{
  tools: {
    profile: "coding",  // 基础配置文件
    allow: ["browser"], // 在 coding 基础上额外允许 browser
    deny: ["exec"],     // 再排除 exec
  },
}

执行顺序:profile 先建立基础允许列表 → allow 追加 → deny 排除。

8.2.3 工具组(Group)

allow/deny 支持组快捷方式:

{
  tools: {
    allow: ["group:web"],  // 同时允许 web_search 和 web_fetch
    deny: ["group:runtime"],  // 同时禁止 exec, bash, process
  },
}
组名 包含的工具
group:runtime exec, bash, process
group:fs read, write, edit, apply_patch
group:sessions sessions_list, sessions_history, sessions_send, sessions_spawn, sessions_yield, subagents, session_status
group:memory memory_search, memory_get
group:web web_search, web_fetch
group:ui browser, canvas
group:automation cron, gateway
group:messaging message
group:nodes nodes
group:openclaw 所有内置工具(不含插件工具)

8.2.4 按模型提供商限制工具

有些模型提供商的安全策略不同,你可以按提供商设置不同的工具策略:

{
  tools: {
    profile: "coding",
    byProvider: {
      // 给 Gemini 最低权限(因为它对提示词注入更敏感)
      "google-antigravity": { profile: "minimal" },
      // 本地模型可以给完整权限
      "ollama": { profile: "full" },
    },
  },
}

这在多模型混合使用的场景中非常有用——给本地模型全权,给云端模型受限权限。

8.3 exec 工具:让 Agent 执行命令

exec 是 Agent 最强大的工具——它让 Agent 能在主机上运行任意 Shell 命令。强大意味着危险,所以 OpenClaw 为它设计了多层安全控制。

8.3.1 基本用法

// 前台执行
{ "tool": "exec", "command": "ls -la" }

// 后台执行 + 轮询
{ "tool": "exec", "command": "npm run build", "yieldMs": 1000 }
{ "tool": "process", "action": "poll", "sessionId": "<id>" }

// 向后台进程发送按键
{ "tool": "process", "action": "send-keys", "sessionId": "<id>", "keys": ["Enter"] }
{ "tool": "process", "action": "send-keys", "sessionId": "<id>", "keys": ["C-c"] }

8.3.2 执行位置:sandbox / gateway / node

exec 支持三种执行位置:

┌────────────────────────────────────────────────────────┐
│ host=sandbox(默认)                                    │
│   在 Docker 容器中执行                                  │
│   隔离性强,适合不可信的 Agent                            │
│                                                        │
│ host=gateway                                           │
│   在 Gateway 进程所在主机执行                            │
│   需要 approval 审批                                     │
│   适合需要访问宿主机资源的场景                            │
│                                                        │
│ host=node                                              │
│   在配对的远程设备上执行                                 │
│   需要 Node Host 运行                                   │
│   适合需要特定硬件的场景(如 macOS 上运行 Swift)         │
└────────────────────────────────────────────────────────┘

⚠️ 踩坑记录

问题:沙盒关闭后,Agent 调用 exec 仍然成功执行了命令。

原因:旧版 OpenClaw 在沙盒关闭时会静默回退到 gateway 执行。

解决:当前版本已修复——沙盒关闭 + host=sandbox 会直接失败,而不是静默回退。确保显式设置 host=gateway 或启用沙盒。

8.3.3 安全审批机制

当 exec 在 gateway 或 node 上执行时,需要通过审批:

{
  tools: {
    exec: {
      host: "gateway",
      security: "allowlist",  // deny | allowlist | full
      ask: "on-miss",        // off | on-miss | always
    },
  },
}
security 模式 行为
deny 拒绝所有主机执行(沙盒默认)
allowlist 只允许白名单中的命令路径
full 允许所有命令(危险,仅限可信环境)
ask 模式 行为
off 不弹审批(配合 allowlist 使用)
on-miss 白名单中没有的命令才弹审批
always 每次都弹审批

审批列表存储在 ~/.openclaw/exec-approvals.json,支持三种响应:

  • allow-once:本次允许
  • allow-always:永久加入白名单
  • deny:拒绝

8.3.4 会话级覆盖

你可以用 /exec 命令在当前会话中临时更改 exec 设置:

/exec host=gateway security=allowlist ask=on-miss node=mac-1
/exec                     # 查看当前设置

这只影响当前会话,不写入配置文件。要永久禁用 exec,使用 tools.deny: ["exec"]

8.3.5 安全回收站:Safe Bins

OpenClaw 区分两种"白名单":

  • allowlist:完全信任的可执行文件路径
  • safeBins:仅 stdin 模式的流过滤器(如 catheadgrep
{
  tools: {
    exec: {
      safeBins: ["cat", "head", "tail", "grep", "wc"],
      safeBinTrustedDirs: ["/usr/local/bin/mysafetools"],
    },
  },
}

⚠️ 安全警告

不要把解释器(python3noderubybash)加入 safeBins。safeBins 的设计初衷是"只能读取 stdin 的纯过滤器"。解释器可以执行任意代码,放在 safeBins 中等于绕过了安全控制。如果需要允许解释器,使用显式的 allowlist 条目并保持审批开启。

8.4 browser 工具:让 Agent 操控浏览器

browser 工具让 Agent 能像人一样操作网页——打开页面、点击按钮、填写表单、截图。

8.4.1 两个浏览器档案

OpenClaw 的浏览器工具支持两种档案(Profile):

openclaw 档案(默认)
├── 独立的 Chromium 实例
├── 不共享你的登录状态
├── Agent 可以完全控制
└── 安全、隔离

user 档案
├── 附加到你正在运行的 Chrome
├── 共享你的登录状态(已登录的网站可以直接用)
├── 通过 Chrome DevTools MCP 协议连接
└── 需要你在电脑前批准连接

选择建议:日常自动化用 openclaw 档案;需要操作已登录的网站时用 user 档案。

8.4.2 快速上手

# 启动浏览器
openclaw browser start

# 打开网页
openclaw browser open https://example.com

# 获取页面快照(AI 模式,返回带编号的元素列表)
openclaw browser snapshot

# 获取交互元素列表(角色模式,返回可操作的元素)
openclaw browser snapshot --interactive

# 点击编号为 12 的元素
openclaw browser click 12

# 在编号为 23 的输入框中输入文字
openclaw browser type 23 "hello"

# 截图
openclaw browser screenshot

# 等待特定文本出现
openclaw browser wait --text "Done"

# 等待 URL 匹配
openclaw browser wait --url "**/dashboard"

8.4.3 Agent 如何使用浏览器

Agent 获取一个 browser 工具,工作流程是:

1. Agent 调用 browser snapshot → 获取页面元素列表和编号
2. Agent 根据编号调用 browser act(click/type/drag/select)
3. 需要验证时调用 browser screenshot
4. 编号在导航后会变化,需要重新 snapshot

这意味着 Agent 不需要写 CSS 选择器——它通过"看"(snapshot)来"操作"(click/type),和人类操作浏览器的方式一样。

8.4.4 配置

{
  browser: {
    enabled: true,
    defaultProfile: "openclaw",
    headless: false,  // true = 无头模式,不显示浏览器窗口
    profiles: {
      openclaw: { cdpPort: 18800, color: "#FF4500" },
      // 远程浏览器(如 Browserless 云服务)
      browserless: {
        cdpUrl: "wss://production-sfo.browserless.io?token=<KEY>",
        color: "#00AA00",
      },
    },
  },
}

8.4.5 调试工作流

当 Agent 的浏览器操作失败时(如"not visible"、"strict mode violation"):

# 1. 查看当前页面状态
openclaw browser snapshot --interactive

# 2. 使用角色引用操作(更精确)
openclaw browser click e12

# 3. 高亮显示目标元素,确认 Playwright 找到了正确的元素
openclaw browser highlight e12

# 4. 检查网络请求
openclaw browser requests --filter api --clear

# 5. 检查控制台错误
openclaw browser console --level error

# 6. 深度调试:录制 Trace
openclaw browser trace start
# ... 复现问题 ...
openclaw browser trace stop

💡 提示:快照中的引用编号(ref)在页面导航后会失效。如果操作失败,重新获取快照并使用新的编号。这是设计如此——保证操作的是"当前"页面的"当前"状态。

8.5 web_search 和 web_fetch:信息获取双武器

8.5.1 web_search:搜索网页

web_search 是轻量级的 HTTP 搜索工具,不涉及浏览器自动化。

选择搜索提供商

提供商 结果风格 API Key 特色
Brave 结构化摘要 BRAVE_API_KEY 免费 1000 次/月,支持 llm-context 模式
DuckDuckGo 结构化摘要 无需 免费,非官方 HTML 解析
Gemini AI 合成答案 + 引用 GEMINI_API_KEY 谷歌搜索增强
Grok AI 合成答案 + 引用 XAI_API_KEY xAI 搜索增强
Perplexity 结构化 + 内容提取 PERPLEXITY_API_KEY 支持域名过滤
Exa 神经搜索 + 内容提取 EXA_API_KEY 语义搜索,支持高亮
Firecrawl 结构化摘要 FIRECRAWL_API_KEY 搭配 scrape 工具深度提取
Tavily 结构化摘要 TAVILY_API_KEY 支持主题过滤

自动检测机制:如果不指定 provider,OpenClaw 按以下顺序检测 API Key 并使用第一个找到的:

Brave → Gemini → Grok → Kimi → Perplexity → Firecrawl → Tavily → DuckDuckGo(兜底)

配置示例(Brave Search)

{
  plugins: {
    entries: {
      brave: {
        config: {
          webSearch: {
            apiKey: "BRAVE_API_KEY_HERE",
          },
        },
      },
    },
  },
  tools: {
    web: {
      search: {
        provider: "brave",
        maxResults: 5,
        timeoutSeconds: 30,
        cacheTtlMinutes: 15,
      },
    },
  },
}

8.5.2 web_fetch:抓取网页内容

web_fetch 做的事情很简单:HTTP GET + HTML 转可读内容。它不执行 JavaScript,所以不适合 JS 重度的网站。

{
  tools: {
    web: {
      fetch: {
        enabled: true,
        maxChars: 50000,
        timeoutSeconds: 30,
        cacheTtlMinutes: 15,
        readability: true,  // 使用 Readability 提取正文
      },
    },
  },
}

Firecrawl 回退:如果 Readability 提取失败,可以配置 Firecrawl 作为回退方案——它有更强的反爬虫绕过能力:

{
  tools: {
    web: {
      fetch: {
        firecrawl: {
          enabled: true,
          apiKey: "fc-...",
          timeoutSeconds: 60,
        },
      },
    },
  },
}

选择决策

需要搜索?→ web_search
需要读取特定 URL?→ web_fetch
网页是 JS 渲染的?→ browser 工具
需要登录?→ browser 工具(user 档案)

8.6 技能(Skill):教会 Agent 新技能

Skill 是 OpenClaw 最灵活的扩展方式之一。它不需要写代码——只需要写一个 Markdown 文件。

8.6.1 Skill 是什么

每个 Skill 是一个包含 SKILL.md 的目录。SKILL.md 由两部分组成:

---
name: my-skill
description: 用简洁的一句话描述这个技能
---

这里是详细的 Markdown 指令,告诉 Agent:
- 什么时候使用这个技能
- 使用哪些工具
- 按什么步骤操作
- 有什么注意事项

YAML 头(frontmatter)是元数据,告诉 OpenClaw "这是一个技能";Markdown 正文是"说明书",注入到系统提示词中。

8.6.2 Skill 的加载位置和优先级

Skill 可以存放在三个地方:

<workspace>/skills/          (最高优先级,仅当前 Agent 可见)
~/.openclaw/skills/          (中优先级,所有 Agent 共享)
OpenClaw 内置                (最低优先级)

同名 Skill,高优先级覆盖低优先级。这意味着你可以在 workspace 中自定义内置 Skill 的行为——只需要创建同名目录。

还可以通过配置添加额外的共享目录:

{
  skills: {
    load: {
      extraDirs: ["~/Projects/agent-scripts/skills"],
    },
  },
}

8.6.3 动手写第一个 Skill

场景:你想让 Agent 在每次生成代码后自动运行测试。

# 1. 创建 Skill 目录
mkdir -p ~/.openclaw/workspace/skills/test-after-code

# 2. 编写 SKILL.md

~/.openclaw/workspace/skills/test-after-code/SKILL.md

---
name: test_after_code
description: 在生成或修改代码文件后,自动运行相关测试
---

# 代码后测试

## 触发条件

当用户要求你编写、修改或重构代码文件时,在完成代码编写后:
1. 检查项目中是否存在测试文件
2. 如果存在,运行对应的测试命令
3. 如果测试失败,修复代码并重新运行
4. 直到所有测试通过再回复用户

## 步骤

1. 用 `exec` 运行 `find . -name "*.test.*" -o -name "*_test.*" -o -name "test_*"` 查找测试文件
2. 根据项目类型运行测试:
   - Node.js: `npm test` 或 `npx jest`
   - Python: `pytest` 或 `python -m pytest`
   - Go: `go test ./...`
3. 如果测试失败,分析失败原因并修复
4. 重新运行测试确认通过

## 注意

- 不要在测试命令中添加不存在的测试文件
- 如果项目没有测试框架,跳过此技能
- 长时间运行的测试套件可以设置 `yieldMs: 5000` 后台运行

3. 启用新会话

/new  # 或 openclaw gateway restart

4. 验证 Skill 已加载

openclaw skills list

5. 测试

你:帮我写一个计算斐波那契数列的函数
Agent:[编写代码]
       [自动检测到测试框架]
       [运行测试]
       [测试通过]
       [回复用户]

8.6.4 环境门控:Skill 的条件加载

不是所有 Skill 都应该在所有环境中可用。OpenClaw 提供了"门控"(Gating)机制——在加载时根据条件过滤 Skill:

---
name: gemini
description: 使用 Gemini CLI 进行编程辅助和 Google 搜索
metadata:
  {
    "openclaw":
      {
        "emoji": "♊️",
        "requires": { "bins": ["gemini"] },
        "os": ["darwin", "linux"],
      },
  }
---

门控字段:

字段 含义
requires.bins 所有列出的二进制必须在 PATH 中
requires.anyBins 至少一个二进制在 PATH 中
requires.env 环境变量必须存在(或在 config 中提供)
requires.config openclaw.json 中的指定路径必须为真值
os 限定操作系统(darwinlinuxwin32
always 始终包含(跳过其他门控)

如果门控条件不满足,Skill 不会出现在系统提示词中——Agent 根本不知道有这个 Skill。

8.6.5 Skill 配置

你可以在配置中启用/禁用 Skill、注入环境变量:

{
  skills: {
    allowBundled: ["gemini", "peekaboo"],  // 只允许这些内置 Skill
    entries: {
      "image-lab": {
        enabled: true,
        apiKey: { source: "env", provider: "default", id: "GEMINI_API_KEY" },
        env: {
          GEMINI_API_KEY: "GEMINI_KEY_HERE",
        },
      },
      "unwanted-skill": { enabled: false },  // 禁用某个 Skill
    },
  },
}

⚠️ 安全警告

第三方 Skill 应被视为不可信代码。安装前务必阅读 SKILL.md 内容。对于不信任的输入和有风险的工具调用,优先在沙盒中运行。

8.6.6 ClawHub:公共 Skill 市场

ClawHub 是 OpenClaw 的公共 Skill 注册中心,浏览地址:https://clawhub.com

# 安装 Skill 到当前 workspace
openclaw skills install <skill-slug>

# 更新所有已安装的 Skill
openclaw skills update --all

# 列出已安装的 Skill
openclaw skills list

8.6.7 Token 成本

每个 Skill 在系统提示词中约占 97 个 token(加上名称和描述的长度)。如果你加载了大量 Skill,这些 token 会累积。通过 /context list 可以查看 Skill 占用的具体 token 数:

Skills list: 2,184 chars (~546 tok) (12 skills)

如果 Skill 占用太多上下文,用 skills.allowBundled 精简允许的 Skill 列表。

8.7 插件(Plugin):给 OpenClaw 装上新能力

Plugin 是 OpenClaw 最强大的扩展方式。它可以注册新的工具、通道、模型提供商、语音服务等——几乎所有能力都可以通过 Plugin 扩展。

8.7.1 Plugin 的两种格式

格式 工作方式 来源
Native openclaw.plugin.json + 运行时模块,进程内执行 官方插件、社区 npm 包
Bundle Codex/Claude/Cursor 兼容布局,映射到 OpenClaw 功能 .codex-plugin/.claude-plugin/.cursor-plugin/

Bundle 格式意味着 OpenClaw 可以直接使用为其他 AI 编码工具开发的插件——这是一个重要的生态兼容设计。

8.7.2 安装和管理

# 查看已加载的插件
openclaw plugins list

# 从 npm 安装
openclaw plugins install @openclaw/voice-call

# 从 ClawHub 安装
openclaw plugins install clawhub:@openclaw/voice-call

# 从本地目录安装(开发模式)
openclaw plugins install ./my-plugin

# 更新
openclaw plugins update --all

# 诊断
openclaw plugins doctor

8.7.3 配置

{
  plugins: {
    enabled: true,
    allow: ["voice-call"],
    deny: ["untrusted-plugin"],
    entries: {
      "voice-call": {
        enabled: true,
        config: { provider: "twilio" },
      },
    },
    slots: {
      memory: "memory-core",       // 记忆插件槽位(互斥)
      contextEngine: "legacy",     // 上下文引擎槽位(互斥)
    },
  },
}

关键概念:Slots(槽位)是互斥的——同一类别只能有一个活跃插件。例如 memory 槽位可以是 memory-core(内置)或 memory-lancedb(安装型),但不能同时启用两个。

8.7.4 发现顺序

OpenClaw 按以下顺序发现插件(第一个匹配生效):

1. plugins.load.paths  →  显式指定的文件/目录
2. <workspace>/.openclaw/extensions/  →  工作空间扩展
3. ~/.openclaw/extensions/  →  全局扩展
4. 内置插件  →  随 OpenClaw 安装

工作空间来源的插件默认禁用——必须显式启用。内置插件遵循各自的默认启用/禁用状态。

8.7.5 核心 Plugin API

Plugin 通过 register(api) 回调注册能力:

export default definePluginEntry({
  id: "my-plugin",
  name: "My Plugin",
  register(api) {
    // 注册模型提供商
    api.registerProvider({ /* ... */ });

    // 注册 Agent 工具
    api.registerTool({
      name: "my_tool",
      description: "做一件事",
      parameters: Type.Object({ input: Type.String() }),
      async execute(_id, params) {
        return { content: [{ type: "text", text: `Got: ${params.input}` }] };
      },
    });

    // 注册通道
    api.registerChannel({ /* ... */ });

    // 注册生命周期钩子
    api.registerHook("before_tool_call", async (ctx) => {
      // 在工具调用前执行逻辑
      return { block: false };
    });
  },
});

完整的注册方法列表:

方法 注册什么
registerProvider 模型提供商(LLM)
registerChannel 聊天通道
registerTool Agent 工具
registerSpeechProvider 语音合成 / 语音识别
registerMediaUnderstandingProvider 图像/音频分析
registerImageGenerationProvider 图像生成
registerWebSearchProvider 网页搜索
registerHook / on(...) 生命周期钩子
registerHttpRoute HTTP 端点
registerCommand / registerCli CLI 命令
registerContextEngine 上下文引擎
registerService 后台服务

8.8 动手写一个 Plugin

现在我们来写一个实用的 Plugin:一个能查询服务器状态的自定义工具。

8.8.1 项目结构

my-server-monitor/
├── package.json
├── openclaw.plugin.json
├── index.ts
└── tsconfig.json

8.8.2 package.json

{
  "name": "@myorg/openclaw-server-monitor",
  "version": "1.0.0",
  "type": "module",
  "openclaw": {
    "extensions": ["./index.ts"]
  }
}

openclaw 字段告诉 OpenClaw 去哪里找入口文件。

8.8.3 openclaw.plugin.json

{
  "id": "server-monitor",
  "name": "Server Monitor",
  "description": "查询服务器状态信息",
  "configSchema": {
    "type": "object",
    "additionalProperties": false,
    "properties": {
      "servers": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "name": { "type": "string" },
            "host": { "type": "string" },
            "port": { "type": "number" }
          },
          "required": ["name", "host"]
        }
      }
    }
  }
}

manifest 声明了插件的身份、配置 Schema。即使不需要配置,也必须提供空的 configSchema。

8.8.4 index.ts

import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
import { Type } from "@sinclair/typebox";

interface ServerConfig {
  name: string;
  host: string;
  port?: number;
}

export default definePluginEntry({
  id: "server-monitor",
  name: "Server Monitor",
  description: "查询服务器状态信息",
  register(api) {
    // 注册必需工具——始终可用
    api.registerTool({
      name: "server_status",
      description: "查询已配置服务器的状态",
      parameters: Type.Object({
        serverName: Type.Optional(Type.String({ description: "服务器名称" })),
      }),
      async execute(_id, params) {
        const config = api.pluginConfig as { servers?: ServerConfig[] };
        const servers = config.servers || [];

        const target = params.serverName
          ? servers.find(s => s.name === params.serverName)
          : servers[0];

        if (!target) {
          return {
            content: [{ type: "text", text: `未找到服务器: ${params.serverName || "默认"}` }],
          };
        }

        // 这里是实际的查询逻辑
        // 示例:通过 exec 检查服务器是否在线
        return {
          content: [{
            type: "text",
            text: `服务器 ${target.name} (${target.host}:${target.port || 80}) 状态正常`,
          }],
        };
      },
    });

    // 注册可选工具——用户必须显式允许
    api.registerTool(
      {
        name: "server_restart",
        description: "重启指定的服务器(危险操作)",
        parameters: Type.Object({
          serverName: Type.String({ description: "服务器名称" }),
        }),
        async execute(_id, params) {
          return {
            content: [{
              type: "text",
              text: `已发送重启请求到 ${params.serverName}`,
            }],
          };
        },
      },
      { optional: true },
    );
  },
});

关键设计决策

  • server_status 是必需工具——安全,只读操作
  • server_restart 是可选工具——有副作用,用户必须显式允许

8.8.5 使用

// openclaw.json
{
  plugins: {
    entries: {
      "server-monitor": {
        enabled: true,
        config: {
          servers: [
            { name: "web-1", host: "192.168.1.10", port: 80 },
            { name: "db-1", host: "192.168.1.20", port: 5432 },
          ],
        },
      },
    },
  },
  // 允许可选工具
  tools: {
    allow: ["server_restart"],
  },
}
# 安装
openclaw plugins install ./my-server-monitor

# 重启 Gateway
openclaw gateway restart

# 验证
openclaw plugins list

8.9 子 Agent(Sub-Agent):并行任务分派

子 Agent 是 OpenClaw 的"多任务处理"机制——主 Agent 可以派生出独立的子 Agent 在后台并行执行任务。

8.9.1 工作原理

主 Agent
├── 收到用户请求:"帮我同时查三个项目的状态"
├── 调用 sessions_spawn × 3
│   ├── 子 Agent A → 查询项目 Alpha
│   ├── 子 Agent B → 查询项目 Beta
│   └── 子 Agent C → 查询项目 Gamma
├── [等待所有子 Agent 完成]
└── 汇总结果并回复用户

每个子 Agent 运行在独立的会话中(agent:<agentId>:subagent:<uuid>),有独立的上下文和 Token 消耗。完成后通过"announce"机制将结果回传给主 Agent。

8.9.2 配置

{
  agents: {
    defaults: {
      subagents: {
        model: "anthropic/claude-sonnet-4-6",  // 子 Agent 使用更便宜的模型
        maxSpawnDepth: 1,                       // 不允许嵌套派生(默认)
        maxChildrenPerAgent: 5,                 // 每个 Agent 最多 5 个子任务
        maxConcurrent: 8,                       // 全局并发上限
        runTimeoutSeconds: 900,                 // 单次运行超时(秒)
        archiveAfterMinutes: 60,                // 完成后 60 分钟归档
      },
    },
  },
}

💡 成本提示:每个子 Agent 有独立的上下文和 Token 消耗。对于繁重或重复性的任务,给子 Agent 配置更便宜的模型,主 Agent 用高质量模型——这样可以显著降低成本。

8.9.3 嵌套子 Agent(编排器模式)

maxSpawnDepth: 2 时,子 Agent 可以再派生子 Agent:

主 Agent
└── 编排器子 Agent(depth 1)
    ├── 工人子 Agent A(depth 2)→ 执行具体任务
    ├── 工人子 Agent B(depth 2)→ 执行具体任务
    └── 工人子 Agent C(depth 2)→ 执行具体任务

结果沿着链条回传:depth-2 → depth-1 → 主 Agent。

深度 会话键格式 角色 能否派生
0 agent:<id>:main 主 Agent 始终可以
1 agent:<id>:subagent:<uuid> 子 Agent(编排器) maxSpawnDepth >= 2
2 agent:<id>:subagent:<uuid>:subagent:<uuid> 子子 Agent(工人) 永远不能

8.9.4 命令行控制

/subagents list                    # 查看当前会话的子 Agent
/subagents spawn main 分析日志       # 手动派生一个子 Agent
/subagents kill <id>                # 停止特定子 Agent
/subagents kill all                 # 停止所有子 Agent
/subagents log <id> 50              # 查看子 Agent 日志
/subagents info <id>                # 查看子 Agent 详情
/subagents send <id> 改用新方法     # 向子 Agent 发送消息
/subagents steer <id> 换个方向       # 实时引导子 Agent

8.9.5 工具策略

默认情况下,子 Agent 获得会话工具(sessions_*)——防止子 Agent 派生更多子 Agent 或访问其他会话。

{
  tools: {
    subagents: {
      tools: {
        deny: ["gateway", "cron"],  // 额外禁止 gateway 和 cron
      },
    },
  },
}

maxSpawnDepth >= 2 时,depth-1 的编排器子 Agent 会自动获得 sessions_spawnsubagentssessions_listsessions_history,以便管理其子任务。

8.10 斜杠命令:实时控制

斜杠命令是你在聊天中控制 Agent 的方式。它们分为两类:

8.10.1 指令(Directives)

指令可以嵌入消息中,也可以单独发送。单独发送时会持久化到当前会话。

指令 功能 示例
/think 调整思考深度 /think:high, /t medium
/fast 快速模式 /fast on, /fast off
/verbose 详细日志 /verbose on, /verbose full
/reasoning 显示推理过程 /reasoning on, /reasoning stream
/elevated 提权模式 /elevated on, /elevated full
/exec exec 设置 /exec host=gateway security=allowlist
/model 切换模型 /model opus, /model 3
/queue 队列设置 /queue debounce:2s cap:25

思考深度级别

级别 映射 效果
off 关闭 不使用扩展思考
minimal think 基础思考
low think hard 较深思考
medium think harder 深度思考
high ultrathink 最大预算
xhigh ultrathink+ 超大预算(仅 GPT-5.2/Codex)
adaptive 自适应 由提供商管理(Claude 4.6 默认)

内联 vs 持久化

# 内联:只影响这条消息
帮我分析这段代码 /think:high

# 持久化:影响当前会话的所有后续消息
/think:high
→ Thinking level set to high.

8.10.2 命令(Commands)

命令必须作为独立消息发送:

/status              # 查看当前状态
/tools               # 查看当前可用的工具
/compact             # 手动压缩上下文
/new                 # 新会话
/new sonnet          # 新会话 + 切换模型
/stop                # 停止当前运行
/tts always          # 开启语音回复
/usage tokens        # 显示 Token 用量
/export-session      # 导出当前会话为 HTML
/btw 当前在做什么?   # 临时侧问题,不影响会话上下文

8.10.3 /btw:临时侧问题

/btw 是一个独特的设计——它让 Agent 在不改变主会话上下文的情况下回答一个临时问题:

用户:/btw 我们刚才讨论到了哪里?
Agent:[基于当前会话上下文回答,但不写入历史记录]

这适合在长任务进行中快速获取信息,而不打断 Agent 的工作流。

8.10.4 命令权限控制

{
  commands: {
    native: "auto",        // 原生命令(Discord/Telegram)
    text: true,            // 文本命令解析
    bash: false,           // ! <cmd> 直接执行 Shell(危险)
    config: false,         // /config 修改配置(危险)
    plugins: false,        // /plugins 管理插件(危险)
    debug: false,          // /debug 运行时覆盖(危险)
    allowFrom: {           // 命令权限白名单
      "*": ["admin_user"],
      discord: ["user:123456"],
    },
    useAccessGroups: true, // 使用访问组权限
  },
}

⚠️ 安全建议configbashpluginsdebug 默认都是关闭的,因为它们允许通过聊天直接修改配置或执行命令。只在可信环境中启用。

8.11 TTS(文字转语音)

OpenClaw 支持将回复转换为语音,支持多个提供商:

提供商 API Key 特色
ElevenLabs ELEVENLABS_API_KEY 高质量多语言语音
Microsoft 无需 通过 Edge TTS,免费但无 SLA
OpenAI OPENAI_API_KEY GPT-4o-mini-tts

8.11.1 配置

{
  messages: {
    tts: {
      auto: "inbound",    // off | always | inbound | tagged
      provider: "elevenlabs",
      providers: {
        elevenlabs: {
          voiceId: "pMsXgVXv3BLzUgSXRplE",
          modelId: "eleven_multilingual_v2",
        },
      },
    },
  },
}

auto 模式:

模式 行为
off 不自动转语音
always 所有回复都转语音
inbound 只在收到语音消息后回复语音
tagged 只在回复中包含 [[tts]] 标签时转语音

8.11.2 模型驱动的语音控制

模型可以在回复中嵌入 TTS 指令来动态控制语音参数:

这是正常文本。

[[tts:voiceId=pMsXgVXv3BLzUgSXRplE speed=1.1]]
[[tts:text]](笑声) 再读一遍这首歌。[[/tts:text]]

这允许 Agent 根据上下文选择不同的语气、语速和情感。

8.11.3 运行时控制

/tts status          # 查看当前状态
/tts always          # 所有回复都转语音
/tts inbound        # 只在收到语音后回复语音
/tts provider openai  # 切换提供商
/tts limit 2000      # 设置摘要阈值
/tts summary off     # 关闭长文本自动摘要
/tts audio 你好世界   # 一次性生成语音

8.12 LLM Task:结构化 JSON 输出

llm-task 是一个可选的插件工具,专门用于需要 JSON 结构化输出的场景——比如工作流引擎中的 LLM 步骤。

8.12.1 启用

{
  plugins: {
    entries: {
      "llm-task": { enabled: true },
    },
  },
  tools: {
    allow: ["llm-task"],
  },
}

8.12.2 使用场景

{
  "prompt": "分析这封邮件的意图和情感倾向",
  "input": {
    "subject": "紧急:服务器宕机",
    "body": "我们的生产服务器已经离线 30 分钟了..."
  },
  "schema": {
    "type": "object",
    "properties": {
      "intent": { "type": "string" },
      "sentiment": { "type": "string", "enum": ["urgent", "normal", "low"] },
      "draft_reply": { "type": "string" }
    },
    "required": ["intent", "sentiment", "draft_reply"]
  }
}

返回的 JSON 会自动按照 schema 验证。如果提供了 schema 但输出不符合,工具会返回验证错误。

⚠️ 安全提示llm-task 是 JSON-only 模式——模型只能输出 JSON,不能调用工具。如果需要 LLM 有工具能力,使用子 Agent(sessions_spawn)代替。

8.13 综合实战:构建一个"代码审查助手"

让我们把本章学到的知识综合起来,构建一个实用的代码审查助手。

8.13.1 需求

一个能自动审查 Git 提交的 Agent,当收到新的 Pull Request 时:

  1. 获取变更的代码
  2. 运行测试
  3. 分析代码质量
  4. 输出审查报告

8.13.2 实现

Step 1:创建审查 Skill

~/.openclaw/workspace/skills/code-review/SKILL.md

---
name: code_review
description: 审查 Git 提交或 PR 的代码变更,输出结构化审查报告
metadata:
  {
    "openclaw":
      {
        "requires": { "bins": ["git"] },
      },
  }
---

# 代码审查流程

## 触发条件

当用户要求审查代码、检查 PR 或审查提交时激活。

## 步骤

1. 获取变更范围
   - 如果是 PR:用 `exec` 运行 `gh pr diff <pr-number>`
   - 如果是提交:用 `exec` 运行 `git show <commit-hash>`
   - 如果是当前变更:用 `exec` 运行 `git diff`

2. 运行测试
   - 检测测试框架(查找 package.json / pytest.ini / go.mod)
   - 运行测试:`npm test` / `pytest` / `go test ./...`
   - 如果测试失败,在报告中标记为"阻塞问题"

3. 代码分析
   - 使用 `read` 工具逐文件读取变更内容
   - 检查以下维度:
     a. 安全漏洞(SQL 注入、XSS、硬编码密钥)
     b. 性能问题(N+1 查询、内存泄漏、不必要的循环)
     c. 代码质量(命名、复杂度、重复代码)
     d. 边缘情况处理(空值、错误处理、边界条件)

4. 输出报告
   格式如下:

   ## 审查报告

   **审查范围**:[PR/提交描述]

   ### 测试结果
   - 状态:[通过/失败]
   - 失败详情:[如有]

   ### 发现的问题

   | 严重度 | 文件 | 行号 | 描述 | 建议 |
   |:---:|:---|:---:|:---|:---|
   | 高 | path/to/file.ts | 42 | SQL 注入风险 | 使用参数化查询 |
   | 中 | path/to/file.ts | 78 | 未处理空值 | 添加 null check |

   ### 总结
   - 高优先级问题:N 个
   - 中优先级问题:N 个
   - 低优先级问题:N 个
   - 建议:[通过/需要修改后通过/拒绝]

Step 2:配置工具权限

{
  tools: {
    profile: "coding",
    allow: ["browser"],  // 如果需要查看 PR 网页
  },
  commands: {
    bash: true,  // 允许 ! 命令(在可信环境中)
  },
}

Step 3:使用

你:审查一下最新的提交
Agent:[执行 git log -1 --oneline]
       [执行 git show HEAD]
       [检测到测试框架,运行 pytest]
       [逐文件分析代码]
       [输出审查报告]

8.13.3 进阶:用子 Agent 并行审查

如果审查涉及多个大型文件,可以用子 Agent 并行处理:

用户:审查 PR #123,这个 PR 改了 5 个文件
Agent:[获取 PR diff]
       [识别变更文件:file1.ts, file2.ts, file3.ts, file4.ts, file5.ts]
       [派生 3 个子 Agent 并行审查]
       [等待结果]
       [汇总审查报告]

这需要在配置中启用子 Agent 并设置合理的并发数。

8.14 工具体系的设计哲学

理解了工具体系的实现细节后,我们来看看它背后的设计哲学——这有助于你在实际使用中做出更好的决策。

8.14.1 最小权限原则

OpenClaw 的工具权限设计遵循最小权限原则:

默认状态
├── 工具 profile: full(所有内置工具可用)
├── exec host: sandbox(在容器中执行)
├── exec security: deny(禁止主机执行)
└── 子 Agent: 无会话工具(不能派生更多子 Agent)

收紧权限
├── tools.deny: ["exec"]          → 禁止命令执行
├── tools.profile: "minimal"      → 只有 session_status
├── plugins.deny: [...]           → 禁止特定插件
└── skills.allowBundled: [...]   → 限制可用技能

8.14.2 能力与知识分离

Skill 只提供"知识"(怎么做),不提供"能力"(能做什么)。这保证了:

  • 禁用 exec 工具后,即使 Skill 中写了 运行 git 命令,Agent 也无法执行
  • 禁用 browser 工具后,即使 Skill 中写了 打开网页,Agent 也无法操作

能力由工具层控制,知识由技能层提供,二者解耦。

8.14.3 插件作为所有权边界

OpenClaw 的架构中,插件 = 所有权边界。每个能力(如图片生成)应该先定义接口契约,再由插件实现。这意味着:

  • 切换图片生成提供商不需要改代码——只需要换插件
  • 不同插件可以注册同一个能力(如多个语音提供商)
  • 核心 OpenClaw 只定义契约,不耦合任何具体实现

本章小结

  • OpenClaw 的工具体系是三层架构:工具(能做什么)→ 技能(怎么做)→ 插件(扩展什么)
  • 工具通过 allow/deny/profile 精细控制,deny 优先于 allow
  • exec 工具支持 sandbox/gateway/node 三种执行位置,配合安全审批机制
  • browser 工具支持 isolated(openclaw 档案)和 existing-session(user 档案)两种模式
  • web_search 支持 8 个搜索引擎提供商,自动检测 API Key
  • Skill 是 Markdown 文件,通过环境门控条件加载,是零代码扩展 Agent 能力的最佳方式
  • Plugin 可以注册工具、通道、模型提供商等几乎所有能力,是深度扩展的唯一方式
  • 子 Agent 实现并行任务分派,支持嵌套编排器模式
  • 斜杠命令分为指令(内联/持久化)和命令(独立消息)两类

下一步

Agent 有了"手脚"(工具体系),接下来要让它"多线操作"——这就是多 Agent 路由的范畴。下一章深入 OpenClaw 的多 Agent 架构,从路由策略到委派模式,让你的系统从"单 Agent"进化到"多 Agent 协作"。