🔧 OpenClaw Agent工具调用指南

AI Agent如何优雅地调用工具?这篇文章告诉你答案

什么是Agent工具调用?

想象一下,你是一个只会说话的AI,突然有人问你"北京现在天气怎么样?"——你无法访问实时数据,只能尴尬地说"我不知道"。但如果给你一个"天气查询工具",你就能瞬间回答。这就是工具调用(Tool Calling)的魔力。

在OpenClaw中,工具调用是Agent与外部世界交互的核心机制。它让AI从"只会说"进化成"会做事"——查询数据库、调用API、执行代码、读写文件,无所不能。

💡 核心概念:工具调用本质上是Agent与LLM之间的"契约"——Agent声明工具的能力,LLM决定何时调用、传什么参数,然后Agent执行并将结果返回给LLM。

工具调用的工作流程

OpenClaw的工具调用遵循一个优雅的循环:

  1. 工具注册 - Agent声明可用工具及其参数schema
  2. 意图识别 - LLM分析用户请求,判断是否需要调用工具
  3. 参数构建 - LLM生成符合schema的参数JSON
  4. 工具执行 - Agent执行工具并获取结果
  5. 结果整合 - LLM将工具结果融入最终回复

流程图解

用户请求 → LLM分析 → 需要工具?
                           ↓是
                     生成工具调用参数
                           ↓
                     Agent执行工具
                           ↓
                     返回结果给LLM
                           ↓
                     LLM生成最终回复 → 返回用户

OpenClaw工具调用实战

1. 定义工具Schema

{
  "tools": [
    {
      "name": "get_weather",
      "description": "查询指定城市的当前天气",
      "parameters": {
        "type": "object",
        "properties": {
          "city": {
            "type": "string",
            "description": "城市名称,如:北京、上海"
          },
          "unit": {
            "type": "string",
            "enum": ["celsius", "fahrenheit"],
            "description": "温度单位,默认celsius"
          }
        },
        "required": ["city"]
      }
    }
  ]
}

2. 在Agent中注册工具

// OpenClaw工具定义示例
const weatherTool = {
  name: "get_weather",
  description: "查询指定城市的当前天气",
  parameters: {
    type: "object",
    properties: {
      city: { type: "string", description: "城市名称" },
      unit: { type: "string", enum: ["celsius", "fahrenheit"] }
    },
    required: ["city"]
  },
  handler: async (params: { city: string; unit?: string }) => {
    // 调用天气API
    const response = await fetch(
      `https://api.weather.com/current?city=${params.city}`
    );
    return response.json();
  }
};

// 注册到Agent
agent.registerTool(weatherTool);

3. 处理工具调用响应

// LLM返回的工具调用
const toolCall = {
  id: "call_abc123",
  name: "get_weather",
  arguments: '{"city": "北京", "unit": "celsius"}'
};

// Agent执行工具
const result = await agent.executeToolCall(toolCall);

// 将结果返回给LLM
const messages = [
  { role: "user", content: "北京天气怎么样?" },
  { role: "assistant", toolCalls: [toolCall] },
  { role: "tool", toolCallId: "call_abc123", content: JSON.stringify(result) }
];

最佳实践

1. 工具描述要精准

好的工具描述能让LLM准确判断何时调用:

✅ 好的描述:"查询指定城市的当前天气,返回温度、湿度、风速等信息"
⚠️ 差的描述:"获取天气信息"(太模糊,LLM可能误用)

2. 参数校验要严格

永远不要信任LLM生成的参数:

handler: async (params) => {
  // 参数校验
  if (!params.city || typeof params.city !== 'string') {
    throw new Error("city参数必须是字符串");
  }
  
  // 类型转换与边界检查
  const city = params.city.trim().slice(0, 50);
  
  // 执行工具逻辑
  return await fetchWeather(city);
}

3. 错误处理要优雅

工具执行失败时,返回清晰的错误信息给LLM:

handler: async (params) => {
  try {
    return await fetchData(params);
  } catch (error) {
    return {
      error: true,
      message: `查询失败: ${error.message}`,
      suggestion: "请检查参数是否正确,或稍后重试"
    };
  }
}

4. 避免工具调用循环

设置最大调用次数防止无限循环:

const MAX_TOOL_CALLS = 5;
let callCount = 0;

while (response.toolCalls && callCount < MAX_TOOL_CALLS) {
  const results = await executeToolCalls(response.toolCalls);
  response = await llm.chat(messages, results);
  callCount++;
}

高级技巧

并行工具调用

当多个工具调用相互独立时,可以并行执行:

const toolCalls = response.toolCalls;

// 并行执行所有工具
const results = await Promise.all(
  toolCalls.map(call => executeTool(call))
);

工具链式调用

某些场景需要前一个工具的输出作为后一个工具的输入:

// 先查询用户ID,再获取用户详情
const userId = await agent.callTool("get_user_id", { name: "张三" });
const userDetails = await agent.callTool("get_user_details", { id: userId });
💡 建议:对于复杂的链式调用,考虑使用OpenClaw的Workflow功能,它提供了更清晰的状态管理和错误处理。

常见问题

Q: 工具调用和函数调用有什么区别?

在OpenClaw中,这两个概念基本等价。不过"工具"更强调Agent层面,"函数"更偏向代码层面。

Q: 一个Agent可以注册多少个工具?

理论上没有限制,但建议控制在10-20个以内,太多会让LLM难以选择正确的工具。

Q: 工具调用会增加多少延迟?

取决于工具本身的执行时间。建议对每个工具设置超时,避免长时间等待。

📅 最后更新:2026年5月2日 | 作者:妙趣AI