Skip to content

函数调用(Tool Use / Function Calling)

让模型自己决定调什么工具 + 生成参数。GPT 叫 "function calling",Claude 叫 "tool use",本质同一回事。

协议差异速览

Provider协议字段名
OpenAI 系列/v1/chat/completionstools + tool_choice
Claude 系列/v1/messagestools + tool_choice

OpenAI 协议

POST https://shuro.vip/v1/chat/completions

请求示例

json
{
  "model": "gpt-5.5",
  "messages": [
    {
      "role": "user",
      "content": "北京今天天气怎么样?"
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_current_weather",
        "description": "获取指定城市的当前天气",
        "parameters": {
          "type": "object",
          "properties": {
            "location": {
              "type": "string",
              "description": "城市名称,如:北京、上海"
            },
            "unit": {
              "type": "string",
              "enum": ["celsius", "fahrenheit"]
            }
          },
          "required": ["location"]
        }
      }
    }
  ],
  "tool_choice": "auto"
}

响应示例

json
{
  "id": "chatcmpl-DZwB90CSso7968zxe9srYK4PGt80N",
  "object": "chat.completion",
  "created": 1777457491,
  "model": "gpt-5.5",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "call_er37krPTyuvOffIpsFRGrqji",
            "type": "function",
            "function": {
              "name": "get_current_weather",
              "arguments": "{\"location\":\"北京\",\"unit\":\"celsius\"}"
            }
          }
        ],
        "refusal": null
      },
      "logprobs": null,
      "finish_reason": "tool_calls"
    }
  ],
  "usage": {
    "prompt_tokens": 72,
    "completion_tokens": 21,
    "total_tokens": 93
  }
}

注意:

  • contentnull(模型选择调用 tool 而非直接回答)
  • tool_calls[].function.arguments字符串化的 JSON(要 JSON.parse
  • finish_reasontool_calls

tool_choice 取值

含义
"auto"模型自己决定调不调(默认)
"none"强制不调 tool
"required"强制至少调一个
{"type": "function", "function": {"name": "xxx"}}强制调指定 tool

gpt-5.5 多了 reasoning_content

json
{
  "message": {
    "role": "assistant",
    "content": null,
    "reasoning_content": null,         新字段
    "tool_calls": [...]
  }
}

GPT-5 系列在 tool call 前可能输出思考链放在 reasoning_content

Claude 原生 Messages 协议

POST https://shuro.vip/v1/messages

请求示例

json
{
  "model": "claude-opus-4-7",
  "max_tokens": 2048,
  "tools": [
    {
      "name": "get_current_weather",
      "description": "获取指定城市的当前天气",
      "input_schema": {
        "type": "object",
        "properties": {
          "location": {
            "type": "string",
            "description": "城市名称"
          },
          "unit": {
            "type": "string",
            "enum": ["celsius", "fahrenheit"]
          }
        },
        "required": ["location"]
      }
    }
  ],
  "messages": [
    {"role": "user", "content": "北京今天天气怎么样?"}
  ]
}

Claude vs OpenAI 字段差异

OpenAIClaude
tools[].function.nametools[].name
tools[].function.parameterstools[].input_schema
tool_calls[].function.arguments(字符串)content[].input对象,不是字符串)

Claude 响应示例

json
{
  "id": "msg_xxx",
  "model": "claude-opus-4-7",
  "stop_reason": "tool_use",
  "content": [
    {"type": "text", "text": "我帮你查天气。"},
    {
      "type": "tool_use",
      "id": "toolu_xxx",
      "name": "get_current_weather",
      "input": {
        "location": "北京",
        "unit": "celsius"
      }
    }
  ]
}

Claude 的 input已解析的对象,不用再 JSON.parse

多轮调用(Tool 结果反馈)

模型调用 tool → 你执行 → 把结果发回给模型 → 模型继续推理。

OpenAI 多轮

json
{
  "model": "gpt-5.5",
  "messages": [
    {"role": "user", "content": "北京天气?"},
    {
      "role": "assistant",
      "content": null,
      "tool_calls": [{
        "id": "call_xxx",
        "type": "function",
        "function": {"name": "get_current_weather", "arguments": "{\"location\":\"北京\"}"}
      }]
    },
    {
      "role": "tool",
      "tool_call_id": "call_xxx",
      "content": "{\"temp\":18,\"description\":\"\"}"
    }
  ],
  "tools": [...]
}

模型基于 tool 结果继续生成自然语言回答。

Claude 多轮

