AI 严选AIAICN / API FIELD GUIDE
工具集成

工具调用为什么没有最终答案?完成一次 call → result 往返

用不联网的完整工具调用示例,检查函数白名单、参数校验、call_id 对应与结果回传,避免只收到工具请求就结束。

AI 严选 · 编辑整理(AI 辅助) · 写于 · 资料核对

本文目录
  1. 先检查你在哪一步停住
  2. 把模型输出当作不可信输入
  3. 一段可直接运行的本地闭环
  4. 换成真实接口时的验收清单
  5. 失败时要恢复哪个环节
直接回答

模型返回工具调用,只是在请求你的应用执行动作;它不等于业务已经完成。应用需要校验参数、调用允许的函数,再把结果连同正确的 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 后再加入结果,避免把其他上下文项丢掉。这里不验证真实模型能力,只验证应用能正确关联调用与结果。

JavaScript · 本地合成示例,不联网、不消耗 API 额度
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。对带推理上下文的响应,按官方要求保留相应项,不只摘出函数调用。不要假设一轮只会调用一个工具,也不要假设下一轮必定是最终回答。

  1. 正常只读参数能查到结果,并且回传 call_id 与原调用相同。
  2. 未知函数、非法 JSON、缺字段、越权参数在执行前被拒绝。
  3. 并行调用分别关联结果;轮次、工具耗时和输出大小都有上限。
  4. 最终回答与实际工具返回相符;没有工具执行记录时不显示“已完成”。

官方依据:来源 1

失败时要恢复哪个环节

解析失败应停止该次执行或回传受控的错误说明,不能随意补默认参数继续执行。工具超时要区分“没执行”和“可能执行但响应丢失”;后者先查业务状态。回传失败时保存脱敏调用标识,重试不得重新制造副作用。必要时退回普通文本回答,明确告诉用户操作未完成,而不是把工具参数当作结果显示。

来源与适用边界

2026-10-21 阅读下列官方资料。操作步骤为本站编辑归纳,代码与数字为本地合成示例;未调用付费模型,不是服务商实测报告,也不构成接口或性能承诺。

  1. https://developers.openai.com/api/docs/guides/function-calling