本文根据 OpenAI 官方《Function calling》整理,资料核对于 2026-11-05。配图为本站整理的示意图,不是界面截图。代码里的模型名取自官方当天示例,请以官方模型页为准。本站(bigolab.com)不是 OpenAI 官方网站。API 是按用量计费的独立服务,与 ChatGPT 订阅分开计算,Key 的获取见 /guides/openai-api-key。
适用于谁
- 想让模型“动手”的开发者:查数据库、查天气、查订单、发邮件,由模型决定调不调、传什么参数;
- 已经能发出第一个请求(见 /guides/openai-api-python-quickstart),但没写过工具调用的人;
- 对 Responses 请求格式还不熟的人,可以先看 /guides/openai-responses-api。
结论先说
- 模型自己不会执行你的函数。 它只会返回“我想调用某函数、参数是什么”,真正执行的是你的程序。
- 一次完整调用要两次请求以上:第一次带
tools,第二次把函数结果带回去,才能得到最终回答。 - 函数用 JSON schema 描述,字段是
type、name、description、parameters、strict。 - 官方建议始终开启
strict,让调用严格符合你的 schema;开启后要求每个对象additionalProperties为false,且所有字段都在required里。 - 回传结果用
function_call_output,必须带上对应的call_id,否则模型对不上是哪一次调用。

图:本站根据 OpenAI 官方《Function calling》 整理的示意图
一、先认识三个词
官方用三个词解释:
- 工具(tool):你告诉模型“你可以用”的能力,比如
get_weather,参数是location; - 工具调用(tool call):模型看了提示后,认为要完成任务就得用某个工具,于是返回的一种特殊响应;
- 工具调用输出(tool call output):你的程序执行后产生的结果,可以是 JSON 或纯文本,并要引用具体那次调用的
call_id。
官方还区分:函数是用 JSON schema 定义的一种工具;除此之外还有处理自由文本的自定义工具,以及平台内置工具(联网搜索、代码解释器、MCP 等)。本文只讲函数。
二、定义函数
函数通常放在每次请求的 tools 参数里。官方给的字段:
| 字段 | 含义 |
|---|---|
type | 固定写 function |
name | 函数名,例如 get_weather |
description | 什么时候用、怎么用 |
parameters | 用 JSON schema 定义的参数 |
strict | 是否开启严格模式 |
示例(Python 字典写法,布尔值是 True、False):
python
tools = [
{
"type": "function",
"name": "get_weather",
"description": "查询某个城市当前的天气。",
"strict": True,
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市和国家,例如 Bogota, Colombia",
},
"units": {
"type": ["string", "null"],
"enum": ["celsius", "fahrenheit", None],
"description": "温度单位,不确定时传 null",
},
},
"required": ["location", "units"],
"additionalProperties": False,
},
}
]
这里 units 是可选参数,但在 strict 模式下仍然要列进 required,用 ["string", "null"] 表示可以为空,这是官方说明的写法。enum 里加 None 是本站为了让枚举与 null 类型一致做的补充,官方示例只写了两个单位,如遇校验报错以官方当天文档为准。
三、完整示例:Python
下面的结构对应官方五步。函数是本站写的假数据,只为演示流程:
python
import json
from openai import OpenAI
client = OpenAI()
def get_weather(location, units=None):
# 这里应当换成真正查天气的代码
return {"location": location, "temperature": 25, "unit": units or "celsius"}
input_list = [{"role": "user", "content": "巴黎今天天气怎么样?"}]
# 1. 带着 tools 发第一次请求
response = client.responses.create(
model="gpt-6-astra", # 以官方模型页当天为准
tools=tools,
input=input_list,
)
# 保留模型输出,下一次请求要一起带上
input_list += response.output
# 2~4. 找出 function_call,执行,把结果加进 input
for item in response.output:
if item.type == "function_call" and item.name == "get_weather":
args = json.loads(item.arguments)
result = get_weather(**args)
input_list.append({
"type": "function_call_output",
"call_id": item.call_id,
"output": json.dumps(result, ensure_ascii=False),
})
# 5. 带着结果再请求一次,拿最终回答
response = client.responses.create(
model="gpt-6-astra",
tools=tools,
input=input_list,
)
print(response.output_text)
三个要点:
item.arguments是 JSON 字符串,要自己json.loads;call_id必须原样带回;- 官方说推理模型返回的推理项在回传结果时也必须一起传回,上面“整体加入
response.output”的写法就满足这一点。
四、完整示例:Node.js
保存为 .mjs 文件运行。官方 Node 示例还用到一个 toResponseInputItems 辅助函数来整理输出,这里为了简洁,直接展开 response.output;这一处是本站改写,若你的 SDK 版本提示类型不符,请按官方当天示例使用辅助函数。
javascript
import OpenAI from "openai";
const openai = new OpenAI();
const tools = [
{
type: "function",
name: "get_weather",
description: "查询某个城市当前的天气。",
strict: true,
parameters: {
type: "object",
properties: {
location: { type: "string", description: "城市和国家" },
},
required: ["location"],
additionalProperties: false,
},
},
];
function getWeather(location) {
return { location, temperature: 25, unit: "celsius" }; // 换成真实查询
}
const input = [{ role: "user", content: "巴黎今天天气怎么样?" }];
let response = await openai.responses.create({
model: "gpt-6-astra", // 以官方模型页当天为准
tools,
input,
});
input.push(...response.output);
for (const item of response.output) {
if (item.type !== "function_call") continue;
if (item.name === "get_weather") {
const { location } = JSON.parse(item.arguments);
input.push({
type: "function_call_output",
call_id: item.call_id,
output: JSON.stringify(getWeather(location)),
});
}
}
response = await openai.responses.create({
model: "gpt-6-astra",
tools,
input,
});
console.log(response.output_text);
五、一次可能有多个调用
官方提醒:模型的响应里可能有零个、一个或多个函数调用,所以最好假定会有多个。官方的示例里,一次响应同时包含两个 get_weather 和一个 send_email。写法上就是上面那个 for 循环:遍历 output,每遇到一个 function_call 就执行一次,各自回传带自己 call_id 的结果。
如果函数没有返回值(比如发邮件),官方建议回一个表示成败的字符串,例如 "success"。如果函数要返回图片或文件,可以传图片或文件对象的数组而不是字符串。
六、strict、tool_choice 和并行调用

