OpenAI API 函数调用(function calling)怎么写:tools 定义、function_call_output 回传、strict 模式

想让模型调用你自己的函数查天气、查订单?Responses API 里在 tools 中声明函数,模型返回 function_call,你执行后用 function_call_output 把结果发回去。本文给 Python 和 Node 完整示例,讲 strict、tool_choice、并行调用,和官方的最佳实践。

NNathaniel bigo··原创首发·AI 辅助撰写
9 分钟读完
资料核对于 2026-11-05 · 依据官方文档与公开资料整理 其他 账号
本文根据 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。

结论先说

  1. 模型自己不会执行你的函数。 它只会返回“我想调用某函数、参数是什么”,真正执行的是你的程序。
  2. 一次完整调用要两次请求以上:第一次带 tools,第二次把函数结果带回去,才能得到最终回答。
  3. 函数用 JSON schema 描述,字段是 type、name、description、parameters、strict。
  4. 官方建议始终开启 strict,让调用严格符合你的 schema;开启后要求每个对象 additionalProperties 为 false,且所有字段都在 required 里。
  5. 回传结果用 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 和并行调用

tool_choice 的设置:auto、required、指定函数、allowed_tools、none

图:本站根据 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

Nathaniel 的更多内容

  1. 01

    Claude Code 在 Windows 上的常见坑:Git Bash 还是 PowerShell、路径反斜杠、假报错、WSL 怎么选

    Windows 上用 Claude Code,装好之后最容易踩的是:用哪个 shell、路径写法不一致、grep 没匹配就报错、钩子没生效、WSL 和原生怎么选。本文逐条按官方文档整理原因和处理办法,附三段提示词和一张对照表。

    Claude0
  2. 02

    Claude Code Hooks 实战「提交前自动跑测试」:PreToolUse 拦住 git commit,测试不过就退出码 2,附 Windows 注意点

    只写一个完整例子:让 Claude Code 每次要执行 git commit 之前,先自动跑项目测试,没通过就拦下并把输出交给它修。本文按官方 Hooks 文档给出脚本、settings.json 配置、测试方法、排错和 Windows 的两处坑。

    Claude0
  3. 03

    Claude Code 自定义斜杠命令与 Skill 实战:从零写一个「生成更新日志」的 /release-notes,含传参、预执行命令和调试

    概念看过了,还是不知道从哪下手?本文按 Claude Code 官方「Extend Claude with skills」写一个完整可用的例子:用 /release-notes 根据 git 记录生成更新日志,覆盖目录、frontmatter、传参、预执行命令、预授权和调试。

    Claude0
  4. 04

    Claude Code 部署网站:先写 Dockerfile 和 compose 在本机跑通,再按清单上云服务器,别让它直接改线上

    想让 Claude Code 帮你把网站部署到云服务器。本文只写通用做法,按 Docker 官方文档讲:让它写 Dockerfile、.dockerignore 和 compose,在本机跑通,端口和数据卷怎么设,再给出上线清单,并说明为什么不要让它直接动线上机器。

    Claude0
  5. 05

    Claude Code 写爬虫与数据清洗:先查 robots.txt 和网站条款,控制频率,原始数据留一份再清洗

    想让 Claude Code 写爬虫抓数据再清洗。本文先讲合规:robots.txt 不是授权也不是安全措施、网站条款要自己读;再讲怎么用 Python 标准库检查规则、小样本先试、保存原始数据,以及用 pandas 清洗,附四段提示词。

    Claude0
  6. 06

    Claude Code 写 Chrome 扩展:按 Manifest V3 起步,加载未打包的扩展,改了哪些文件要重新加载

    想让 Claude Code 帮你写一个 Chrome 扩展。本文按 Chrome 官方扩展文档讲:manifest.json 的最小写法、在 chrome://extensions 加载未打包的扩展、哪些改动要刷新、怎么看控制台和报错,再给四段提示词,以及权限要尽量少。

    Claude0

同产品的其他教程

  1. 01

    OpenAI API 的 token 怎么算、怎么估算费用:input_tokens 计数接口、tiktoken 和隐藏的输出 token

    发请求前想知道会用多少 token?官方有 Responses 的 input_tokens 计数接口,能把文字、图片、文件、工具定义一起算准;本地 tiktoken 只适合纯文本。本文给 Python 和 Node 示例,讲输出 token 为什么可能比看到的多,以及怎么估算费用。

    ChatGPT0
  2. 02

    OpenAI API Node.js / TypeScript 快速上手:npm install openai、example.mjs 第一个请求,到流式、函数调用、联网搜索

    用 Node.js 调 OpenAI API:设置 OPENAI_API_KEY 环境变量,npm install openai,新建 example.mjs,用 client.responses.create 发出第一个请求。并列出图片、文件、流式、函数调用、联网搜索和错误捕获的 Node 写法。

    ChatGPT0
  3. 03

    OpenAI API 用量层级(usage tiers)与速率限制怎么提升:Free、Build、Launch、Grow 和后台 Limits 页

    OpenAI API 的限速不是固定的:官方按累计购买额度把组织分成 Free、Build、Launch、Grow 四个层级,达到门槛自动升级。本文讲 RPM、TPM 等指标、怎么在后台查自己的限额、响应头怎么读、花费上限和限速的区别,以及怎么让限额变得够用。

    ChatGPT0
  4. 04

    OpenAI API 报错 400、401、403、404、429、500、503 怎么排查:按官方错误码页逐个看原因和解决办法

    调用 OpenAI API 返回 400、401、403、404、429、500、503,各自什么意思?本文按官方 Error codes 页,每个状态码一节,写清官方给的原因和解决办法,并说明 404 在官方页面里的位置、429 的六种情形,附 Python 和 Node 的错误捕获写法。

    ChatGPT0
  5. 05

    OpenAI Realtime API 是什么:语音到语音会话、WebRTC 与 WebSocket、临时密钥和事件机制

    Realtime API 让模型直接处理音频,做可以随时打断的语音助手。本文按官方文档讲它是什么、什么时候用、浏览器接入的流程、session 与事件、可用声音、60 分钟会话上限、安全标识,以及它和转写、文字转语音的分工。

    ChatGPT0
  6. 06

    OpenAI 图像生成 API 怎么用:gpt-image 系列、images.generate 与 Responses 工具、尺寸质量和遮罩编辑

    用 OpenAI API 生成或编辑图片,有 Image API 和 Responses 里的 image_generation 工具两条路。本文按官方文档给 Python 和 Node 示例,讲 gpt-image 模型选择、尺寸质量格式参数、遮罩编辑、被拦截时的错误处理,以及需要组织验证的提醒。

    ChatGPT0

0 条评论

登录 后参与评论

还没有评论,来抢沙发~