跳转到主要内容
Function Calling(函数调用,简称 FC)是构建 Agent 的基础能力:模型不执行函数,只输出”想调哪个函数 + 什么参数”,执行在你自己的代码里完成,把结果回传后模型再给出最终回答。 本页基于 OpenAI 官方文档整理(developers.openai.com/api/docs/guides/function-calling,2026年6月数据),两个端点的示例均可直接复制运行。

完整调用循环

1

定义 tools

把函数名、用途描述、参数 JSON Schema 随请求发给模型
2

模型返回函数调用

模型判断需要调用时,返回函数名和 JSON 格式的参数
3

本地执行

你的代码解析参数、真正执行函数(查数据库、调外部 API……)
4

回传结果

把执行结果连同历史一起再发一次请求,模型基于结果生成最终回答

两个端点的关键格式差异

同一个功能,/v1/chat/completions/v1/responses 的字段格式不一样,这是接入时最容易踩的坑:
Chat CompletionsResponses
tools 定义嵌套:{"type": "function", "function": {name, parameters, ...}}扁平:{"type": "function", "name": ..., "parameters": ...}
调用返回message.tool_calls[](含 id顶层 output item:{"type": "function_call", "call_id", "name", "arguments"}
结果回传{"role": "tool", "tool_call_id": ..., "content": ...}{"type": "function_call_output", "call_id": ..., "output": ...}
strict 模式需显式 "strict": true服务端会尽量自动归一化为 strict
两套格式不能混用。把 Chat Completions 的嵌套 function: {...} 定义发给 /v1/responses(或反过来)是 SDK 报”参数无效”最常见的原因。

Chat Completions 完整示例

以查天气为例,走完”定义 → 调用 → 执行 → 回传”全循环:
import json
from openai import OpenAI

client = OpenAI(
    api_key="YOUR_API_KEY",
    base_url="https://api.apiyi.com/v1"
)

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "获取指定城市的当前天气",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "城市名,如:北京"}
            },
            "required": ["city"],
            "additionalProperties": False
        },
        "strict": True
    }
}]

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

# 第 1 次请求:模型决定调函数
r1 = client.chat.completions.create(
    model="gpt-5.4", messages=messages, tools=tools
)
tool_call = r1.choices[0].message.tool_calls[0]
args = json.loads(tool_call.function.arguments)

# 本地执行(这里用假数据代替真实查询)
weather = {"city": args["city"], "temp": "26°C", "condition": "晴"}

# 第 2 次请求:回传结果,模型生成最终回答
messages.append(r1.choices[0].message)
messages.append({
    "role": "tool",
    "tool_call_id": tool_call.id,
    "content": json.dumps(weather, ensure_ascii=False)
})

r2 = client.chat.completions.create(
    model="gpt-5.4", messages=messages, tools=tools
)
print(r2.choices[0].message.content)

Responses 完整示例

注意三处不同:tools 定义是扁平的、调用以顶层 function_call item 返回、回传用 function_call_output。配合 previous_response_id,第 2 次请求不必重发全部历史:
import json
from openai import OpenAI

client = OpenAI(
    api_key="YOUR_API_KEY",
    base_url="https://api.apiyi.com/v1"
)

tools = [{
    "type": "function",          # 扁平定义,没有嵌套的 function 字段
    "name": "get_weather",
    "description": "获取指定城市的当前天气",
    "parameters": {
        "type": "object",
        "properties": {
            "city": {"type": "string", "description": "城市名,如:北京"}
        },
        "required": ["city"],
        "additionalProperties": False
    }
}]

# 第 1 次请求
r1 = client.responses.create(
    model="gpt-5.4",
    input="北京天气怎么样?",
    tools=tools
)

# 从 output 数组里找 function_call item
call = next(item for item in r1.output if item.type == "function_call")
args = json.loads(call.arguments)

weather = {"city": args["city"], "temp": "26°C", "condition": "晴"}

# 第 2 次请求:用 previous_response_id 接上文,只回传函数结果
r2 = client.responses.create(
    model="gpt-5.4",
    previous_response_id=r1.id,
    input=[{
        "type": "function_call_output",
        "call_id": call.call_id,
        "output": json.dumps(weather, ensure_ascii=False)
    }],
    tools=tools
)
print(r2.output_text)

strict 严格模式(结构化输出)

