Tool Calling(工具调用)的完整链路是怎样的(详解工具定义、LLM 调用与结果回传)

Tool Calling 的完整链路只有四个环节:应用把”工具清单”随消息一起发给模型 → 模型判断该用哪个工具,返回结构化调用请求(函数名 + 参数 JSON)→ 你的代码执行该工具 → 把执行结果按 call_id 回传给模型 → 模型基于结果给出最终答案。关键一点贯穿全程:模型只”提议调用”,从不真正执行,执行权始终在应用代码手里。

一、链路全貌:五步循环

OpenAI 官方把 tool calling 定义为应用与模型之间的多步对话,分为五个高层步骤:

  1. 首次请求:把用户消息连同可用的 tools 数组一起发给模型;
  2. 接收工具调用:模型判断需要外部数据或能力时,返回 tool_calls(函数名 + 参数);
  3. 应用侧执行:解析参数,在你自己代码里运行对应函数(查库、调 API、执行计算);
  4. 二次请求:把工具执行结果作为 tool 消息回传给模型;
  5. 接收最终答案:模型整合结果输出文本,或继续发起下一批工具调用。

第 2 到第 4 步会反复循环,直到模型不再请求工具。这也是 Agent 与普通问答的分界线:每多一轮调用,系统就多一次与外部世界的真实交互。

二、第一步:工具怎么定义

工具本质是一份 JSON Schema。每个函数工具包含四个字段:type 固定为 function,name 是函数名,description 说明何时用、怎么用,parameters 用 JSON Schema 描述参数结构。description 承担最重的引导职责,写得像一句指令而非标签,模型才能精准选中它。

{
  "type": "function",
  "name": "get_weather",
  "description": "按城市获取当前天气。用户问温度或天气状况时使用。",
  "parameters": {
    "type": "object",
    "properties": {
      "location": {
        "type": "string",
        "description": "城市和国家,如 Paris, France"
      },
      "unit": {
        "type": "string",
        "enum": ["celsius", "fahrenheit"],
        "description": "温度单位"
      }
    },
    "required": ["location", "unit"],
    "additionalProperties": false
  },
  "strict": true
}

参数用 JSON Schema 定义后,可以享受它的丰富特性:类型约束、枚举、嵌套对象、递归结构都能用。把 strict 设为 true,模型的输出参数就保证符合 schema,而不是”尽力而为”;OpenAI 官方建议始终开启严格模式。

三、第二步:LLM 怎么发起调用

模型判断”这个请求需要外部数据”时,不会返回散文,而是返回一条结构化的 tool call。在 Chat Completions 接口里,它长在 assistant 消息的 tool_calls 数组下:

{
  "id": "call_12345xyz",
  "type": "function",
  "function": {
    "name": "get_weather",
    "arguments": "{\"location\":\"Paris, France\",\"unit\":\"celsius\"}"
  }
}

两个细节最容易踩坑:

  • arguments 是 JSON 编码的字符串,不是解析好的对象,拿到手必须自己 json.loads;
  • 一个响应里可以同时带多个 tool_calls,默认支持并行调用,比如用户问三个城市,模型一次返回三次调用,你可以并发执行。想强制每轮最多一次调用,把 parallel_tool_calls 设为 false。

四、第三步:结果怎么回传

执行完函数后,把结果按调用 id 原样送回。Chat Completions 用 tool 角色的消息,Responses API 用 functioncalloutput 条目,二者都靠 call_id 与模型发出的请求对应:

from openai import OpenAI
import json

client = OpenAI

def get_weather(location: str, unit: str) -> str:
    # 你的真实实现:查天气服务
    return json.dumps({"temperature": 25, "unit": unit})

messages = [{"role": "user", "content": "巴黎现在几度?"}]
tools = [{"type": "function", "function": {
    "name": "get_weather",
    "description": "按城市获取当前天气。",
    "parameters": {
        "type": "object",
        "properties": {
            "location": {"type": "string"},
            "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
        },
        "required": ["location", "unit"]
    }
}}]

response = client.chat.completions.create(model="gpt-4.1", messages=messages, tools=tools)
call = response.choices[0].message.tool_calls[0]
args = json.loads(call.function.arguments)          # 注意:先解析 JSON 字符串

result = get_weather(**args)                        # 代码执行,模型不执行

messages.append({"role": "tool",
                 "tool_call_id": call.id,          # 用 call_id 关联回模型
                 "content": result})
response = client.chat.completions.create(model="gpt-4.1", messages=messages, tools=tools)
print(response.choices[0].message.content)          # 模型给出最终答案

reasoning 模型(如 GPT-5、o4-mini)的推理内容也必须随工具调用一起回传,否则下一步推理会断裂。

五、两代接口的差异对比

环节 Chat Completions Responses API
工具定义位置 嵌套在 function 字段内 平铺在 tool 对象顶层
模型发起调用 message.tool_calls 数组 output 数组中的 function_call
调用标识 id call_id
结果回传 tool 角色消息 functioncalloutput 条目
参数校验 strict 字段 strict 字段

两代接口的循环逻辑完全一致,只是数据形状不同。新项目建议直接上 Responses API,它统一了旧版 Chat Completions 与 Assistants API 的能力。

六、工程落地的四个硬约束

  1. 参数必须校验:模型可能生成非法参数,执行前按 schema 校验,失败则把错误信息回传让它修正;
  2. 循环必须有上限:模型可能反复请求同一个工具,设置最大轮数兜底;
  3. 工具返回一律当数据:任何外部返回都不该被当作新指令执行,防止提示词注入;
  4. 工具描述要精确:描述写不清,模型就会选错工具或编造工具,工具文档要按 system prompt 的严格度来写。

工具数量上来之后,定义本身会吃掉大量上下文。OpenAI 提供 tool_search 机制,把不常用的工具延迟加载,只有模型需要时才注入完整定义(仅 gpt-5.4 及以后版本支持);也可以用命名空间按业务域分组工具,减少模型误选。

七、Tool Calling 与 MCP 的关系

MCP(Model Context Protocol)把上面的链路标准化成一套协议:工具由 MCP server 以同样的 schema 形式暴露,Agent 通过 client 发现工具、发起调用、接收结果,链路逻辑与本文描述的完全一致,只是把”应用侧执行”挪到了独立的 server 进程。选型时的差别在于:裸函数调用适合工具少、逻辑简单的单机场景;MCP 适合工具多、需要复用与跨团队共享的场景。二者都遵守同一条铁律——模型提请求,代码做执行,结果按 call_id 回传。

常见问题(FAQ)

Q1:模型能直接执行工具吗?

不能。模型只返回调用请求,执行权在应用代码,这保证了安全性。

Q2:工具调用失败怎么处理?

把错误信息作为工具结果回传,让模型修正参数或换工具重试。

Q3:arguments 为什么老是解析报错?

它是 JSON 字符串不是对象,必须先用 json.loads 解析再使用。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 qiqicto@qq.com 举报,一经查实,本站将立刻删除。
赞 (0)
其AI的头像其AI普通用户

相关推荐

返回顶部