OpenAI Agents API 发布后,AI Agent 为什么更需要 JSON?从 Agent Harness、Tool Calling 到 JSON Schema

截至 2026 年 9 月 18 日:Agents API 公测把 Codex Harness 托管了。循环不归你写之后,你还握着的几乎全是 JSON——工具 Schema、arguments、tool_result、MCP、session 事件。合同松了,托管循环只会把坏参数跑得更勤。

先给结论:Agents API 把循环托管了,没有把合同托管。2026 年 9 月 10 日,OpenAI 把驱动 Codex 的 Agent Harness 以 public beta 交给开发者。模型调度、上下文压缩、子 Agent、沙箱生命周期,都从你的进程挪到了 beta.agents.sessions。你还握在手里的,几乎全是 JSON:function 工具的 JSON Schema、arguments、tool_result 的字符串、MCP 的 inputSchema、session 事件流。Harness 替你跑 loop,不等于替你校验字段。合同松了,托管循环只会把坏参数跑得更勤。

这篇按 2026 年 9 月 18 日写。本站已有《Agent 为什么离不开 JSON》《Tool Calling 为什么依赖 JSON Schema》《JSON Schema 会成为标准 Contract 吗》《MCP / Skills / Tools / Subagents》《MCP 是什么》。本文只回答:Agents API 发布之后,JSON 为什么更重要,而不是更不重要。

9 月 10 日到底发布了什么

OpenAI 的原话是:用驱动 Codex 的同一套 harness 和基础设施,给开发者一个托管的云端 Agent。公开文档把它放在 beta.agents 命名空间,请求要带 OpenAI-Beta: agents=v1。Harness 本身不另收费,你付的是模型 token、工具和沙箱时间。

一次 session 创建里,你提交的是一份 JSON:模型、指令、工具列表、环境、输入。官方示例用 gpt-6-astra,工具可以是 MCP、自定义 function、内置检索。环境可以是 none、openai_hosted,或接到 Blaxel、Cloudflare、Daytona、E2B、Modal、Vercel 这类自建 / 合作沙箱。多 Agent 用 multi_agent.enabled 和 max_concurrent_subagents 打开。

它不是又一个「请输出 JSON」的聊天接口。Responses API 还在;Agents SDK 还在。Agents API 收走的是循环本身:谁决定下一跳、何时压缩上下文、何时派子 Agent。公测期字段名仍可能改,但分层已经清楚:OpenAI 跑 harness,你提供工具合同和业务结果。

三套入口:Responses、Agents SDK、Agents API

2026 年 9 月,OpenAI 并排放着三条做 Agent 的路。混用之前先分清「循环跑在哪」:

入口循环跑在哪状态存在哪你还写什么
Responses API你的应用你自己拼 history / Conversations模型调用、工具回灌、整段 loop
Agents SDK你的进程SDK session + 你的存储审批、部署、仍可改 loop
Agents APIOpenAI 托管的 Codex harness服务端 session / turn / item工具定义、function 结果、环境选择;改不了 loop

单次补全继续用 Responses。要自己握审批和落盘,用 SDK。要把「跑几天的任务、压缩、子 Agent、沙箱」交给对方,用 Agents API。三条路的工具参数都还是 JSON Schema。差别是:前两条你还能在 loop 里加补丁;第三条补丁只能加在合同和回灌上。

Agent Harness 是什么,它不替你签什么

Harness 是夹在模型和副作用之间的运行时:读事件、选工具、喂结果、压缩上下文、在超长任务里保住进度。Codex 那一套现在开源可见,Agents API 则由 OpenAI 运维同一套逻辑,并随模型版本升级。公告里点名的能力包括自动 compaction、Tool search、Programmatic Tool Calling、并行 subagents。

它不签这几样东西:

  • 某个 customer_id 该不该存在、该不该是 UUID;
  • 你的函数该不该接受多余键;
  • MCP Server 的 inputSchema 松还是紧;
  • 回灌给模型的 output 是对象、字符串,还是一段聊天。

这些仍然是 JSON Schema 和你自己的二次校验。托管 harness 提高的是「循环能跑多久、能并行多少」;它不提高「这一跳参数是否合法」。把两者当成一回事,是这篇要拆开的第一层误会。

为什么托管之后 JSON 跳数反而更多

自己写 loop 时,坏 JSON 往往死在你这一侧:parse 失败、字段对不上,你就停。循环托管之后,失败被推迟、被复制、被送进更多通道:

