模型返回工具调用,只是在请求你的应用执行动作;它不等于业务已经完成。应用需要校验参数、调用允许的函数,再把结果连同正确的 call_id 送回模型,直到得到可展示输出或达到停止条件。
适用前提
以下针对 OpenAI Responses 的自定义函数工具。模型和供应商必须支持该功能;本文不包含真实模型调用,示例的目录查询完全使用本地固定数据。
先检查你在哪一步停住
一条闭环应有工具定义、模型返回的 function_call、应用执行记录、function_call_output 和后续模型响应。不要只检查“tools 参数被接受”。如果只记录函数名却没回传结果,模型没有机会基于结果回答;如果 call_id 对错了,结果就不能可靠关联到原调用。官方函数指南说明了这两类对象的对应方式。
官方依据:来源 1
把模型输出当作不可信输入
函数名称必须命中白名单,arguments 必须能解析为 JSON 并满足应用自己的约束。strict schema 能约束接口形状,但不能替代权限判断、业务校验和预算控制。查询工具宜先只读;需要外部副作用的动作,应在真正执行前走应用既有授权流程。不要把模型给出的函数名直接当文件路径、SQL 或命令运行。
一段可直接运行的本地闭环
将代码保存为 tools-demo.mjs 并运行 node tools-demo.mjs。mockModel 代表合成模型响应;示例刻意保留完整 output 后再加入结果,避免把其他上下文项丢掉。这里不验证真实模型能力,只验证应用能正确关联调用与结果。
const tool = {type:'function', name:'lookup_doc', strict:true,
parameters:{type:'object', properties:{slug:{type:'string'}},
required:['slug'], additionalProperties:false}};
const history = [{role:'user', content:'查找入门文档'}];
function mockModel(input) {
const result = input.find(x => x.type === 'function_call_output');
return result
? {output:[{type:'message', text:JSON.parse(result.output).title}]}
: {output:[{type:'function_call', call_id:'demo-call-1',
name:tool.name, arguments:JSON.stringify({slug:'intro'})}]};
}
let final;
for (let turn=0; turn<3; turn++) {
const response = mockModel(history);
history.push(...response.output);
const calls = response.output.filter(x => x.type === 'function_call');
if (!calls.length) { final = response; break; }
for (const call of calls) {
if (call.name !== 'lookup_doc') throw new Error('工具不在白名单');
const args = JSON.parse(call.arguments);
if (!args || Array.isArray(args) || typeof args !== 'object' ||
Object.keys(args).length !== 1 || args.slug !== 'intro')
throw new Error('参数不符合本地目录约束');
history.push({type:'function_call_output', call_id:call.call_id,
output:JSON.stringify({title:'API 接入指南(演示)'})});
}
}
if (!final) throw new Error('超过最大工具轮次');
console.assert(final.output[0].text === 'API 接入指南(演示)');
console.log(final.output[0].text);换成真实接口时的验收清单
真实集成需要把工具定义传给已确认支持的接口,再按 SDK 返回类型处理完整 output。对带推理上下文的响应,按官方要求保留相应项,不只摘出函数调用。不要假设一轮只会调用一个工具,也不要假设下一轮必定是最终回答。
- 正常只读参数能查到结果,并且回传 call_id 与原调用相同。
- 未知函数、非法 JSON、缺字段、越权参数在执行前被拒绝。
- 并行调用分别关联结果;轮次、工具耗时和输出大小都有上限。
- 最终回答与实际工具返回相符;没有工具执行记录时不显示“已完成”。
官方依据:来源 1
失败时要恢复哪个环节
解析失败应停止该次执行或回传受控的错误说明,不能随意补默认参数继续执行。工具超时要区分“没执行”和“可能执行但响应丢失”;后者先查业务状态。回传失败时保存脱敏调用标识,重试不得重新制造副作用。必要时退回普通文本回答,明确告诉用户操作未完成,而不是把工具参数当作结果显示。
2026-10-21 阅读下列官方资料。操作步骤为本站编辑归纳,代码与数字为本地合成示例;未调用付费模型,不是服务商实测报告,也不构成接口或性能承诺。