首页使用帮助Function Calling
HELP / API 工具调用

OpenAI Function Calling 怎么用?

Function Calling 让模型提出“调用哪个工具、传什么参数”,真正执行仍由你的应用完成。可靠实现要处理 strict Schema、call_id、多调用循环、工具结果回传、权限校验和失败重试。

主关键词:OpenAI Function Calling 怎么用strictcall_id更新:2026-10-31
先给结论

Function Calling 不是“模型替你执行代码”,而是一个由应用控制的工具调用循环:发送工具定义 → 模型返回一个或多个调用 → 应用校验并执行 → 用原始 call_id 回传结果 → 继续请求,直到模型返回最终回答。生产系统不要只处理第一个调用,也不要把 strict 当成权限验证。

官方资料(2026-10-30 核对):Function calling guide · Responses API reference · Chat Completions reference · 迁移到 Responses

Function Calling 的五步循环

  1. 定义工具:给出稳定的名称、明确描述和参数 JSON Schema,只暴露当前任务需要的工具。
  2. 发送请求:模型决定是否调用工具;tool_choice 可改变这个选择范围。
  3. 读取全部调用:Responses 中查找 function_call Items;不要假定只会返回一个。
  4. 应用执行:解析参数后做 Schema、业务、身份和权限校验,再调用数据库或内部 API。
  5. 回传并继续:用对应的 call_id 发送 function_call_output,重复循环,直到没有新调用。

模型只负责提出调用;支付、发信、删除、退款等副作用必须由服务端基于当前用户权限再次确认。工具返回值也应只包含模型完成任务所需的数据,避免把密钥、完整用户资料或内部错误栈放进上下文。

Responses API 完整最小示例

1. 定义 strict 工具并发起请求

import OpenAI from "openai";
const client = new OpenAI();

const tools = [{
  type: "function",
  name: "get_order_status",
  description: "按订单号查询订单状态",
  strict: true,
  parameters: {
    type: "object",
    properties: {
      order_id: { type: "string", description: "订单号,如 A-102" }
    },
    required: ["order_id"],
    additionalProperties: false
  }
}];

let response = await client.responses.create({
  model: "YOUR_MODEL",
  instructions: "只在用户要求查订单时调用工具。",
  input: "帮我查订单 A-102",
  tools
});

strict: true 时,每个对象应设置 additionalProperties: false,并把所有 properties 列进 required。需要“可选字段”时,可让字段类型包含 null,而不是从 required 中删除。

2. 执行所有调用,并按 call_id 回传

for (let step = 0; step < 5; step++) {
  const calls = response.output.filter(
    item => item.type === "function_call"
  );
  if (calls.length === 0) break;

  const outputs = [];
  for (const call of calls) {
    const args = JSON.parse(call.arguments);
    validateAndAuthorize(call.name, args);
    const result = await runToolIdempotently(call.name, args);

    outputs.push({
      type: "function_call_output",
      call_id: call.call_id,
      output: JSON.stringify(result)
    });
  }

  response = await client.responses.create({
    model: "YOUR_MODEL",
    instructions: "只在用户要求查订单时调用工具。",
    previous_response_id: response.id,
    input: outputs,
    tools
  });
}

const answer = response.output_text;

关键不是代码长短,而是三个不变量:执行全部调用、使用模型返回的 call_id、给循环设置步数上限。如果模型在工具调用旁返回 reasoning Items,使用推理模型时要按官方端点要求保留并传回这些 Items,不能只摘出函数名和参数。

Responses 与 Chat Completions 的工具调用差异

环节Responses APIChat Completions
工具定义工具字段直接包含 name、description、parameters函数定义通常位于工具对象的 function 内
模型返回response.output 中的 function_call Itemchoices[0].message.tool_calls[]
关联标识call_id每个 tool call 的 id
工具结果function_call_output + call_idrole: "tool" + tool_call_id
继续上下文可用 previous_response_id,或自己传回所需 Items把 assistant 的 tool_calls 消息和随后各 tool 消息加入 messages
结束判断没有新的 function_call,再读最终 message/output_text没有 tool_calls,再读 message.content;工具阶段常见 finish_reason 为 tool_calls

如果你正在迁移端点,先看 Responses API 与 Chat Completions 区别。两套格式不能只改 URL:调用对象、结果回传、状态和流式事件都不同。

strict 模式解决什么,不解决什么?

它能解决参数形状

  • 字段名、类型、枚举和必填项按支持的 JSON Schema 子集输出。
  • 减少参数缺失、额外字段和类型漂移。
  • Schema 不兼容时尽早暴露配置错误,而不是让错误参数进入工具。

它不能解决业务与安全

  • 订单号存在,不代表当前用户有权查看该订单。
  • 金额符合 number,不代表金额在业务允许范围内。
  • 工具名称正确,不代表当前会话允许调用删除、支付或发信。
  • 参数结构正确,也可能包含模型误解、过期数据或提示注入诱导。