strict: true 让模型输出的参数严格符合你的 JSON Schema,杜绝幻觉字段和缺字段。三个要求:
  1. Schema 里必须有 "additionalProperties": false
  2. 所有字段都要出现在 required 里(可选语义用 "type": ["string", "null"] 表达)
  3. 只能用受支持的 JSON Schema 子集(基本类型、enum、数组、嵌套对象等)
// ✅ 合法的 strict schema
{
  "type": "object",
  "properties": {
    "city": {"type": "string"},
    "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
    "date": {"type": ["string", "null"], "description": "可选,默认今天"}
  },
  "required": ["city", "unit", "date"],
  "additionalProperties": false
}
// ❌ 不合法:缺 additionalProperties,date 不在 required 里
{
  "type": "object",
  "properties": {
    "city": {"type": "string"},
    "date": {"type": "string"}
  },
  "required": ["city"]
}
strict 模式与并行函数调用不兼容:需要严格 schema 保证时,请同时设置 parallel_tool_calls: false

parallel_tool_calls 与 tool_choice

并行调用

parallel_tool_calls 默认开启,模型可以在一轮里同时请求多个函数(如同时查北京和上海的天气)。逐个执行后全部回传再发起下一次请求,每个结果都要带对应的 call_id(responses)或 tool_call_id(chat)配对。

tool_choice 控制策略

取值行为
"auto"(默认)模型自行决定调不调、调哪个
"required"必须调用至少一个函数
{"type": "function", "name": "get_weather"}强制调用指定函数
"none"禁止调用,只生成文本

allowed_tools 限定子集

工具很多但本轮只想开放一部分时,用 tool_choiceallowed_tools 形式限定可调用子集 —— 它不改变 tools 列表本身,因此不破坏 缓存 的稳定前缀:
tool_choice={
    "type": "allowed_tools",
    "mode": "auto",
    "tools": [{"type": "function", "name": "get_weather"}]
}

流式中的函数调用

Chat Completions:按 index 拼接

函数参数在流式里是分片下发的,按 index 累加 arguments 字符串,流结束后再 json.loads
stream = client.chat.completions.create(
    model="gpt-5.4", messages=messages, tools=tools, stream=True
)

calls = {}  # index -> {name, arguments}
for chunk in stream:
    delta = chunk.choices[0].delta if chunk.choices else None
    if delta and delta.tool_calls:
        for tc in delta.tool_calls:
            entry = calls.setdefault(tc.index, {"name": "", "arguments": ""})
            if tc.function.name:
                entry["name"] = tc.function.name
            if tc.function.arguments:
                entry["arguments"] += tc.function.arguments

print(calls)  # 流结束后每个 entry 的 arguments 才是完整 JSON

Responses:监听语义事件

response.function_call_arguments.delta 事件携带参数增量,response.function_call_arguments.done 给出完整参数,无需自己按 index 拼。

最佳实践与踩坑

写好工具定义:
  • 函数名和 description 是写给模型看的:说清楚”什么时候该调我”,比如 "获取实时天气,仅当用户明确询问天气时调用"
  • 参数用 enum 收窄:能枚举就别用自由字符串,幻觉参数会少一大半
  • 工具定义放 prompt 前部且保持稳定:tools 会参与缓存前缀比对,定义稳定 = 输入费打 1 折(见 缓存计费
  • Agent 循环设最大轮数:避免模型在”调函数 → 回传 → 又调函数”里打转烧钱
常见踩坑:
现象处理
arguments 不是合法 JSONstrict: true,从根上解决
模型调了不存在的函数名tool_choice 收紧;检查 description 是否误导
并行调用后报 call_id 不匹配每个结果必须和对应调用的 call_id / tool_call_id 一一配对,缺一个都会报错
两个端点格式混用报参数错误对照上文差异表,确认 tools 定义嵌套/扁平与端点匹配

模型支持与选型

gpt-5 全系支持函数调用,按场景选:
场景推荐模型理由
日常 Agent / 工具调用gpt-5.4($2.50 / $15.00 每 1M)能力与成本均衡
高频轻量工具路由gpt-5.4-mini($0.75 / $4.50 每 1M)便宜,简单分发够用
复杂多步推理 Agentgpt-5.5($5.00 / $30.00 每 1M)长链路规划更稳

相关链接