OpenAI API · JavaScript 工具编排 · 2026-11-01 核对

OpenAI Programmatic Tool Calling 怎么用?JavaScript 工具编排教程

让模型生成一段受控 JavaScript,在托管 V8 运行时中并行、循环和组合多个工具,只把完成任务所需的精简结果带回模型上下文。

主关键词:OpenAI Programmatic Tool Calling 怎么用官方资料核对:2026-11-01第三方中文指南
先给结论

在 Responses API 中加入 {"type":"programmatic_tool_calling"},再给允许程序调用的工具设置 allowed_callers:["programmatic"] 或 ["direct","programmatic"]。它适合有明确边界、能用代码过滤、连接、去重、聚合或验证多个工具结果的阶段;单次查询、逐步语义判断、审批敏感写操作和必须保留原生引用的任务,优先直接工具调用。

Programmatic Tool Calling 解决什么问题?

普通工具循环常把每次工具结果交给模型再决定下一步。结果多、字段大或控制流固定时,中间内容会反复进入上下文。Programmatic Tool Calling(PTC)让模型生成 JavaScript,把中间结果保留在运行时变量中,并在代码内完成并行调用、循环、条件分支与结构化压缩。

任务形态推荐方式原因
一个查询或一个动作直接 Function Calling没有必要增加程序层
多个结果要筛选、连接、排序、去重或聚合Programmatic Tool Calling代码可只返回较小结构
后续参数由前一步确定,流程与失败边界明确Programmatic Tool Calling代码可稳定派生参数
每个结果都会改变下一次搜索策略直接调用需要模型逐步判断
付款、删除、发消息等高影响写操作直接调用 + 明确审批保留授权边界与审计链
最终回答必须保留引用或原生文件直接调用除非程序能完整保留并验证证据

运行时边界:它不是 Node.js 容器

OpenAI 会为每段生成程序启动新的隔离 V8 运行时。它支持 JavaScript 和顶层 await,但官方明确说明没有 Node.js、包安装、直接网络访问、通用文件系统、子进程、console 或跨程序持久 JavaScript 状态。

  • 外部系统只能通过请求中已启用的 tools.* 访问。
  • 程序用 text(...) 或 image(...) 发出最终结果。
  • 客户端函数仍在你的应用服务器执行,V8 只负责编排。
  • 每次程序都要把必要状态从工具结果或当前响应项目中重新获得。

Responses API 最小配置

下面把库存和需求查询仅开放给 program。parameters 约束输入,output_schema 描述函数结果 JSON 的稳定字段;使用前仍需在官方模型页确认所选模型支持 PTC。

import OpenAI from "openai";

const client = new OpenAI();

const tools = [
  {
    type: "function",
    name: "get_inventory",
    description: "Return stock for one SKU.",
    parameters: {
      type: "object",
      properties: { sku: { type: "string" } },
      required: ["sku"],
      additionalProperties: false
    },
    output_schema: {
      type: "object",
      properties: {
        sku: { type: "string" },
        available_units: { type: "number" }
      },
      required: ["sku", "available_units"],
      additionalProperties: false
    },
    allowed_callers: ["programmatic"],
    strict: true
  },
  {
    type: "function",
    name: "get_demand",
    description: "Return requested units for one SKU.",
    parameters: {
      type: "object",
      properties: { sku: { type: "string" } },
      required: ["sku"],
      additionalProperties: false
    },
    output_schema: {
      type: "object",
      properties: {
        sku: { type: "string" },
        requested_units: { type: "number" }
      },
      required: ["sku", "requested_units"],
      additionalProperties: false
    },
    allowed_callers: ["programmatic"],
    strict: true
  },
  { type: "programmatic_tool_calling" }
];

const response = await client.responses.create({
  model: "gpt-6-astra",
  store: false,
  tools,
  input: "比较 sku_123 的库存与需求,只返回缺口摘要。"
});

allowed_callers 三种设置

配置调用方式适用场景
省略或 ["direct"]仅模型直接调用需要逐步判断、审批或查看原始结果
["programmatic"]仅 program 中调用返回结构稳定、只服务于有界处理阶段
["direct","programmatic"]两种方式都允许同一工具确实承担两个已明确的工作流阶段

不要只写“高效使用 PTC”。官方建议把路由写具体:哪个有界阶段使用程序、可用哪些工具、何时并行、程序最终必须输出什么结构、停止条件、重试次数,以及哪些判断或审批必须回到直接调用。

output_schema 为什么重要?

