# Tool Use Patterns

> 【工具调用模式】为 AI Agent 设计健壮的工具集成方案。触发时机：用户说"tool use"、"工具调用"、"function calling"、"工具集成"时。

- Skill: `afine907/tool-use-patterns` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add afine907/tool-use-patterns`
- Raw SKILL.md: https://api.skillmd.com/api/skills/afine907/tool-use-patterns/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: afine907 (https://skillmd.com/u/afine907)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/afine907/tool-use-patterns

---


# Tool Use Patterns — Agent 防御性工具集成

为 AI Agent 设计健壮的工具调用方案，防止生产环境中最常见的 Agent 失败模式。

> **核心洞察：** 工具误用是生产中最常见的 Agent 特定失败模式——也是最阴险的：第 2 步的一个畸形参数静默地腐化了后续每一步。


## Goal

为 AI Agent 设计健壮的工具集成方案。覆盖防御性 Schema 设计、重试/降级策略、输出解析验证、工具组合编排

## Trigger

- 用户说"tool use"、"工具调用"、"function calling"、"工具集成"
  - 构建需要调用外部工具/API 的 Agent
  - 调试 Agent 中的工具调用失败
  - 设计 Agent 系统的工具 Schema

## 工作流程

```
审计工具面 → 设计 Schema → 实现防御包装 → 添加监控 → 测试失败模式
```

## Step 1: 工具面审计

盘点 Agent 可调用的所有工具，按风险分级：

| 风险等级 | 定义 | 示例 | 处理方式 |
|---------|------|------|---------|
| **只读** | 不修改任何状态 | 搜索、读文件、查询数据库 | 自动执行 |
| **可逆写入** | 修改状态但可回滚 | 创建分支、写临时文件 | 确认后执行 |
| **不可逆写入** | 修改状态且无法回滚 | 发送邮件、删除数据、发布内容 | 显式审批 |
| **危险** | 可能造成安全问题 | 执行代码、修改权限、访问密钥 | 默认拒绝 |

对每个工具记录：
- 工具名称和功能描述
- 输入参数列表（类型、必填/可选、约束条件）
- 返回值格式
- 失败模式（超时、限流、参数错误、服务不可用）
- 副作用（是否修改状态、是否可逆）

> 详细失败模式目录见 [references/failure-modes.md](references/failure-modes.md)

## Step 2: 防御性 Schema 设计

工具参数 Schema 是 Agent 和工具之间的契约。设计不良的 Schema 是工具误用的根本原因。

### Schema 设计原则

1. **严格类型** — 用 enum 约束可选值，用 format 约束格式，不留模糊空间
2. **必填/可选分离** — 必填参数必须在 `required` 数组中声明
3. **默认值** — 所有可选参数提供合理默认值
4. **描述即文档** — description 字段要告诉 LLM 何时用、怎么用、什么格式

### Schema 模板

```json
{
  "name": "tool_name",
  "description": "做什么 + 返回什么 + 什么时候用。不要模糊描述如'获取数据'。",
  "parameters": {
    "type": "object",
    "properties": {
      "param_name": {
        "type": "string",
        "enum": ["option_a", "option_b"],
        "description": "参数含义 + 格式约束 + 示例值"
      }
    },
    "required": ["param_name"],
    "additionalProperties": false
  }
}
```

> 详细 Schema 模板见 [references/schema-templates.md](references/schema-templates.md)

## Step 3: 重试与降级策略

工具调用失败不是异常，是常态。需要在代码层面（非提示层面）实现防御。

### 错误分类与响应

| 错误类型 | 特征 | 响应策略 |
|---------|------|---------|
| **瞬时故障** | 超时、5xx、限流 | 指数退避重试（最多 3 次） |
| **参数错误** | 4xx、验证失败 | 将错误信息返回 LLM，让它修正参数重试 |
| **工具不可用** | 连接拒绝、服务下线 | 切换备用工具或优雅降级 |
| **输出异常** | 格式不符、数据缺失 | 解析错误 + 请求澄清或换方案 |

### 断路器模式

在代码层面实现，不要依赖提示中的"不要循环超过 N 次"：

```
连续失败 3 次 → 打开断路器 → 暂停调用 30 秒 → 半开状态试探 → 成功则关闭
```

关键规则：
- 断路器在工具调度层实现，不在提示层
- 工具失败时返回结构化错误给 LLM（`{ success: false, error: "..." }`），永远不要静默吞掉错误
- 永远不要返回空结果让 LLM 以为成功了
- 幂等性键：对有副作用的工具，每次调用携带唯一 ID，防止重试导致重复执行

> 详细组合模式见 [references/composition-patterns.md](references/composition-patterns.md)

## Step 4: 输出解析与验证

工具返回值是 LLM 后续推理的基础。畸形输出会级联腐化所有后续步骤。

### 防御性解析

1. **Schema 验证** — 用 Pydantic/Zod 验证输出结构，不信任自由格式
2. **部分响应处理** — 工具返回部分数据时，标记缺失字段而非猜测
3. **异常检测** — 工具返回空数组、null、意外格式时，报告而非忽略
4. **工具幻觉检测** — Agent 可能伪造工具输出（声称调用了工具但实际没有），通过验证调用记录来检测

### 错误返回格式

工具执行失败时，返回结构化错误而非崩溃：

```python
# 正确：结构化错误，LLM 可以据此决策
return {"success": False, "error": "参数格式错误：report_id 应为 RPT-XXXX 格式", "retryable": False}

