OpenAI Responses API 怎样让模型调用自定义函数
我们拿开发时经常用到的「查询项目发布状态」场景做演示,你可以直接把自定义的函数作为工具声明传给OpenAI Responses API,就能让模型自动判断什么时候需要调用工具、传什么参数,不需要自己手动处理多轮上下文的来回拼接,上手门槛很低。
直接把自定义函数的名称、参数结构、功能说明按规范格式放到tools请求字段里,调用API后模型会自行判断是否触发函数,拿到返回结果后再整理成自然语言回复用户。
让 OpenAI Responses API 调用自定义函数,关键不是把函数代码发给模型,而是把“函数契约”放进 tools,再由你的应用接住模型返回的 function_call、执行本地函数,最后提交对应的 function_call_output。这是一条明确的往返链路:模型决定调用什么,你的服务决定是否真的执行。
官方文档:https://developers.openai.com/api/docs/guides/tools
最小闭环可以概括为:定义一个type: "function"工具,读取response.output中的function_call,用它的call_id回传执行结果,再请求一次 Responses API。模型不会直接访问你的数据库或业务函数。
先写一个最小可用的函数工具
下面用 get_project_status 作为示例:模型只负责根据用户问题填出项目名,真正的状态查询由应用里的 getProjectStatus 完成。Responses API 的函数工具可以直接写成 type、name、description、parameters 和 strict 这些字段。
const tools = [
{
type: "function",
name: "get_project_status",
description: "查询指定项目当前的发布状态。",
parameters: {
type: "object",
properties: {
project: {
type: "string",
description: "项目标识,例如 billing-api"
}
},
required: ["project"],
additionalProperties: false
},
// strict 让模型生成的参数遵守上面的 JSON Schema。
strict: true
}
];
这里的 description 要写成模型能理解的业务边界,参数名也要保持稳定。开启严格模式时,对象需要显式设置 additionalProperties: false,并把属性列入 required;如果某个业务字段可以缺省,可以把它声明为允许 null,而不是遗漏必填声明。

把工具交给 Responses API
工具定义完成后,在第一次请求里把它放到 tools。默认情况下,模型会自己判断是否需要调用工具;如果一次业务只允许一个本地动作,可以同时设置 parallel_tool_calls: false,让这一轮最多出现一个函数调用。
import OpenAI from "openai";
const client = new OpenAI();
const response = await client.responses.create({
model: "gpt-6-astra",
input: "请告诉我 billing-api 当前是否可以发布。",
tools,
// 关闭并行调用,便于这个单动作示例按一个函数处理。
parallel_tool_calls: false
});
console.log(response.output);
如果希望强制模型调用某一个工具,可以进一步使用 tool_choice;但一般的业务问答先使用默认的自动选择更自然。工具数量较多时,也要让每个函数的描述互相区分,避免模型面对多个相似入口时难以选择。
识别 function_call 并执行本地函数
响应的 output 不是一段固定文本数组,其中可能出现类型为 function_call 的项目。这个项目包含函数名、JSON 编码的 arguments 和后续回传必须使用的 call_id。应用先解析参数,再按函数名路由到白名单实现。
function getProjectStatus(project) {
// 真实项目中可在这里访问受控的数据库或内部服务。
const known = {
"billing-api": { state: "ready", blockers: 0 },
"search-api": { state: "blocked", blockers: 2 }
};
return known[project] ?? { state: "unknown", blockers: null };
}
function callFunction(name, args) {
// 只允许显式列出的函数名,避免把任意输入当作可执行入口。
if (name === "get_project_status") {
return getProjectStatus(args.project);
}
throw new Error(`未知函数:${name}`);
}
const functionCalls = response.output.filter(
(item) => item.type === "function_call"
);
for (const toolCall of functionCalls) {
const args = JSON.parse(toolCall.arguments);
const result = callFunction(toolCall.name, args);
console.log(toolCall.call_id, result);
}
不要用 response.output_text 代替这一步,因为模型此时可能还没有最终回答。也不要根据函数名拼接任意方法调用;把可执行函数放进明确的路由表,未知名称和参数解析失败都应该进入应用自己的错误处理。

