OpenAI 在 2026 年 7 月 9 日发布 GPT-5.6 家族时加入了 Programmatic Tool Calling(PTC)。传统工具调用是“模型决定一次、应用执行一次、结果再交给模型”;PTC 则允许模型生成一段 JavaScript,在托管的隔离运行时中并行调用工具、循环处理结果、执行条件分支,最后只返回压缩后的结构化结论。示例只展示请求结构,不发送付费请求。

先判断任务是否适合 PTC

PTC 适合控制流可预测、工具结果很多、且代码能完成过滤、连接、排名、去重、聚合或校验的阶段。例如同时查询多个仓库的测试结果,再按失败类型分组。它不适合每一步都需要语义判断的探索式搜索,也不适合付款、删除、发布等需要审批的写操作。一次查询用直接调用更清楚;有副作用的动作也应保留为直接调用,让应用在参数确定后建立授权边界。

这与普通并行工具调用也不同。仅仅“有三个调用”不足以启用 PTC。真正的收益来自减少模型往返和中间上下文:程序先把大结果压缩为一个有证据的小对象,再让模型解释。

配置一个只读工具阶段

请求中加入 programmatic_tool_calling,并用 allowed_callers 明确哪些工具可以被程序调用。可预测的返回值还应声明 output_schema,否则生成的 JavaScript 不知道字段是否稳定。

const tools = [
  {
    type: "function",
    name: "get_build_status",
    description: "Return repo, branch, status and failed_tests.",
    parameters: {
      type: "object",
      properties: { repo: { type: "string" } },
      required: ["repo"],
      additionalProperties: false
    },
    output_schema: {
      type: "object",
      properties: {
        repo: { type: "string" },
        status: { type: "string" },
        failed_tests: { type: "array", items: { type: "string" } }
      },
      required: ["repo", "status", "failed_tests"],
      additionalProperties: false
    },
    allowed_callers: ["programmatic"],
    strict: true
  },
  { type: "programmatic_tool_calling" }
];

const response = await client.responses.create({
  model: "gpt-5.6-terra",
  input: orchestrationPrompt,
  tools,
  store: false
});

生产工具还要在服务端重新校验参数、租户和资源范围。allowed_callers 只是调用路径配置,不是授权系统。即使模型生成的程序位于隔离环境中,工具本身仍可能访问真实系统。

把编排契约写进提示词

不要只说“高效使用 PTC”。应明确限定阶段、可用工具、输出形状、并发规则、重试次数、停止条件和直接调用的交接点。

只在“汇总构建状态”阶段使用 PTC,只能调用 get_build_status。
并行查询给定仓库,每个仓库最多一次;瞬时失败最多重试一次。
返回 {total, passed, failed, evidence[]},evidence 保留仓库和失败测试。
禁止写操作。缺少必填字段时返回结构化失败,不得猜测。
最终发布或重跑构建必须改用直接工具调用并等待批准。

这个契约让失败可观察,也避免程序与直接调用来回切换、重复已经完成的工作。

模型与成本也要固定版本

gpt-5.6 别名指向 Sol;Sol 面向前沿能力,Terra 平衡能力与成本,Luna 面向高吞吐。不要因为 PTC 可用就默认选择最强档,应在同一评测集上比较三档。8 月 21 日调整后,Sol 的标准文本价格为每百万输入 token 4 美元、输出 20 美元。价格不是永久常量,生产记录应保存实际模型、账单数据、评测日期、缓存 token、工具费用与总延迟。

正确处理暂停与续接

PTC 仍返回标准 Responses API 对象。输出数组可能出现 program、由程序发起的 function_call,以及最终的 program_output。应用执行自己拥有的函数后,必须把原始 call_idcaller 关系随结果一起返回。若使用 store: false,续接时需要重放响应条目;若保存响应,则可使用 previous_response_id。出现未完成状态、超时或缺失字段时应停止或进入受限重试,不能把半成品当成成功。

托管运行时是全新的隔离 V8:支持顶层 await,但没有 Node.js、包安装、直接网络、通用文件系统、子进程、控制台或跨程序持久状态。外部访问只能经过请求里开放的工具。这个限制减小了攻击面,却不能替代工具权限、参数验证和审计日志。

验收时同时看两层输出

program_output 正确,不代表最终回答一定完整。模型可能在最终消息中遗漏字段、证据或限制。因此应在同一批代表性任务上比较直接调用与 PTC:先检查答案正确率和证据完整性,再比较 token、延迟、调用次数、轮次与重试。只有原有评测继续通过,资源下降才算改进。

我的建议是从一个只读、可回放、输出很大的聚合阶段开始。给工具定义严格输入输出,为程序设置调用和重试预算,把所有写操作留在直接调用之后。PTC 的价值不是让 Agent 获得更多权限,而是把确定性的工具编排从语言模型往返中抽出来,同时保留清晰的证据链与人工控制点。