程序会直接读取工具返回字段;如果结果只是自然语言,模型生成的 JavaScript 可能猜错字段或解析失败。为可预测结果定义 output_schema,并把实际对象编码为 function_call_output.output 字符串。若返回形态不可预期,就不要强行程序化,改用直接调用让模型查看结果。

  • 返回紧凑结构,不要把大段无关日志塞给程序。
  • 记录明确的错误字段、可重试类型和终止条件。
  • 需要证据时,把证据字段写入程序最终结果 Schema。
  • 函数尽量幂等,避免重放或重试重复产生副作用。

识别 program、function_call 与 program_output

PTC 不会创建新的响应信封,仍返回标准 Responses 对象。response.output 可能包含以下顶层项目:

项目关键字段应用动作
program生成代码、call_id、fingerprint保存完整响应项目,等待嵌套调用或结果
function_call自己的 call_id;caller.caller_id 指向 program应用执行客户端函数
program_outputprogram 的 call_id、result、completed/incomplete校验结果结构与状态
message最终文本或 refusal到达时才结束循环

客户端函数回传循环

你的应用仍要运行每个客户端函数,并把结果送回正确的 program。回传时保留函数的 call_id,还要原样复制 caller;否则服务无法恢复对应程序。

const calls = response.output.filter(
  (item) => item.type === "function_call"
);

const outputs = await Promise.all(calls.map(async (call) => ({
  type: "function_call_output",
  call_id: call.call_id,
  caller: call.caller,
  output: JSON.stringify(
    await implementations[call.name](JSON.parse(call.arguments))
  )
})));

// store:false:继续请求时按原顺序重放完整 response.output,
// 再追加 outputs;不能只保留 function_call。

循环要处理暂停多次、incomplete 状态和无待处理函数但尚未出现最终 message 的情况。存储响应可使用 previous_response_id;store:false 时要完整重放 program、reasoning、function_call、function_call_output 与 program_output。最终只在收到 message 后读取 response.output_text 或 refusal。

程序适合怎样编排工具?

const [stock, demand] = await Promise.all([
  tools.get_inventory({ sku: "sku_123" }),
  tools.get_demand({ sku: "sku_123" })
]);

text(JSON.stringify({
  sku: stock.sku,
  available_units: stock.available_units,
  requested_units: demand.requested_units,
  shortage_units: Math.max(
    demand.requested_units - stock.available_units,
    0
  )
}));

这类流程适合 PTC,因为两个只读调用可安全并行,字段稳定,最后只需返回四个数字。若下一步要根据语义质量决定搜索方向,或要修改库存,则应退出程序阶段,由模型直接判断并由应用审批写操作。

与 Tool Search 怎样配合?

Tool Search 先解决“大目录里要加载哪些工具”,PTC 再解决“已加载工具如何用代码编排”。Tool Search 是顶层工具,正在运行的 JavaScript 不能直接搜索工具。

  1. 函数、custom 或 MCP 先设置 defer_loading:true。
  2. 模型在顶层执行 Tool Search 并加载需要的定义。
  3. 工具还需允许 allowed_callers 包含 programmatic。
  4. 后续 program 才能通过 tools.* 调用它们。

支持的工具与审批边界

官方当前列出的可编程调用类型包括 function、custom、MCP、Apply Patch、本地和托管 Shell、Code Interpreter。MCP 的 require_approval 可以暂停程序等待审批。工具进入 program 不会改变它真正运行的位置:Shell 仍在沙箱,MCP 仍连接相应服务器,函数仍由你的应用执行。

程序编排不等于获得权限

应用必须逐个校验参数、租户、资源范围和调用权限。付款、删除、写库、外发消息、代码发布等高影响动作保留应用级审批;即使工具允许 programmatic,也不能把模型生成代码当作授权。

ZDR 与数据保留要单独核对

Responses API 的 PTC 可以支持 Zero Data Retention 工作流,而且不要求持久代码执行容器,但 ZDR 必须先为组织或项目启用。store:false 只代表无状态续接,并不会自动启用 ZDR;最终资格取决于完整请求中的模型、工具和第三方服务。

如何评测成本与质量

PTC 可能减少进入模型上下文的中间工具输出,但不能只看 Token。先以直接调用建立基线,再用相同真实任务比较:

  • 最终答案正确性、完整性和证据覆盖。
  • 输入 Token、总 Token、端到端延迟和总成本。
  • 模型轮次、工具调用数、重试与恢复次数。
  • 副作用、审批、越权和错误降级结果。
  • 实际走的调用路径是否符合设计阶段。