用原始 call_id 回传 function_call_output
执行结果需要作为新的输入项回传给下一次 Responses 请求。先把上一轮的 response.output 转成可继续使用的输入项,再追加一个与当前调用对应的 function_call_output。其中 call_id 必须来自原始函数调用,不能自己生成一个看似相近的编号。
import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";
const input = [
{ role: "user", content: "请告诉我 billing-api 当前是否可以发布。" }
];
// 保留模型这轮产生的完整 output,供下一次请求理解调用上下文。
input.push(...toResponseInputItems(response.output));
for (const toolCall of functionCalls) {
let output;
try {
const args = JSON.parse(toolCall.arguments);
output = JSON.stringify(callFunction(toolCall.name, args));
} catch (error) {
// 把可读错误作为工具结果交回模型,而不是让调用链静默中断。
output = JSON.stringify({
state: "error",
message: error instanceof Error ? error.message : "函数执行失败"
});
}
input.push({
type: "function_call_output",
call_id: toolCall.call_id,
output
});
}
const finalResponse = await client.responses.create({
model: "gpt-6-astra",
input,
tools,
parallel_tool_calls: false
});
console.log(finalResponse.output_text);
这次请求得到的 output_text 才是面向用户的最终回答。函数返回值最好是结构稳定、字段含义明确的 JSON 字符串;如果业务失败,也可以把失败状态作为工具结果交回模型,让它据此向用户解释,而不是把内部堆栈直接写进输出。
三个容易让调用链失效的边界
| 现象 | 优先检查 | 处理方向 |
|---|---|---|
| 模型没有调用函数 | 用户任务是否真的需要该工具,工具描述是否清晰 | 先保持默认自动选择;需要强制动作时再配置 tool_choice |
| 请求因 Schema 被拒绝 | strict、required 和 additionalProperties 是否匹配 | 补齐对象字段约束,可选值用允许 null 表达 |
| 回传后没有最终文本 | call_id 是否原样对应,是否把函数结果追加为新输入 | 保留完整 output item,再提交 function_call_output |
| 一轮出现多个调用 | 是否允许并行函数调用 | 单动作流程设置 parallel_tool_calls: false,批量任务再设计并行处理 |
最后要把“模型选择函数”和“应用授权执行”分开。模型输出的是建议调用及其参数,真正的权限校验、数据访问、超时、幂等和审计仍然属于你的应用。函数调用做得越接近真实业务,越应该在本地路由层再次检查参数,而不是只依赖模型给出的 JSON。
常见问题
模型会直接运行我写的 JavaScript 函数吗?
不会。模型只能输出符合工具契约的 function_call;你的应用要自行解析参数、调用本地函数,并把结果作为 function_call_output 发回。
为什么一定要保存 call_id?
它把函数结果和当前响应里的具体调用关联起来。尤其在允许并行调用时,不能只按函数名匹配结果,必须为每一个调用使用对应的 call_id。
strict=true 是否代表业务参数一定安全?
不是。严格模式主要约束输出参数符合 Schema;权限、资源范围、字段值合法性和业务副作用仍要由你的服务校验。
这条实现路径可以压缩成一句话:用 tools 声明契约,读取 function_call,由应用白名单路由并执行函数,再用原始 call_id 发送 function_call_output,最后读取新的 output_text。如果把并行策略、Schema 约束和业务授权都放在应用边界内,Responses API 的自定义函数调用就会变成一条可控的工程流程。
MySQL JSON_TABLE 数值与日期字段的类型转换和截断边界
- 上一篇
- MySQL JSON_TABLE 数值与日期字段的类型转换和截断边界
- 下一篇
- MySQL GET_LOCK 怎样实现同一任务的单实例执行
-
- 科技周边 · 人工智能 | 5小时前 |
- OpenAI API 怎样读取模型返回的使用量字段
- 234浏览 收藏
-
- 科技周边 · 人工智能 | 5小时前 | 人工智能 · OpenAI Batch API batch status 批处理任务 API状态查询
- OpenAI Batch API 怎样查询批处理任务状态
- 292浏览 收藏
-
- 科技周边 · 人工智能 | 5小时前 | Parquet Hugging Face Datasets shard to_parquet push_to_hub
- Hugging Face Datasets 导出 Parquet 时怎么控制分片大小
- 378浏览 收藏
-
- 科技周边 · 人工智能 | 5小时前 | PyTorch DataLoader IterableDataset get_worker_info
- PyTorch IterableDataset 怎样为每个 worker 分配不同数据片段
- 455浏览 收藏
-
- 科技周边 · 人工智能 | 5小时前 | python · 人工智能 · snapshot_download Hugging Face Hub HF_HUB_CACHE HF_HOME 模型缓存 huggingface_hub
- Hugging Face Hub 怎样用缓存目录管理模型文件
- 247浏览 收藏
-
- 科技周边 · 人工智能 | 5小时前 |
- Hugging Face Transformers 怎样用 ignore_mismatched_sizes 加载分类模型
- 113浏览 收藏
-
- 科技周边 · 人工智能 | 5小时前 |
- OpenAI API 怎样为请求设置幂等键
- 174浏览 收藏
-
- 科技周边 · 人工智能 | 5小时前 |
- OpenAI Responses API 怎样让长任务异步运行
- 327浏览 收藏
-
- 科技周边 · 人工智能 | 5小时前 | temperature top_p OpenAI API reasoning.effort max_output_tokens 采样参数
- OpenAI API 怎样用 temperature 之外的参数控制采样
- 131浏览 收藏
-
- 科技周边 · 人工智能 | 5小时前 |
- OpenAI API 怎样限制输出内容使用指定文本格式
- 268浏览 收藏
-
- 科技周边 · 人工智能 | 5小时前 |
- ONNX Runtime 怎样查看模型输入名称与形状
- 349浏览 收藏
-
- 科技周边 · 人工智能 | 16小时前 |
- Hugging Face Datasets IterableDataset batch 丢弃尾批的配置方法
- 297浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 720次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 728次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 804次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 767次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 604次使用
-
- CodeGeeX for Jetbrains IDEs正式上线!
- 2023-01-17 284浏览
-
- 技术阿里云实现ocr批量图片和pdf文件表格图片转换excel文档/支持票据图片提取/普通图片文字提取处理
- 2023-01-18 387浏览
-
- 直播预告|FeatureStore Meetup V2
- 2023-01-10 328浏览
-
- 深入浅出特征工程 – 基于 OpenMLDB 的实践指南(上)
- 2023-02-25 426浏览
-
- 开源机器学习数据库OpenMLDB v0.4.0产品介绍
- 2023-01-10 147浏览