# 正确：可重试错误
return {"success": False, "error": "服务暂时不可用 (HTTP 503)", "retryable": True}

# 错误：静默返回空结果
return None  # LLM 以为成功了，继续在错误基础上推理

# 错误：抛出异常让框架捕获
raise ValueError("bad input")  # 错误信息不够具体，LLM 无法恢复
```

## Step 5: 工具组合模式

单工具调用很少能满足复杂任务。多工具编排有四种基本模式：

### 顺序流水线
```
A → B → C（串行，每步依赖前一步的输出）
```
适用：数据获取 → 处理 → 存储

### 并行扇出
```
A + B → 合并结果（同时执行，无依赖）
```
适用：多数据源聚合、并行搜索

### 条件分支
```
A 成功 → B；A 失败 → C（根据结果选择路径）
```
适用：有降级方案的工具调用

### 补偿回滚（Saga 模式）
```
A → B → C 失败 → 补偿 B → 补偿 A
```
适用：多步写入操作，需要在失败时恢复状态

**编排规则：**
- 每个编排步骤记录执行结果到 Ledger（复用 task-loom 模式）
- 总步骤数设置硬上限（代码级，非提示级）
- 每步注册补偿动作后再执行（Saga 模式）

## Step 6: 测试工具集成

工具集成测试需要覆盖正常路径和失败路径。

### 测试矩阵

| 测试类型 | 方法 | 覆盖点 |
|---------|------|--------|
| **Mock 测试** | 模拟工具响应 | 参数验证、输出解析、错误处理 |
| **故障注入** | 模拟超时、5xx、空响应 | 重试逻辑、断路器、降级策略 |
| **集成测试** | 真实工具 + 沙箱环境 | 端到端流程、实际延迟、真实错误 |
| **属性测试** | 随机输入生成 | 边界条件、Schema 鲁棒性 |

### 必测场景

- [ ] 工具正常返回 → 参数正确传递、输出正确解析
- [ ] 工具超时 → 重试后成功
- [ ] 工具持续失败 → 断路器触发、优雅降级
- [ ] 参数格式错误 → LLM 收到错误信息并修正
- [ ] 工具返回异常格式 → 解析不崩溃、标记异常
- [ ] 并发工具调用 → 无竞态条件
- [ ] 幂等性验证 → 重试不产生重复副作用

> 完整测试清单见 [references/testing-checklist.md](references/testing-checklist.md)

## 快速使用

```
用户：我正在构建一个能调用 GitHub API 的 Agent，但工具调用经常失败
助手：使用 /tool-use-patterns 审计工具面、设计防御性 Schema、实现断路器
```

## 边界情况

- **工具数量超过 25 个** — Anthropic 工程博客指出，超过 25 个工具后 Agent 可靠性显著下降。使用检索或分层策略筛选当前步骤的可用工具
- **工具 Schema 漂移** — 第三方 API 更新响应格式时，Agent 无法感知。需要在工具包装层做版本校验
- **工具返回超大响应** — 截断到合理长度，避免撑爆上下文窗口
- **多 Agent 共享工具** — 每个 Agent 应有独立的工具权限范围，避免权限堆叠

## 安全检查

- 所有工具输入在执行前做 Schema 验证（LLM 生成的参数是不可信输入）
- 有副作用的工具必须接受幂等性键
- 文件操作类工具做路径沙箱检查（`Path.resolve()` 验证）
- 不要让工具异常冒泡到 Agent 层（捕获后返回结构化错误）