因此应用侧仍要做 allowlist、身份校验、资源归属检查、数值范围、幂等键和审计日志。Schema 是输入边界,不是授权系统。

tool_choice 和并行调用怎么选?

配置模型行为适合场景
auto可以不调用,也可调用一个或多个工具普通助手和开放式问答
required至少调用一个工具答案必须建立在实时系统数据上
强制指定函数只允许目标函数流程已明确进入某个动作步骤
allowed_tools从工具集合中进一步缩小允许范围多阶段 Agent、最小权限
none禁止工具调用纯文本步骤或安全降级

默认要假设一次响应可能有多个调用。若业务必须串行,或工具有相互依赖,可设置 parallel_tool_calls: false,使一次最多产生一个调用;否则就为每个调用分别执行并回传结果。即使并行,也要限制并发、超时和重试,避免模型一次请求放大后端压力。

生产环境的安全与稳定性清单

  1. 最小工具集:每一步只提供真正允许的工具,名称和描述要互斥、清晰。
  2. 验证两层:先验证 Schema,再验证用户身份、资源归属、业务状态和数值范围。
  3. 副作用幂等:支付、发信、创建订单使用幂等键;重试不能重复执行。
  4. 边界明确:设置工具超时、最大输出大小、调用总步数和每轮并发数。
  5. 错误可读:把安全的结构化错误回传给模型,不泄露 Token、连接串或内部栈。
  6. 可观测:记录 response id、call_id、工具名、耗时、结果状态和业务追踪 ID;敏感参数脱敏。
  7. 故障分类:429 按限流退避,5xx/超时有限重试;参数或权限错误不要无脑重试。

部署前还应使用固定评测集覆盖“不调用工具、调用一个、调用多个、参数非法、权限不足、工具超时、重复回传、模型继续调用”八类路径。相关排障见 OpenAI API 429 与速率限制、500/503 和超时。

最常见的六个实现错误

  1. 只处理 calls[0]:后续调用丢失,模型拿不到完整数据。
  2. 自己生成关联 ID:必须回传原调用的 call_id 或 tool_call_id。
  3. 解析参数后直接执行:JSON 可解析不等于通过权限和业务规则。
  4. 把工具结果当最终答案:工具结果还要交给模型,直到没有新调用。
  5. 循环没有上限:模型和工具可能互相触发,导致成本和副作用失控。
  6. 把 Function Calling 当 Structured Outputs:前者连接外部动作,后者约束最终 JSON;选择规则见 Structured Outputs 与 JSON mode。
Webhook 不是模型工具调用

Function Calling 是模型请求你的应用执行工具;Webhook 是 OpenAI 向服务器发送事件。若工具链需要接收后台终态,请单独按 OpenAI Webhooks 验签、去重与重试指南搭建接收端。

审核不能替代工具授权

执行工具前既要校验 Schema、权限和业务规则,也要按风险审核对话内容;字段与流程见 OpenAI Moderation API 指南。

常见问题

Function Calling 是让模型直接执行函数吗?

不是。模型只返回要调用的工具名称和 JSON 参数;你的应用必须校验参数、检查权限、真正执行函数,再把结果回传给模型。

Responses API 怎样把工具结果与原调用对应起来?

读取 function_call Item 的 call_id,并用同一 call_id 发送 function_call_output。不要用数组位置、函数名或自己生成的 ID 猜测对应关系。

strict: true 能保证什么?

它让函数参数在支持的 JSON Schema 子集内遵循 Schema。每个对象要设置 additionalProperties: false,所有 properties 都要列入 required;可选值可用包含 null 的联合类型。它不替代业务校验或权限控制。

一次响应会返回多个 Function Call 吗?

会。应用应假设可能有零个、一个或多个调用,逐个执行并回传结果。确实需要限制并行调用时,可设置 parallel_tool_calls: false,使一次最多产生一个调用。

tool_choice 应该怎么选?

默认 auto 允许模型不调用、调用一个或多个工具;required 要求至少调用一个;也可强制指定函数、限制 allowed_tools,或用 none 禁止工具。生产环境应只暴露当前步骤真正允许的工具。

为什么回传工具结果后模型没有给最终答案?

工具调用是循环而不是固定两步。模型可能继续请求其他工具;应用要反复处理 function_call,直到没有新调用,再读取最终 message/output_text,并设置最大步数避免死循环。

Function Calling 与 Structured Outputs 有什么区别?

Function Calling 用于让模型请求外部动作或数据;Structured Outputs 用于约束模型最终文本结果的 JSON 形状。两者都可使用 strict Schema,但调用循环、call_id 和工具执行只属于 Function Calling。

先把调用闭环跑通,再增加工具

从一个只读、无副作用的工具开始,验证 strict、call_id、多调用、超时和日志;通过后再逐步开放写操作。

实时语音中的工具调用

Realtime 仍需由后端校验参数、权限和幂等,再回传工具结果;建连、VAD 与打断状态机见 Realtime API 指南。