跳转到主要内容
函数调用(又称 tool use)指的是:模型不再用文字回复,而是返回一个结构化的调用请求——要调用哪个函数、传什么参数。函数的实际代码由在自己这边运行,再把结果交回给模型。之后模型才会把结果整理成一段正常的、给人看的回答。 听起来不起眼,但所有智能体(Agent)都建立在这个机制之上。模型本身不能查你的数据库、取天气、调别人的 API,但它能请你去做,并根据你返回的内容继续推理。 流程始终是同一套:
  1. 你描述好可用的函数(它们的 schema),带上 tools= 发出一个普通请求。
  2. 模型返回的不是文字,而是一个 tool_calls 数组——调用什么、传什么参数。
  3. 你自己运行函数,然后发出第二次请求,把模型的回复和函数结果都追加进历史。
  4. 模型返回最终文字。

完整 Python 示例

用经典的 get_weather(city) 举例。真实场景里它会去调天气服务;这里返回一个占位结果,让流程更清晰。
import json
from openai import OpenAI

client = OpenAI(
    api_key="sk-你的密钥",
    base_url="https://www.ruapi.ai/v1",
)

# 这是你自己的真实代码。模型并不会运行它,只会请求你去调用。
def get_weather(city: str) -> str:
    # 这里本该是一次真实的天气 API 调用
    return f"{city}当前 +18°C,局部多云"

# 给模型的函数描述:它能做什么、接收哪些参数
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "返回指定城市的当前天气",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "城市名,例如「北京」",
                    }
                },
                "required": ["city"],
            },
        },
    }
]

messages = [{"role": "user", "content": "北京现在天气怎么样?"}]

# 第 1 步。第一次请求——把问题和工具列表交给模型
response = client.chat.completions.create(
    model="claude-opus-4-8",  # 准确名称见主站定价页
    messages=messages,
    tools=tools,
)

message = response.choices[0].message

# 第 2 步。检查模型是否想调用函数
if message.tool_calls:
    # 重要:先把模型自己的回复(带 tool_calls 的那条)追加进历史
    messages.append(message)

    # 第 3 步。逐个处理调用(可能不止一个)
    for tool_call in message.tool_calls:
        # 参数是以 JSON 字符串形式传来的——必须先解析
        args = json.loads(tool_call.function.arguments)

        if tool_call.function.name == "get_weather":
            result = get_weather(args["city"])
        else:
            result = "未知函数"

        # 把调用结果作为单独的 role="tool" 消息发回去
        messages.append(
            {
                "role": "tool",
                "tool_call_id": tool_call.id,  # 与这次具体调用绑定
                "content": result,
            }
        )

    # 第 4 步。第二次请求——此时模型看到结果,给出最终回答
    final = client.chat.completions.create(
        model="claude-opus-4-8",
        messages=messages,
        tools=tools,
    )
    print(final.choices[0].message.content)
else:
    # 模型选择直接回答,没有调用函数
    print(message.content)
只有能力较强的模型才支持 tool use——比如 ClaudeGPT 系列。较老或轻量的模型 可能直接忽略 tools=。哪个模型支持什么,请看主站**「定价」**页上的能力标记。

常见坑

一次回复里的 message.tool_calls 是一个数组,可能包含不止一个调用——比如同时查两个城市的天气。 用循环遍历它,为每一个 tool_call 都追加一条带自己 tool_call_idrole="tool" 消息。 只要有一个调用没回结果,下一次请求就会报错。
messages 里的顺序是严格的:先追加模型自己的回复(带 tool_calls 的那个 message 对象), 然后追加带结果的 role="tool" 消息。如果在没有前置助手回复的情况下直接发结果, API 会因历史不一致而报错。
tool_call.function.arguments 是一个 JSON 字符串,不是现成的字典。使用前必须 用 json.loads(...) 解析。直接对字符串按键取值会报错。

下一步