跳载体谁生成谁必须校验
创建 sessionagent / tools / environment JSON你的应用你:提交前
function 定义JSON Schema(parameters)你的应用你:收紧 required / additionalProperties
模型发起调用arguments 对象托管 harness + 模型你:执行前再验一遍
回灌结果tool_result.output 字符串你的应用你:先 stringify 合法值
MCPJSON-RPC + inputSchemaServer / harnessServer 与你的允许列表
事件流agent.session.* JSON 事件托管服务你:按 type 分支,不要当聊天正文 parse

再加上 Tool search 按需加载定义、Programmatic Tool Calling 在代码里串并行调用、subagent 各自带一份上下文——一次用户任务里的 JSON 往返,比「单次 Function Calling」多一截。托管让这些跳对你不可见,不可见不等于可以不校验。数据流的逐跳拆解见《从 Tool Calling 到 MCP》。

Tool Calling:function 工具仍是 JSON Schema

Agents API 的 function 工具和 Responses API 用同一套定义。你交给 agent.tools 的不是一段自然语言,而是名字、说明、一份 JSON Schema:

{
  "type": "function",
  "name": "get_customer",
  "description": "Look up a customer by ID.",
  "parameters": {
    "type": "object",
    "properties": { "customer_id": { "type": "string" } },
    "required": ["customer_id"],
    "additionalProperties": false
  }
}

官方示例把 required 写满,并把 additionalProperties 设为 false。这不是排版习惯。Agent 一旦被允许多写一个键,那个键就可能变成路径、SQL 片段或「顺便删除」。Schema 是模型在解码时看到的合同,也是你在执行前应再跑一遍的合同。严格模式、ajv、二次校验的流水线见《Tool Calling 为什么依赖 JSON Schema》。

描述字段仍然有用,它帮模型选工具;它不能代替类型、枚举和必填。Harness 越聪明,越会在一堆工具里挑一个「差不多」的——差不多的调用,只能靠 Schema 挡下来。

requires_action 与 tool_result:回灌也是 JSON

模型要跑你的函数时,session 停在 agent.session.requires_action。待处理项在 required_actions 里,而不是「历史里有一条 function_call」就算数。一条典型的 pending 调用是:

{
  "type": "function_call",
  "turn_id": "turn_123",
  "call_id": "call_123",
  "name": "get_customer",
  "arguments": { "customer_id": "123" }
}

文档把 arguments 写成对象。不要把它再包进聊天回复里用 JSON.parse 抠——那是上一篇《JSON.parse 为什么失败》的通道错误。你要做的是:用同一份 Schema 校验这个对象,执行函数,然后往 session 事件接口回 agent.session.input.tool_result,带上原来的 turn_id / call_id。

成功时 success: true,output 是字符串或受支持的内容数组。对象要先 JSON.stringify。失败时 success: false,给模型一段能读的 error。不要把堆栈、密钥、整份数据库行回灌回去。进程若在执行后、回灌前崩溃,应按 session / turn / call 做幂等:重启后先读 pending,再决定是否重跑。

Function 始终在你的应用里跑,即使 session 带了沙箱。Harness 不会替你执行 get_customer。你不在线,这一跳就挂起。这是托管循环里,少数仍然完全属于你的同步点——也是你必须把 JSON 做对的那一跳。

Tool search 与 Programmatic Tool Calling

工具一多,把全部 Schema 塞进上下文会烧 token、打缓存。Agents API 默认急切加载 function;不常用的可以 defer_loading: true,并在 agent.tools 里放 {"type": "tool_search"}。模型先搜到相关定义,再调用。于是多出一跳「定义本身也是 JSON」:搜到的 Schema 必须和你真正实现的函数一致,不能搜到一份宽合同、执行一份窄实现。

Programmatic Tool Calling 让受支持的模型写一小段代码,并行或串联合格工具,再只把过滤后的结果带回上下文。这降低了「每一跳都占满窗口」的成本,提高了「中间 JSON 必须合法」的要求。中间结果若类型漂移,后面的过滤和合并会在你看不见的 harness 里静默错下去。SDK 一侧已经出现「把结构化错误编码成 JSON」的修补,说明这条路径吃的就是 Schema,不是散文。

MCP 与 Subagents:更多 Schema,更多 JSON

把 MCP Server 写进 agent.tools,harness 负责发现工具、发起调用、把结果喂回模型。和 function 不同:这些调用不经过你的应用。HTTP 默认由 OpenAI 连;也可以指定从环境连,或在沙箱里用 stdio 拉起进程。你在这一层能做的,是 allowed_tools、初始化失败是否让 turn 失败(required: true),以及 Server 自己的 inputSchema 有多紧。

