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 Completions 完整示例
以查天气为例,走完”定义 → 调用 → 执行 → 回传”全循环:Responses 完整示例
注意三处不同:tools 定义是扁平的、调用以顶层function_call item 返回、回传用 function_call_output。配合 previous_response_id,第 2 次请求不必重发全部历史:
strict 严格模式(结构化输出)
strict: true 让模型输出的参数严格符合你的 JSON Schema,杜绝幻觉字段和缺字段。三个要求:
- Schema 里必须有
"additionalProperties": false - 所有字段都要出现在
required里(可选语义用"type": ["string", "null"]表达) - 只能用受支持的 JSON Schema 子集(基本类型、enum、数组、嵌套对象等)
parallel_tool_calls 与 tool_choice
并行调用
parallel_tool_calls 默认开启,模型可以在一轮里同时请求多个函数(如同时查北京和上海的天气)。逐个执行后全部回传再发起下一次请求,每个结果都要带对应的 call_id(responses)或 tool_call_id(chat)配对。
tool_choice 控制策略
allowed_tools 限定子集
工具很多但本轮只想开放一部分时,用tool_choice 的 allowed_tools 形式限定可调用子集 —— 它不改变 tools 列表本身,因此不破坏 缓存 的稳定前缀:
流式中的函数调用
Chat Completions:按 index 拼接
函数参数在流式里是分片下发的,按index 累加 arguments 字符串,流结束后再 json.loads:
Responses:监听语义事件
response.function_call_arguments.delta 事件携带参数增量,response.function_call_arguments.done 给出完整参数,无需自己按 index 拼。
最佳实践与踩坑
写好工具定义:- 函数名和 description 是写给模型看的:说清楚”什么时候该调我”,比如
"获取实时天气,仅当用户明确询问天气时调用" - 参数用 enum 收窄:能枚举就别用自由字符串,幻觉参数会少一大半
- 工具定义放 prompt 前部且保持稳定:tools 会参与缓存前缀比对,定义稳定 = 输入费打 1 折(见 缓存计费)
- Agent 循环设最大轮数:避免模型在”调函数 → 回传 → 又调函数”里打转烧钱