常见错误与排查顺序

  1. 没有 program:确认模型支持,并在 tools 中加入 programmatic_tool_calling。
  2. 工具不可用:检查 allowed_callers 是否包含 programmatic;延迟工具是否已经先由 Tool Search 加载。
  3. 字段为 undefined:检查 output_schema 和实际 output JSON 是否一致。
  4. 程序无法恢复:回传时是否保留原 call_id 与 caller。
  5. 无限续接:明确停止条件、最大轮次、重试和 incomplete 处理。
  6. 结果缺证据:把必需证据字段写进程序最终结果,不要只返回结论。
  7. 出现越权写入:缩小 allowed_callers,把高风险动作改为直接调用和审批。

上线前检查清单

  • 在官方模型页确认生产模型支持 Programmatic Tool Calling。
  • 逐个标注工具是 direct、programmatic 还是两者,默认最小授权。
  • 为稳定工具结果定义 output_schema、错误形态和幂等行为。
  • 循环完整处理 program、caller、function_call、program_output、message 和 incomplete。
  • 限制程序可用工具、最大轮次、重试、超时和结果大小。
  • 用直接调用基线比较质量、证据、Token、延迟、成本与安全。
  • 对写操作、审批、引用与原生文件保留直接验证路径。

常见问题

OpenAI Programmatic Tool Calling 和普通 Function Calling 有什么区别?

普通 Function Calling 通常由模型逐次选择工具,应用执行后再把结果交回模型;Programmatic Tool Calling 让模型先生成 JavaScript,在托管 V8 运行时中并行、循环或组合多个符合条件的工具,并只把压缩后的程序结果送回模型。单次查询或每一步都需要语义判断时仍优先直接调用。

Programmatic Tool Calling 的 JavaScript 能使用 Node.js、网络或文件系统吗?

不能直接使用。官方说明每次程序都运行在新的隔离 V8 环境,支持顶层 await,但没有 Node.js、安装包、直接网络、通用文件系统、子进程、console 或跨程序持久状态。程序只能通过请求中允许的 tools.* 调用外部能力,并用 text(...) 或 image(...) 输出。

allowed_callers 应该怎么设置?

省略或设置为 direct 时工具只能直接调用;programmatic 表示只能由 program 调用;同时列出 direct 和 programmatic 表示两种方式都允许。应按具体工作流阶段授权,不要为了方便把所有写操作都开放给 program。

为什么建议给函数增加 output_schema?

parameters 约束输入,output_schema 描述 function_call_output.output 字符串中编码的 JSON 结构。程序需要稳定字段做过滤、聚合和计算时,明确输出 Schema 可减少猜测;如果返回结构不可预测,保留直接调用,让模型先查看结果。

应用怎样继续 program 发起的客户端函数调用?

应用仍负责执行客户端函数。回传 function_call_output 时必须保留原 function_call 的 call_id,并原样复制 caller,让服务知道该结果属于哪个 program。继续请求直到出现最终 message;store:false 时还要按顺序重放 program、reasoning、调用、输出和 program_output 等完整项目。

Programmatic Tool Calling 可以和 Tool Search 一起用吗?

可以,但 Tool Search 是顶层 Responses 工具,不能从正在运行的 JavaScript 内部调用。defer_loading 的函数、custom 或 MCP 工具必须先由模型搜索并加载;之后的 program 才能通过 tools.* 调用同时允许 programmatic 的工具。

Programmatic Tool Calling 一定会更省 Token、更快吗?

不保证。它可能把大型中间结果留在运行时并返回较小结构,但生成代码、暂停恢复、重试和错误处理也有成本。应以直接调用为基线,比较正确率、证据完整性、输入和总 Token、端到端延迟、工具调用数、重试及安全结果。

官方资料

需要执行终端命令?

如果任务需要多语言命令、文件转换或自有运行环境,请参阅 OpenAI Shell 工具教程;先区分托管容器与本地执行,并按最小权限限制文件、网络和命令。

本文核对日期为 2026-11-01。模型支持、工具类型、响应项目、ZDR 资格和 SDK 辅助函数可能调整;生产上线前请重新读取 Programmatic Tool Calling、Tools、Deployment checklist 与模型页。

先从只读、有界工作流做 A/B 基线

选择两个返回稳定 JSON 的只读工具,用同一批真实任务比较直接调用和 PTC 的正确率、证据、Token、延迟与单位成功成本,再决定是否扩大范围。