Skip to content

第 15 章 工具策略

15.1 工具授权的问题

工具是 Agent 与外界交互的唯一通道。哪些工具可以用、谁能用、在什么场景下用——这些问题不是"全开或全关"的二选一,而是需要精细的分层授权。OpenClaw 用一套**多层策略管道(Policy Pipeline)**解决这个问题,同时在工具实现层提供安全边界。

15.2 工具的六个来源

工具从六个来源汇聚到同一个工具集:

Pi coding tools        → bash, read, write, edit, process, apply_patch, glob
OpenClaw core tools    → message, cron, gateway, canvas, nodes, session_status,
                         tts, image, pdf, web_search, web_fetch, browser
Channel tools          → discord_send/react/..., telegram_send/...,
                         slack_post/..., whatsapp_*
Plugin tools           → 各扩展插件注册的自定义工具
SDK tools              → sessions_send/list/history/spawn,
                         subagents, memory_search, memory_get
Sub-agent tools        → subagents-tool(仅 main session 有)

汇聚后经过策略管道过滤,再经过模型兼容性过滤(不支持 tool calling 的模型移除所有工具),最终形成当次请求可用的工具集。


15.3 工具组(Tool Groups)

文件: src/agents/tool-policy-shared.ts

工具按功能分组,策略中可以直接引用组名:

typescript
const TOOL_GROUPS = {
  all: [...],       core: [...],      messaging: [...],
  channels: [...],  memory: [...],    sessions: [...],
  subagents: [...], browser: [...],   canvas: [...],
  nodes: [...],     cron: [...],      gateway: [...],
};

配置示例:

json
{
  "toolPolicy": {
    "allow": ["core", "memory", "messaging"],
    "deny": ["gateway", "nodes"]
  }
}

插件工具可以通过插件 ID 整体引用:

json
{ "toolPolicy": { "allow": ["core", "plugin:my-discord-bot"] } }

15.4 策略管道(Policy Pipeline)

文件: src/agents/tool-policy-pipeline.ts

默认管道步骤(优先级从低到高)

typescript
buildDefaultToolPolicyPipelineSteps({
  globalPolicy,          // 全局策略(最低优先级)
  globalProviderPolicy,  // 全局 × provider 级
  agentPolicy,           // agent 级
  agentProviderPolicy,   // agent × provider 级
  groupPolicy,           // 群组 session 策略
  profilePolicy,         // auth profile 级(最高优先级)
  providerProfilePolicy, // auth profile × provider 级
});

应用逻辑:

初始:tools = 全量工具集
for each step(低 → 高优先级):
  if allow 存在 → tools = tools ∩ expandGroups(allow)
  if deny 存在  → tools = tools - expandGroups(deny)

高优先级步骤完全覆盖低优先级结论:全局可以开放宽松策略,对特定 auth profile 精准收紧。

管道步骤的完整来源

步骤来源文件说明
Profile Policytool-policy-shared.ts全局 allow/deny 配置
Group Policypi-tools.policy.ts群组 session 限制
Subagent Policypi-tools.policy.ts子 Agent 工具限制
Sandbox Policysandbox-tool-policy.tsDocker 沙箱白名单(见第 12 章)
Owner-Onlytool-policy.ts仅 owner 可用
Message Providerpi-tools.ts渠道特定禁用(voice 禁用 tts)
Model Providerpi-tools.ts模型特定禁用(xAI 禁用 web_search)

策略调试

每个步骤都有 label 字段,出现策略冲突时可追踪到具体来源:

[policy:global]   allow=[core, messaging]
[policy:agent]    deny=[gateway]
[policy:group]    deny=[nodes, canvas]
[policy:profile]  allow=[core]      ← 最终生效:只有 core 工具

15.5 Owner-Only 工具

文件: src/agents/tool-policy.ts

typescript
function applyOwnerOnlyToolPolicy(
  tools: AnyAgentTool[],
  senderIsOwner: boolean
): AnyAgentTool[];

senderIsOwner = false 时(Discord 群里的非 owner 用户),owner-only 工具自动从工具集移除:

  • gateway(修改 OpenClaw 配置、重启服务)
  • 高权限 execelevated: true
  • 某些 node 管理工具(device 配对、远程执行)

15.6 核心工具详解

Bash 工具(最复杂)

Bash 工具需要在两种环境执行:宿主机和 Docker 沙箱。

bash-tools.ts                     # 工具定义入口
bash-tools.exec.ts                # 执行核心
bash-tools.exec-host-gateway.ts   # Gateway 宿主机执行
bash-tools.exec-host-node.ts      # 设备节点远程执行
bash-tools.exec-host-shared.ts    # 共享执行逻辑
bash-tools.exec-runtime.ts        # 运行时环境设置
bash-tools.process.ts             # process 工具(进程管理)
bash-process-registry.ts          # 进程注册表

执行审批bash-tools.exec-approval-request.ts):高风险命令可配置需要人工确认,审批请求通过 Gateway WS 推送到 macOS app 或 Control UI。

进程注册表:追踪所有由 bash 工具启动的子进程,session abort 或运行结束时统一清理。

Message 工具

typescript
// 支持跨渠道发送:Agent 在 Telegram 运行,但可发消息到 Discord
{
  action: "send",
  channel: "discord",
  to: "#general",
  message: "任务完成!",
  buttons: [[{ text: "查看详情", url: "https://..." }]]
}

支持:跨渠道发送、行内按钮、文件附件、消息轮询创建、消息反应。

Web 工具集

tools/web-search.ts            # 网页搜索
tools/web-fetch.ts             # 获取网页内容
tools/web-guarded-fetch.ts     # 安全 fetch(SSRF 防护)
tools/web-fetch-visibility.ts  # 内容可见性过滤

