工具设计原则

返回 AI Agent

工具(Tool)是 Agent 与外部世界交互的唯一接口。工具设计的质量直接决定 Agent 能否正确调用——描述不清会让模型猜错参数,职责模糊会导致调用失败或副作用难以追踪。


核心原则

原则说明
单一职责每个工具只做一件事,避免”万能工具”
描述即契约description 要说清楚:做什么、何时用、边界是什么
参数最小化只暴露必要参数,可选参数给合理默认值
幂等优先读操作天然幂等;写操作设计成可重试(同一请求多次调用结果一致)
错误语义明确失败时返回结构化错误,而不是抛出未捕获异常或返回空值
权限最小化工具只拥有完成其职责所需的最低权限

工具 Schema 规范

{
  "name": "search_web",
  "description": "搜索互联网获取最新信息。适用于需要实时数据、近期事件或模型训练截止日期之后的内容。不适用于已知的、静态的知识。",
  "parameters": {
    "type": "object",
    "properties": {
      "query": {
        "type": "string",
        "description": "搜索关键词,使用自然语言,不超过 100 字"
      },
      "max_results": {
        "type": "integer",
        "description": "返回结果数量,默认 5,最大 20",
        "default": 5
      }
    },
    "required": ["query"]
  }
}

描述的黄金公式[动词] + [对象] + [适用场景] + [不适用场景(可选)]


常见设计错误

❌ 描述太短

{ "name": "run_code", "description": "运行代码" }

模型不知道:什么语言?有副作用吗?能访问文件系统吗?

✅ 描述充分

{
  "name": "run_python",
  "description": "在沙箱环境中执行 Python 代码并返回 stdout/stderr。可访问预装库(pandas、numpy、matplotlib)。无网络访问,无文件持久化,执行超时 30 秒。适合数据处理、计算、绘图。"
}

❌ 参数过于宽泛

{ "action": "string 任意操作" }

✅ 使用枚举约束

{
  "action": {
    "type": "string",
    "enum": ["read", "write", "delete"],
    "description": "操作类型:read 只读,write 创建或覆盖,delete 永久删除"
  }
}

返回值设计

# 统一返回结构
@dataclass
class ToolResult:
    success: bool
    data: Any          # 成功时的结果
    error: str | None  # 失败时的原因(模型可读)
    metadata: dict     # 可选:执行时长、来源等
 
# 示例:搜索工具返回
{
  "success": True,
  "data": [
    {"title": "...", "url": "...", "snippet": "..."}
  ],
  "error": None,
  "metadata": {"query_time_ms": 312}
}

危险工具分级

级别示例要求
🟢 安全读文件、搜索、查天气直接执行
🟡 敏感发邮件、写数据库、调第三方 API日志记录 + 限速
🔴 危险删数据、执行系统命令、转账人工确认(Human-in-the-loop)
# 危险操作强制人工确认
def delete_file(path: str) -> ToolResult:
    if not require_human_approval(f"确认删除 {path}?"):
        return ToolResult(success=False, error="用户取消操作", data=None)
    ...

工具测试清单

  • 参数全部合法时能正确执行
  • 参数缺失/类型错误时返回清晰的错误信息
  • 权限不足时拒绝并说明原因
  • 超时或外部服务故障时能优雅降级
  • 多次调用(幂等性)结果一致
  • 返回的错误信息模型能理解并据此重试

相关文档