Skip to content

02 · 工具调用 ​

🎯 难度:初级⏱ 预计:60 分钟# Function Calling# JSON Schema

核心事实:模型请求调用工具,应用执行工具。工具名、描述、参数 Schema 是给模型看的菜单。

定义工具菜单 ​

先看一个模拟天气工具,不连接真实天气接口:

python
from pydantic import BaseModel, Field

class WeatherArgs(BaseModel):
    city: str = Field(min_length=1, max_length=40, description="城市名称")

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "查询演示天气数据,不代表实时天气。支持北京、上海。",
        "parameters": WeatherArgs.model_json_schema(),
    },
}]

required、properties 等 JSON Schema 细节由 Pydantic 生成。工具描述应该说明什么时候用、返回什么、哪些限制。

模型返回的不是调用结果 ​

把 tools 与 messages 一起传给 client.chat.completions.create(),模型可能返回:

json
{
  "role": "assistant",
  "tool_calls": [{
    "id": "call_example",
    "type": "function",
    "function": {
      "name": "get_weather",
      "arguments": "{\"city\":\"北京\"}"
    }
  }]
}

注意 arguments 是 JSON 字符串。应用解析、校验、执行后,再返回:

json
{
  "role": "tool",
  "tool_call_id": "call_example",
  "content": "{\"city\":\"北京\",\"temp_c\":22,\"demo\":true}"
}

必须保留 tool_call_id 对应关系。模型一轮可能请求多个工具,每个调用都需要一个对应结果,然后才能继续请求模型。

交互看看消息如何变化 ​

🔬 messages 数组演变器1 / 6
STEP 1 程序启动,先放入 system 消息,告诉模型它是谁、能做什么。
system你是一个乐于助人的助手,可以使用工具。

上面的 UI 是协议概念演示,不是可以直接发到 API 的完整 JSON。真实数组需要每个调用的 ID、type、function;下面手写 Agent 章节会完整保存 SDK 返回对象。

tool_choice ​

  • auto:模型自行决定是否调用。
  • none:本轮不允许工具调用。
  • 指定函数:强制调用某个工具,具体能力与格式以平台文档为准。

仅仅传入工具,不保证模型一定会用。描述差、任务不匹配、平台不支持,都可能导致没有调用。

安全执行的四道门 ​

  1. 工具名在程序白名单中。
  2. 参数通过 Pydantic 校验,限制长度、范围和额外字段。
  3. 程序验证权限和资源范围,例如文件只能来自指定练习目录。
  4. 可能产生外部影响的动作,执行前明确向用户展示并确认。

不要用 eval / exec 调工具

eval(arguments) 或 eval(function_name) 会把模型输出变成任意代码执行。用 JSON 解析 + 固定工具注册表。能运行 shell 的工具更需要独立沙箱,不能仅靠 Prompt 说「不要危险操作」。

练习 ​

给天气工具加一个 unit 参数,只允许 celsius / fahrenheit。想一想:这是在 Schema 中提示模型就够了,还是执行时也要验证?

答案:两边都要,Schema 帮模型选择正确参数,程序校验保护执行。

用心写给每一个想入门 Agent 开发的前端工程师