web-guarded-fetch.ts 防止 SSRF 攻击,拒绝对内网地址(127.0.0.1、10.x、192.168.x)的请求。

Session 工具集

tools/sessions-send-tool.ts    # 跨 session 发消息
tools/sessions-spawn-tool.ts   # 派生新 session
tools/sessions-list-tool.ts    # 列出活跃 sessions
tools/sessions-history-tool.ts # 获取 session 历史
tools/sessions-access.ts       # 访问控制

Session 工具是多 Agent 协作的基础——父 Agent 可以查看子 Agent 的历史,或向另一个 session 发送消息。

Browser 工具

tools/browser-tool.ts          # 浏览器工具主逻辑
tools/browser-tool.actions.ts  # 动作(点击、输入、截图、滚动)
tools/browser-tool.schema.ts   # 动作 schema

通过 CDP 协议控制 OpenClaw 管理的 Chrome/Chromium 实例。支持:导航、点击、输入、截图、页面快照、文件上传。


15.7 工具安全机制

Before Tool Call Hook

typescript
wrapToolWithBeforeToolCallHook(tool, {
  hookRunner, sessionKey, agentId,
  onBlock: () => { /* 记录被阻止的调用 */ }
});

插件通过 before_tool_call hook 可以在工具执行前拦截特定调用。

Tool Result Guard

session-tool-result-guard.ts 检查工具返回结果:

  • 是否包含敏感信息(API key、密码)
  • 结果大小是否超限
  • 是否包含可能的 prompt injection 内容

Loop Detection

json
{
  "tools": {
    "loopDetection": {
      "enabled": true,
      "maxConsecutive": 5,
      "windowSize": 10
    }
  }
}

tool-loop-detection.ts 检测 Agent 是否陷入无意义的重复调用(比如反复调用同一工具无进展)。

File System Policy

typescript
createToolFsPolicy({
  workspaceRoot: "/home/user/workspace",
  workspaceOnly: true,  // 限制 read/write/edit 在 workspace 内
});

15.8 工具循环检测(Tool Loop Detection)

文件: src/agents/tool-loop-detection.ts

Agent 进入工具调用循环是真实存在的失控场景:反复执行相同的 exec 命令却没有进展,或在两个工具之间乒乓调用,永远无法产生最终回复。工具循环检测系统在每次工具调用前检查历史,发现异常时介入。

四种检测器

typescript
type LoopDetectorKind =
  | "generic_repeat"          // 相同 tool+params 重复调用 N 次
  | "known_poll_no_progress"  // 轮询类工具(如 process poll)调用无进展
  | "global_circuit_breaker"  // 全局熔断:任意工具调用总次数过高
  | "ping_pong";              // A 调 B、B 调 A 的双工具乒乓模式

阈值常量

typescript
const TOOL_CALL_HISTORY_SIZE = 30;   // 滑动窗口大小
const WARNING_THRESHOLD      = 10;   // 触发 warning 级别
const CRITICAL_THRESHOLD     = 20;   // 触发 critical 级别(阻断)
const GLOBAL_CIRCUIT_BREAKER_THRESHOLD = 30; // 全局熔断

检测结果分两级:

  • warning:记录日志,向 Agent 注入提示,不阻断执行
  • critical:终止当前工具调用,强制 Agent 退出中循环

工作流程

工具调用请求

recordToolCall()  ← 写入滑动窗口(最近 30 次)

detectToolCallLoop()

  stuck=false → 正常执行
  stuck=true, warning → 注入提示,继续执行
  stuck=true, critical → 返回错误,中止本次工具调用

recordToolCallOutcome()  ← 记录结果(用于 no_progress 检测)

hashToolCall 用工具名 + 参数的确定性 JSON digest 生成指纹,相同参数重复调用才会触发 generic_repeat;参数略有不同则不计入同一模式。

配置

json
{
  "agents": {
    "defaults": {
      "toolPolicy": {
        "loopDetection": {
          "enabled": true,
          "warningThreshold": 8,
          "criticalThreshold": 15,
          "globalCircuitBreakerThreshold": 25
        }
      }
    }
  }
}

默认关闭enabled: false),需显式开启。


15.9 工具 Schema 兼容性

不同 LLM 对工具 schema 要求不同:

Provider处理文件说明
Google Geminipi-tools.schema.ts移除 Gemini 不支持的 schema 特性
xAIschema/clean-for-xai.ts避免与 xAI 自带 web_search 名称冲突
Claude Code Assisttool-call-id.ts特殊的 tool call ID 清洗
OpenAIpi-tools.ts降级推理标签对

15.10 本章要点

  • 工具来自六个来源,经过多层策略管道 + 模型兼容性双重过滤
  • 策略管道是覆盖式的,高优先级策略完全替代低优先级结论
  • Owner-only 工具在非 owner 场景自动移除
  • Bash 工具区分宿主 / 沙箱执行,支持高风险命令的人工审批
  • Web 工具有 SSRF 防护,Session 工具支持多 Agent 协作
  • 循环检测 + 结果守卫防止 Agent 行为失控

推荐阅读的源文件

文件优先级说明
src/agents/pi-tools.ts★★★工具集构建入口
src/agents/tool-policy-pipeline.ts★★★策略管道实现
src/agents/tool-policy-shared.ts★★★工具组定义
src/agents/tool-policy.ts★★Owner-only 策略
src/agents/bash-tools.ts★★Bash 工具入口
src/agents/tools/web-guarded-fetch.ts★★SSRF 防护
src/agents/tool-loop-detection.ts循环检测

基于 MIT 协议发布