Agent开发-手写一个工具

4 阅读3分钟

任务:手动跑通一次工具调用(不写循环)

实现步骤:

  1. 第一次请求:把用户请求和工具 schema 传给大模型
  2. 工具决策:模型发现需要查数据,返回 tool_calls (包含函数名和参数JSON)
  3. 本地执行:本地执行函数解析参数
  4. 第二次请求:把模型之前的回复,加上本地调用工具的结果 role: “tool”,一起追加到上下文再次发送给模型
  5. 模型回答:模型结合工具的执行结果,返回自然回答

定义工具

工具是一个数组结构,里面可以写很多的工具,模型自行选择。

const tools: OpenAI.ChatCompletionTool[] = [
  {
    type: "function",  // 工具类型, 各个大模型平台可能还有自己的工具库, 例如web_search
    function: {
      name: "get_current_weather", // 名称
      description: "获取指定城市的天气", // 工具描述,模型真正识别的是这个描述
      parameters: { // 参数
        type: "object", // 参数类型
        properties: { // 参数里面的属性
          location: { // 第一个参数名称
            // 这里面包含的是参数的数据结构信息
            type: "string", // 数据类型
            description: "城市名,例如:深圳" // 参数描述
          }
        },
        required: ["location"] // 是否非必填的
      },
    }
  }
];

查看模型返回结果

我们在请求的时候加上了一个 tool 参数,然后大模型就返回一个 tool_calls 状态,告知要调用工具才能获取天气,然后就发现我们的工具里面有获取天气的工具,需要什么参数等,返回给了我们,然后我们就带上返回的参数继续请求大模型。

"id": "071d286ce2e2bd033e39e18d570555bc",
"choices": [
{
  "finish_reason": "tool_calls",
  "index": 0,
  "message": {
    "content": "<think>\n用户询问深圳的天气,我需要调用天气查询工具来获取深圳的天气信息。\n</think>\n\n\n",
    "role": "assistant",
    "name": "MiniMax AI",
    "tool_calls": [
      {
        "id": "call_function_be0bgje7nnv6_1",
        "type": "function",
        "function": {
          "name": "get_current_weather",
          "arguments": "{\"location\": \"深圳\"}"
        },
        "index": 0
      }
    ],
    "audio_content": ""
  }
}
],
"created": 1791882604,
"model": "MiniMax-M2.7-highspeed",
"object": "chat.completion",
"usage": {
    "total_tokens": 230,
    "total_characters": 0,
    "prompt_tokens": 183,
    "completion_tokens": 47
},
"input_sensitive": false,
"output_sensitive": false,
"input_sensitive_type": 0,
"output_sensitive_type": 0,
"output_sensitive_int": 0,
"base_resp": {
    "status_code": 0,
    "status_msg": ""
}

组装数据回填上下文继续请求

既然是查询工具,我们将结果和参数继续返回给大模型,大模型匹配上了参数,和对话id就会把查询的结果返回给我们。

const func = JSON.parse(toolCall.function.arguments);

const resultWeather = {
    ...func,
    condition: "晴天",
}

messages.push({
    role: "tool",
    tool_call_id: toolCall.id,
    content: JSON.stringify(resultWeather)
})

const secondResponse = await client.chat.completions.create({
    model: MODEL,
    messages,
    tools,
})

最终回答

"id": "071d286fa92a68a921a87db6ebe59886",
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "message": {
        "content": "<think>\n天气查询返回了结果:深圳目前是晴天。我来简洁地回复用户。\n</think>\n\n深圳今天天气是**晴天** ☀️",
        "role": "assistant",
        "name": "MiniMax AI",
        "audio_content": ""
      }
    }
  ],
  "created": 1791882607,
  "model": "MiniMax-M2.7-highspeed",
  "object": "chat.completion",
  "usage": {
    "total_tokens": 285,
    "total_characters": 0,
    "prompt_tokens": 255,
    "completion_tokens": 30
  },
  "input_sensitive": false,
  "output_sensitive": false,
  "input_sensitive_type": 0,
  "output_sensitive_type": 0,
  "output_sensitive_int": 0,
  "base_resp": {
    "status_code": 0,
    "status_msg": ""
  }