OpenAI Agents API + JSON Schema 实战:如何让 AI Agent 输出稳定、可验证、可执行的 JSON 数据?
通用 Schema 文已经写过「为什么要契约」。本篇只落到 Agents API:模型填的每一段 JSON,都要先过门,再执行。工具参数、MCP 输入、你自己的账本,是三道门,不是一句「请输出 JSON」。
阅读前速览
| 门 | 锁什么 | 谁执行 |
|---|---|---|
| Function parameters | order_id、布尔、枚举 | additionalProperties: false |
| 宿主校验 | required_actions 里的 arguments | 不过门就不跑函数 |
| 最终卡片 | 给用户看的对象 | 另写 Schema;不是 text.format |
| MCP | 另一张工具表的 inputSchema | subagent 可继承 |
Schema 是门,不是礼貌。宽 object 等于多开一扇门。
稳定、可验证、可执行,是三道手续,不是一个开关
在 Agents API 里,模型仍然只填 JSON。官方 function 定义要带一份 parameters Schema:required、additionalProperties: false、必要时 pattern / enum。这让填充更稳。可验证是你在执行前,用同一份 Schema 再跑一遍 arguments。可执行是过门之后,宿主才产生副作用。
- 稳定:把工具参数写成严 Schema。宽
object等于请模型发明键。 - 可验证:
required_actions里的调用也要本地校验。历史里的 function_call 不够。 - 可执行:不过门就不跑
lookup_order。回写success: false和原因,不要默默改库。
工具怎么调,见 OpenAI Agents API 完整解析。四个对象怎么用 ID 相连,见 Agents API 的 JSON 数据结构。Schema / Function Calling / Structured Output 的通用分工,见 AI 为什么需要 JSON Schema。本篇不再重复那三个词的定义,只写 Agents session 上怎么落地。
第一道门:写在 agent.tools 里的 parameters
官方 function 条目是 name、description、一份 JSON Schema。创建 session 时写进 agent.tools。虚构订单,不要贴真实密钥:
{
"type": "function",
"name": "lookup_order",
"description": "Look up an order by ID. Confirm before any refund.",
"parameters": {
"type": "object",
"properties": {
"order_id": { "type": "string", "pattern": "^[A-Z]-\\d{4}$" },
"include_lines": { "type": "boolean" }
},
"required": ["order_id", "include_lines"],
"additionalProperties": false
}
}
要点就这几个:所有字段进 required;对象关掉多余键;单号用 pattern,不要只写 string。函数默认会预加载。要推迟加载,设 defer_loading: true,并在工具表里放 tool_search。门本身不变。
过不去的参数,不要执行
session 停在 agent.session.requires_action 时,required_actions 里会出现 function_call。下面这一份看起来像在查单,其实已经越门:单号不合 pattern,还多了一个 refund:
{
"type": "function_call",
"turn_id": "turn_2",
"call_id": "call_3c91",
"name": "lookup_order",
"arguments": {
"order_id": "1042",
"include_lines": true,
"refund": true
}
}
同一对 turn_id / call_id,过门的形状应当是这样。多一个键、少一个 required、pattern 漂了,都不该进执行:
{
"type": "function_call",
"turn_id": "turn_2",
"call_id": "call_3c91",
"name": "lookup_order",
"arguments": {
"order_id": "A-1042",
"include_lines": true
}
}
第二道门:宿主用同一份 Schema 再跑
官方 Schema 提高填充质量,但不替你承担副作用。执行前在本地再校验一次。失败写成对象,便于复盘:
{
"check": "lookup_order",
"schema": "parameters",
"pass": ["order_id", "include_lines"],
"fail": [
{ "path": "/order_id", "reason": "pattern" },
{ "path": "/refund", "reason": "additionalProperties" }
],
"execute": false
}
失败就向 events 端点回 agent.session.input.tool_result,success: false,error 写人能读的原因。成功才序列化 output 字符串。不要新开 session「重试」。
{
"type": "agent.session.input.tool_result",
"turn_id": "turn_2",
"call_id": "call_3c91",
"success": false,
"error": "order_id failed schema: expected ^[A-Z]-\\d{4}$"
}
最终卡片是第三道门,不是 Responses 的 text.format
给用户看的订单卡片,和工具参数不是同一份 Schema。Agents API 的 session 不会自动套上 Responses 那种 text.format.json_schema。三件事要分开写:
- 工具参数:锁副作用入口。查单、改库走这里。
- 最终卡片:你从 items 抽出对象后,用另一份 Schema 校验再展示。
- 若必须用 Structured Outputs 锁最终形状:那是 Responses 的层。不要混进同一条 session 资源。
循环该不该托管,见 Agents API vs Responses API。MCP 那一行只是另一张工具表,inputSchema 同样要 additionalProperties: false。边界见 MCP Tool Schema vs Function Calling。subagent 继承 MCP Schema,不继承你的 function。
五步把 JSON 收成可执行
不要从「请输出 JSON」开始。按门走:
- 先写工具 Schema。pattern、enum、required、additionalProperties: false 一次收紧。
- 同一份 Schema 放进宿主校验器。和官方 parameters 不要各写各的。
- required_actions 到了先校验再执行。不过门就回 success: false。
- 最终卡片另写 Schema。从 items 抽出对象后校验,不要把散文当卡片。
- 账本字段自己存。compact 会丢细节。金额、审批不要只活在对话里。
工作流怎么收成 Schema,见 JSON Schema 与 AI Agent 工作流。本篇只要求:Agents session 上,每道门都有对象。
复盘稳定输出,先摊开两段 JSON
漂了,多半是门没对齐,不是模型变笨。
- 把 parameters 和 arguments 格式化,看多余键和缺字段。
- 用 JSONPath 提取 抽出
order_id、$.parameters.required。 - 过门失败和成功的调用 JSON Diff。pattern 漂了先看 Schema,再怪模型。
- 最终卡片 Schema 和工具 Schema 分开审。锁卡片不锁参数,等于只装修门面。
- 订单、session、内网 MCP 不要贴进公共格式化站。JSONSort 在浏览器本地跑。
两段轨迹都能按 Schema 重建,你才是在收 JSON,不是在收散文。
常见误区
- 只在 instructions 里写「请输出 JSON」。那不是门。门在 parameters 和宿主校验器。
- required 只列一部分字段。没列的键,模型可以不填,下一跳就会空。
- additionalProperties 不写或写成 true。官方示例关掉多余键。多一个 refund,副作用就偏了。
- 把 Responses 的 text.format 抄进 Agents session。两套资源。最终卡片你自己校验。
- 校验失败还是执行了函数。可执行的前提是过门。先回 error。
- 让 subagent 跑你的 function。子代理不支持 function 工具。严 Schema 留在主 Agent。
FAQ
Agents API 有没有 Structured Outputs?
工具参数靠 JSON Schema 收紧。给用户看的最终对象,session 不会自动套 Responses 的 text.format。要锁最终形状,自己校验,或把那一跳放到 Responses。
官方 Schema 还要我再校验吗?
要。官方门提高填充质量。副作用发生在你的进程。required_actions 里的 arguments 过同一份 Schema,失败就 success: false。
pattern 和 enum 有必要吗?
有。string 太宽,模型会填 1042 而不是 A-1042。金额、状态用 enum 或明确格式。宽类型是最常见的越门方式。
MCP 工具要不要同一套纪律?
要。inputSchema 同样关掉多余键、列全 required。subagent 继承 MCP,不继承 function。查自家订单的门,留在主 Agent。
校验失败会不会把 session 卡死?
回同一对 turn_id / call_id 的 tool_result 即可。error 写清楚,模型可以改参数再调。不要另开 session 当重试。
结论
Agents API 上的稳定 JSON,不是更长的提示。它是三道门:工具 parameters、宿主再校验、最终卡片另写 Schema。可执行发生在过门之后。
先写清 A-1042 过不了哪一条规则。能指到路径,数据才算可验证。模型会换;门应该先稳定。
延伸阅读
- OpenAI Agents API 完整解析 Session、Tool Calling、Schema 怎么接
- Agents API 的 JSON 数据结构 Agent / Tool Call / Tool Result / Handoff
- Agents API vs Responses API 循环该由谁跑
- 长时间运行的 Agents API Session、compact、Subagents
- AI 为什么需要 JSON Schema Schema / Function Calling / Structured Output
- JSONSort 本地工具箱 格式化、校验、Diff
- 全部文章 更多 JSON 与 AI 开发笔记
更新记录: 首次发布