MCP 的报文仍是 JSON-RPC。Schema 松,托管 harness 会替模型打出更多你看不到的请求。这不是「协议帮你安全了」,是「循环离你更远了」。协议分层见《MCP 是什么》;和 Skills、Subagents 的边界见《2026 Agent 栈》。

Subagents 各自一份上下文,主 Agent 汇总。并行能降延迟,也会并行打出多份 arguments。主 Agent 拿到的汇总若仍是无 Schema 的长文本,你只是把「解析聊天」推迟到了最后一跳。要进程序的结论,最终答复仍应走 Structured Output 或一份你定义的结果 Schema,而不是再从散文里抠。见《Structured Output 是什么》。

你还要在本地校验的四件事

Harness 托管之后,清单不是变短,是变窄:

  1. 工具 Schema。required 写满,additionalProperties: false,枚举收紧。不要靠描述词拦副作用。
  2. 执行前的 arguments。厂商说过 Schema,仍要在你的进程里用同一份再验。类型错、缺字段、多出来的键,这一层拦。
  3. 回灌的 output。先做成合法 JSON 再 stringify。错误走 success: false,不要把内部异常原文丢给模型。
  4. 事件与聊天正文分通道。读 event.type,不要把整段 SSE 当 JSON 值。最终对用户的结构化答复,用 Structured Output,不要 JSON.parse 助手句子。

安全一侧还要记得:arguments 里的字符串可能是注入,不是「类型对了就执行」。见《恶意 JSON 与 Prompt Injection》。JSON Schema 会不会成为跨厂商合同,见《标准 Contract》——Agents API 没有削弱这个判断,它把它推到了你唯一还能改的那一层。

用本地 JSON 工具看合同

接到托管 session 之前,先在浏览器里看三份文本:工具 Schema、一条样本 arguments、你准备回灌的 output。

  • JSON 校验 — 文法是否合法;有 Schema 就一起核字段、必填、多余键。
  • JSON 格式化 — 把压成一行的 tool_result 展开,看你是不是把整行数据库序列化回去了。
  • JSON Diff — 对比「模型传来的 arguments」和「Schema 允许的最小对象」。

数据不离开浏览器。适合把一份失败的 required_actions、一份 parameters、一次 stringify 后的结果放在一起看。合同稳定了,再交给 hosted harness 去跑几天。

常见问题 FAQ

Agents API 是不是让我不用再写 JSON Schema 了?

正好相反。循环被托管之后,Schema 是你还握着的主合同。function 的 parameters、MCP 的 inputSchema、回灌的 output,都还是 JSON。

Agents API、Agents SDK、Responses API 该怎么选?

单次调用用 Responses。要自己握 loop、审批和存储,用 SDK。要把长任务、压缩、子 Agent、沙箱交给 OpenAI,用 Agents API。三条路的工具参数都是 JSON Schema。

arguments 已经是对象,还要不要 JSON.parse?

不要把整段聊天再 parse 一遍。按文档把它当对象,用同一份 JSON Schema 校验。从散文里抠 arguments,是通道用错了。

tool_result 为什么必须 stringify?

文档要求 output 是字符串或受支持的内容数组。对象先做成合法 JSON 再 stringify,避免二次编码和「看起来像对象、其实是字符串」混用。

MCP 工具会经过我的应用吗?

默认不会。harness 直连 Server。你要收紧的是 Server 自己的 inputSchema、allowed_tools,以及不可逆操作在 Server 内的审批。

公测期字段会不会改?

会。这篇按 2026 年 9 月 18 日的公开文档写。分层不会改:harness 跑循环,你提供 JSON 合同。字段名变了,校验责任还在你这边。

总结

Agents API 降低的是「如何跑完一个 Agent」的工程量,提高的是「每一跳 JSON 必须正确」的权重。9 月 10 日交出的是 Codex harness:session、压缩、工具搜索、程序化调用、子 Agent、沙箱。它不检查你的 customer_id 该长什么样,也不替你把 tool_result 编成合法字符串。

2026 年把 Agent 接到程序,顺序没有变:工具走 JSON Schema,结果走 Structured Output,聊天正文不要当 API。变的是,loop 一旦托管,你能打补丁的地方只剩合同。先在本地校验工具里看 Schema、arguments 和回灌结果,再交给 hosted session 去跑。模型会换,harness 会改版本;你的字段合同不应跟着一起松。