同一个业务 Schema 在本地验证通过,接入 OpenAI、Gemini 和 Claude 后却出现拒绝、字段丢失或结果语义错误。
最快解法:共享业务层核心 Schema,但不要假设原始文件可以直接通用;应拆成“核心子集+供应商转换器+统一测试集”,分别验收语法支持、接口行为和业务语义。
这篇文章适合维护多模型适配层的平台工程师、负责 API 验收的测试人员,以及需要设计长期可维护 Schema 的架构师。
如果团队只调用单一模型、没有工具执行和下游写库流程,本文的完整验收链路可能暂时超出实际需要。
先固定验收时间表,再决定是否上线
在第 1 天,Schema 作者固定 $schema、$id、版本号、字段定义和业务说明;第 2 天,适配层开发者生成三家供应商的请求版本;第 3 天,测试团队使用同一批输入和负例执行回归;第 4 天,业务消费者复核事实、权限和数据库约束。
本周建议动作是:先不要把“接口返回了 JSON”当成通过条件,优先建立一份包含 6 类样例 的最小测试集,再根据三家文档逐项标记“支持、需转换、必须阻断”。
JSON Schema 官方当前发布版本是 Draft 2020-12,但它是通用规范,不是任何一家模型 API 的完整实现承诺。官方规范将 Core 与 Validation 分开定义,$ref、$dynamicRef、unevaluatedProperties、format 等行为也属于具体词汇的一部分,不能只看一个 $schema 标识就判断接口兼容。参考:JSON Schema 规范总览 与 Draft 2020-12 规范说明。
第一步:Schema 作者先划出真正需要的核心子集
Schema 作者的任务不是把所有 JSON Schema 关键字都写进去,而是证明每一个约束都对应明确的业务目的。没有业务价值的复杂组合,会增加供应商转换成本,也会让测试团队难以判断失败究竟来自模型、适配器还是定义本身。
| 验收对象 | 核心检查 | 通过条件 | 常见阻断原因 |
|---|---|---|---|
| 规范标识 | $schema、$id、版本号 |
版本可追踪,引用路径稳定 | 只写 Draft 版本,不固定业务版本 |
| 对象结构 | type、properties、required |
必填字段与数据库必填项一致 | 把所有字段都设为必填,导致拒绝率上升 |
| 值域 | enum、minimum、maximum、format |
每项约束可解释并可测试 | 把注释当成真正的值校验 |
| 数组 | items、长度限制、元素类型 |
元素结构可被三家接口表达 | 使用复杂元组或递归数组 |
| 引用 | $defs、$ref |
可展开、可定位、可回溯 | 供应商接口对引用支持不一致 |
| 未知属性 | additionalProperties |
明确是拒绝、保留还是兼容扩展 | 静默删除未知字段,改变业务含义 |
一个适合跨模型的核心 Schema,通常先保留对象、字符串、数字、布尔值、空值、必填字段、枚举和明确的引用关系。复杂条件可以先移到业务校验层,而不是强行塞进模型输出约束中。
例如,订单状态可以使用 enum 限定为 pending、paid、cancelled,但“订单已经支付后不能再次取消”并不是单纯的类型问题。它需要读取数据库状态、判断操作者权限,并检查当前操作是否幂等。
⚠️ 注意:本地 JSON Schema 验证器验证的是“Schema 与实例之间的规范关系”,模型接口处理的却是“生成约束+平台子集+模型行为”。两者通过,不代表三家接口都会接受同一请求。
Schema 作者还应明确 additionalProperties 的使用目的。若未知字段意味着潜在数据污染,应在边界处拒绝;若未知字段只是为了兼容未来版本,则应在下游保留、记录并限制可执行字段。不能为了让请求通过,直接在转换器中删除这个约束。
第二步:把三家接口支持范围做成适配矩阵
OpenAI 的 Structured Outputs 通过 json_schema 和严格模式约束模型输出,但官方文档明确指出,严格模式只支持 JSON Schema 的一个子集;API 参考也特别说明,严格函数调用同样不是完整规范实现。参考:OpenAI Structured Outputs 官方指南 与 OpenAI API Reference。
Gemini Structured Output 也只支持 JSON Schema 子集。当前官方文档列出了 type、properties、required、enum、items、prefixItems、数值边界、组合结构以及部分引用相关字段,但同时提醒复杂或深层嵌套 Schema 可能被拒绝。参考:Gemini Structured Output 文档 与 Gemini API 生成内容参考。
Claude 的工具调用接口则使用 input_schema 描述工具输入,调用结果由应用执行后再回传。它与 OpenAI 的响应格式约束、Gemini 的 responseSchema 并不是同一种参数包装方式,因此平台团队应把“Claude Structured Outputs”作为内部能力标签时,注明它实际对应的是工具输入 Schema、结构化抽取方案,还是另外的输出控制层。参考:Claude 工具使用官方文档。
| 能力维度 | OpenAI | Gemini | Claude |
|---|---|---|---|
| 主要接入位置 | json_schema、函数参数 |
responseSchema、结构化输出 |
工具的 input_schema |
| 是否等于完整 JSON Schema | 否,官方声明为子集 | 否,官方声明为子集 | 不应按完整规范推断 |
| 适配重点 | 严格模式、拒绝、函数参数包装 | responseMimeType、支持字段、复杂度 |
工具定义、调用块、结果回传顺序 |
| 典型失败 | 不支持关键字、严格模式报错 | Schema 被拒绝、字段约束不完整 | 工具调用结构或结果顺序错误 |
| 统一策略 | 生成供应商专用版本 | 生成供应商专用版本 | 使用工具输入适配器 |
这里的关键不是选出“兼容性最好”的一家,而是禁止适配层隐式猜测。转换器每删除、展开或改写一个字段,都应记录原始路径、目标路径、处理动作和风险级别。
建议为每个转换动作保留类似下面的记录:
{
"source_path": "$defs.Order.properties.items",
"target_path": "properties.items",
"action": "inline_ref",
"reason": "目标接口不接受当前引用写法",
"semantic_risk": "medium",
"manual_review": true
}
若转换器发现某个关键字无法表达,但该关键字承载了权限、金额、资源范围或状态转移含义,正确动作不是静默删除,而是阻断发布,或者把这条约束移到独立的业务校验器中。
第三步:供应商适配层按“可追踪转换”验收
多模型平台通常会遇到三类隐性成本。
第一类是参数包装差异:同一个业务对象,在一家接口中放在响应格式参数内,在另一家接口中放在工具定义内;字段名、嵌套层级和严格模式开关不同,导致仅靠复制请求体无法复用。
第二类是关键字降级风险:additionalProperties、$ref、组合结构、格式校验和递归引用,可能在某个平台被接受、在另一个平台被拒绝,或者被接受但只发挥部分作用。被静默删除后,接口看起来“成功”,业务约束却已经丢失。
第三类是版本漂移:模型名称、接口版本、SDK 版本和文档支持范围都会变化。测试报告必须记录 4 个版本信息:核心 Schema 版本、供应商转换器版本、接口版本、模型标识。
| 转换结果 | 处理方式 | 是否允许上线 |
|---|---|---|
| 语法等价,业务含义不变 | 自动转换并记录日志 | ✅ 可自动回归 |
| 结构可表达,但验证强度下降 | 生成警告并增加业务校验 | ⚠️ 需负责人签字 |
| 关键约束无法表达 | 保留原约束,阻断请求或拆分流程 | ❌ 不得静默降级 |
| 仅描述性字段变化 | 保留或重新组织 description |
✅ 可上线,但需抽样检查 |
| 引用无法稳定解析 | 展开引用或改用供应商专用 Schema | ⚠️ 需覆盖嵌套样例 |
对于 OpenAI Structured Outputs、Gemini Structured Output 和 Claude 的工具输入,适配器不应只检查 HTTP 状态码。至少还要检查:请求是否被接口接受、返回是否可解析、字段是否完整、未知属性是否按预期处理、转换日志是否能回到原始 Schema 路径。
在这一步,平台工程团队可以把 多模型 API 适配层设计 作为内部文档入口,重点记录供应商差异,而不是把三家请求格式硬编码在业务服务中。
第四步:测试人员用统一样例集区分三种失败
跨模型 JSON Schema 自动化测试,最容易犯的错误是只准备一个正常样例。正常样例只能证明“某一次请求能返回结果”,无法证明缺字段会被拒绝、错误类型不会被吞掉,也无法发现未知属性在某个平台被悄悄保留。
建议至少准备以下样例类别:
- ✅ 正常对象:所有必填字段合法,枚举值在允许范围内。
- ❌ 缺字段:分别缺少顶层必填项、嵌套必填项和数组元素必填项。
- ❌ 错误类型:字符串代替整数、对象代替数组、空值代替非空字段。
- ⚠️ 未知属性:测试
additionalProperties的真实行为。 - ⚠️ 深层嵌套:验证引用展开、嵌套对象和数组元素是否稳定。
- ⚠️ 超长输入:检查拒绝、截断、部分输出和解析错误。
- ❌ 业务矛盾:字段形状合法,但金额、状态、权限或资源关系不合法。
每个样例都应在三家接口中使用相同的业务输入,但不必强行使用相同的供应商请求文件。统一的是测试意图、输入数据和判定标准;变化的是适配后的请求封装。
| 测试记录字段 | 必须记录的内容 | 失败后归类 |
|---|---|---|
| 请求版本 | API 版本、SDK 版本、模型标识 | 环境漂移 |
| Schema 版本 | 核心版本、供应商版本 | 转换不一致 |
| 响应状态 | HTTP 状态、供应商错误码 | 接口拒绝 |
| 解析结果 | JSON 解析、字段完整性 | 格式失败 |
| 规范验证 | JSON Schema 验证结果 | 结构失败 |
| 业务验证 | 权限、事实、数据库约束 | 语义失败 |
| 执行结果 | 是否真正调用工具或写库 | 安全失败 |
JSON Schema 官方入门文档把验证器描述为接收 Schema 与 JSON 实例并返回验证结果的工具,这正适合放在模型输出之后作为第一道检查,但它不能替代业务层的第二道检查。参考:JSON Schema 验证器工作方式。
第五步:Agent 执行器必须在 Schema 之后再做安全判断
一个参数符合 Schema,不等于这个操作可以执行。
例如,工具参数中包含合法的 resource_id、合法的 operation 枚举和合法的 idempotency_key,仍然需要确认当前用户是否有权访问该资源,资源是否属于当前租户,操作是否在允许的业务范围内,以及幂等键是否已经被使用。
Agent 执行器至少应增加以下检查:
- ✅ 身份与权限:确认调用者、租户、角色和资源归属。
- ✅ 资源存在性:从数据库或权威服务读取资源,不接受模型自行推断。
- ✅ 操作范围:对删除、转账、部署、发布等危险动作设置独立白名单。
- ✅ 幂等控制:要求写操作携带幂等键,并在服务端执行去重。
- ✅ 人工确认:高风险动作在真正执行前要求审批或二次确认。
- ✅ 审计记录:保存原始输出、转换后参数、权限判断和执行结果。
🔒 经验提醒:Schema 是输入边界,不是授权系统。任何会改变数据库、账务、部署状态或访问权限的工具,都不应因为模型输出“格式正确”就直接执行。
如果三家模型都能输出合法参数,但其中一家更容易生成错误资源标识,问题应归类为业务语义或事实核验问题,而不是简单的 Schema 兼容问题。
第六步:下游消费者验收字段关系与事实正确性
下游消费者通常是最容易被忽略的责任方。平台团队可能验证了字段类型,测试团队也记录了响应状态,但数据库写入服务仍然可能接收到一组结构合法、业务错误的数据。
可以把验收分为三层:
- 形状层:字段是否存在,类型是否正确,数组元素是否符合定义。
- 关系层:字段之间是否满足业务关系,例如结束时间不能早于开始时间,退款金额不能超过原订单金额。
- 事实层:实体是否真实存在,状态是否来自权威系统,模型是否有足够证据作出判断。
JSON Schema 的 format 也不能被默认视为完整事实校验。某些接口可能把它当作提示或有限格式约束;即使日期字符串符合格式,也不代表该日期在业务上有效,更不代表对应记录存在。
因此,数据库约束、权限服务、库存系统、订单系统和事实检索结果,都应作为独立验证来源。结构化输出只负责把结果放进可处理的形状,不能承诺事实正确。
什么时候应共享、转换或拆分 Schema?
可以用下面的决策条件快速判断:
- 若三家接口都接受核心字段,且统一样例在形状层、关系层和事实层均通过,则选择“共享业务 Schema+供应商适配器”。
- 若某一家只是不支持引用、格式或复杂组合,但业务含义可以通过展开或外置校验保留,则选择“供应商专用 Schema”,同时保留可追踪转换日志。
- 若关键权限、金额、状态转移或资源边界无法在某个平台表达,则不要静默降级,应阻断上线,或者把模型输出与危险工具拆成两个工作流。
- 若模型返回的结构稳定,但事实核验失败率较高,则保留 Schema,增加检索、数据库查询或人工确认,不要继续堆叠格式关键字。
- 若同一业务对象在三家接口中的参数包装差异已经影响监控、重试和审计,则应抽象统一内部协议,而不是让业务代码直接依赖供应商格式。
最终报告如何给出通过、警告与阻断结论
一份可上线的验收报告,至少应固定以下内容:
- 核心 Schema 文件及版本;
- 三家供应商转换后的 Schema;
- API 版本、模型标识、SDK 版本;
- 正常与负例样例集;
- 每个样例的响应状态、解析结果和验证结果;
- 关键字转换与删除日志;
- 权限、幂等、资源和业务规则检查结果;
- 失败项的责任归属与回归计划。
最终结论建议只保留三种:
| 结论 | 适用条件 | 发布动作 |
|---|---|---|
| ✅ 可上线 | 三家均通过结构、解析、安全和业务语义验收 | 进入灰度,保留回归样例 |
| ⚠️ 需供应商专用 Schema | 结构支持不同,但转换不改变业务含义 | 发布各自版本,禁止共用原始请求 |
| ❌ 必须拆分工作流 | 关键约束无法表达,或危险工具缺少独立安全控制 | 阻断发布,增加业务校验或人工审批 |
如果团队需要批量运行同一套跨模型样例、切换不同 API 适配器并保留稳定的远程测试环境,直接依赖个人电脑通常会遇到环境不一致、权限配置分散和测试节点难以复用的问题。自建环境还需要自行维护远程访问、系统版本、依赖隔离与清理流程;相较之下,按项目周期租赁 Mac 测试环境更适合短期兼容性回归、跨版本验证和临时扩容。可先查看 Mac 云租用方案,再结合团队是否需要长期固定负载、物理接口或本地数据留存,判断 Vuncloud 是否适合作为当前测试链路的补充,而不是替代所有生产基础设施。
对于需要长期稳定重负载、必须连接专用硬件或严格要求本地数据闭环的团队,自购 Mac 仍可能更合适;但如果目标是集中执行多模型验收、临时扩展测试节点,远程 Mac 环境可以减少本地机器差异带来的干扰。使用前可通过 帮助中心 确认远程访问与环境管理边界。
用 Vuncloud 云 Mac,加速 JSON Schema 兼容性验收
通过 Vuncloud 远程 Mac,在接近真实运行环境中验证 Schema 转换、拒绝规则与输出语义的一致性。
无需购置和维护本地设备,按需租用 Mac 资源即可开展接口联调、自动化测试与 Agent 执行验证。