图:本站根据 OpenAI 官方《Function calling》 整理的示意图
strict:设为 true 时,调用会可靠地符合 schema,而不是尽力而为。条件是每个对象 additionalProperties 设为 false、所有 properties 都列在 required。如果你发了 strict: true 但 schema 不满足,请求会被拒绝并说明缺了哪些约束。官方还说:省略 strict 时,Responses 会尽量把 schema 归一化成严格模式,做不到才回退成非严格;想保持非严格要显式写 strict: false。
tool_choice:默认 auto。required 表示必须调用一个或多个函数;也可以强制调用某个指定函数;allowed_tools 能限定可调用的子集,官方说这样做不用改动传入的工具列表,有利于提示词缓存省钱;设 none 等于没传函数。
并行:模型一轮里可能调多个函数。设 parallel_tool_calls 为 false 可保证每轮最多零个或一个调用。
七、官方的几条写法建议
- 函数名、参数说明写清楚,说明格式和输出含义;
- 用枚举和对象结构避免非法状态,官方举例
toggle_light(on, off)就允许出现不合法的调用; - 已经知道的参数别让模型填,比如你手里已有
order_id,就在代码里传,不要做成参数; - 总是连续调用的函数,合并成一个;
- 一开始可用的函数尽量少,官方软性建议少于 20 个。
还有一点和费用有关:官方说函数定义会占上下文,并按输入 token 计费,函数多或描述长时要注意。价格以官方价格页当天为准,见 /guides/openai-api-price-official-table。
常见问题
Q:模型返回了函数调用,为什么 output_text 是空的?
正常。这一轮模型的输出是 function_call 项,不是文字。执行函数、回传结果后的那次请求才有最终文字。
Q:想边生成边显示函数参数?
官方说流式也支持函数调用,会出现 response.function_call_arguments.delta 之类的事件,基础写法见 /guides/openai-api-streaming。
Q:我要的是固定格式的 JSON 回答,不是调函数?
那是结构化输出,见 /guides/openai-api-structured-outputs。
Q:请求被限流了?
见 /guides/openai-api-429-error。
参考资料
- OpenAI 官方:Function calling — https://developers.openai.com/api/docs/guides/function-calling
0 条评论
还没有评论,来抢沙发~