json
{
  "model": "claude-opus-4-7",
  "max_tokens": 2048,
  "messages": [
    {"role": "user", "content": "北京天气?"},
    {
      "role": "assistant",
      "content": [
        {"type": "text", "text": "我帮你查"},
        {"type": "tool_use", "id": "toolu_xxx", "name": "get_current_weather", "input": {"location": "北京"}}
      ]
    },
    {
      "role": "user",
      "content": [
        {
          "type": "tool_result",
          "tool_use_id": "toolu_xxx",
          "content": "{\"temp\":18,\"description\":\"\"}"
        }
      ]
    }
  ],
  "tools": [...]
}

注意 Claude 用 role: user 包裹 tool_result(OpenAI 用 role: tool)。

完整 Python 示例

python
from openai import OpenAI
import json

client = OpenAI(api_key="<key>", base_url="https://shuro.vip/v1")

def get_weather(location, unit="celsius"):
    """模拟查天气"""
    return {"temp": 18, "description": "晴", "unit": unit}

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "获取天气",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {"type": "string"},
                "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
            },
            "required": ["location"]
        }
    }
}]

messages = [{"role": "user", "content": "北京天气?"}]

# 第一轮:模型调用 tool
r1 = client.chat.completions.create(model="gpt-5.5", messages=messages, tools=tools)
tool_call = r1.choices[0].message.tool_calls[0]

# 你执行 tool
args = json.loads(tool_call.function.arguments)
result = get_weather(**args)

# 把结果发回
messages.append(r1.choices[0].message.model_dump())
messages.append({
    "role": "tool",
    "tool_call_id": tool_call.id,
    "content": json.dumps(result)
})

# 第二轮:模型基于结果回答
r2 = client.chat.completions.create(model="gpt-5.5", messages=messages, tools=tools)
print(r2.choices[0].message.content)
# "北京今天 18 度,天气晴朗。"

并行 tool 调用

GPT-5 系 / Claude 支持一次返回多个 tool_calls 并行执行:

json
{
  "tool_calls": [
    {"id": "1", "function": {"name": "get_weather", "arguments": "..."}},
    {"id": "2", "function": {"name": "get_news", "arguments": "..."}},
    {"id": "3", "function": {"name": "get_traffic", "arguments": "..."}}
  ]
}

并行执行三个,再一次性把结果都发回。比串行快 N 倍。

强制 JSON 输出(tool_use 模式)

利用 tool_use 强制 Claude 输出严格 JSON:

json
{
  "model": "claude-opus-4-7",
  "max_tokens": 1024,
  "tools": [{
    "name": "extract_data",
    "description": "Extract structured data",
    "input_schema": {
      "type": "object",
      "properties": {
        "name": {"type": "string"},
        "age": {"type": "integer"}
      },
      "required": ["name", "age"]
    }
  }],
  "tool_choice": {"type": "tool", "name": "extract_data"},
  "messages": [{"role": "user", "content": "我叫张三,30 岁"}]
}

强制调用 extract_datainput 字段就是严格 JSON。详见 结构化输出

支持的模型

模型Function/Tool 支持
gpt-5.5 / gpt-5.4 / gpt-5.4-mini✅ 完整 + 并行
claude-opus-4-8 / claude-opus-4-7 / claude-opus-4-6 / claude-fable-5✅ 完整 + 并行
claude-sonnet-4-6 / claude-haiku-4-5-20251001✅ 完整 + 并行

常见错误

arguments 不是合法 JSON

模型偶尔输出格式错的 JSON。用 try/except 处理

python
try:
    args = json.loads(tool_call.function.arguments)
except json.JSONDecodeError:
    # 给模型反馈 + 重试
    pass

死循环调用同一 tool

模型一直调 get_weather 不返回最终答案。加 max_iterations

python
for i in range(5):  # 最多 5 轮
    resp = client.chat.completions.create(...)
    if resp.choices[0].message.tool_calls:
        # 执行 + 继续
    else:
        break  # 模型给出最终回答了

tool_choice required 但模型不调

少数模型不严格遵守 required。用 Claude 的 tool_choice: {type: "tool", name: "xxx"} 更可靠

跟 MCP 的区别

Function CallingMCP
调用方模型模型(透过 MCP server)
工具定义写在 request bodyMCP server 自己声明
执行你的应用代码MCP server 进程
共享单个 request全局所有 chat
适合业务逻辑跨应用复用(DB、GitHub 等)

详见 MCP 数据连接器

参考

内容采用 CC BY-NC-ND 4.0 协议 · 禁止商业使用 / 禁止改编 / 禁止训练 AI 模型