Codex 把 final_output_json_schema 编译成 Responses text.format,严格模式由服务端约束模型输出。通用采样链不会再在本地用 JSON Schema 验证一次;它仍把最终内容作为 Assistant Message 文本交付,专用调用方可再反序列化自己的领域类型。
具体问题与启用条件
本节区分请求约束、服务端严格验证、客户端 JSON 解析和领域 fallback,避免把四件事合成一个“结构化输出解析器”。
| 条件来源 | 决定字段或状态 | 对本机制的影响 |
|---|---|---|
| Turn 输入 | final_output_json_schema=Some(Value) | Prompt 携带 output_schema |
| 请求编译 | output_schema_strict | 生成 text.format.strict |
| Guardian reviewer source | 特殊来源 | strict=false;普通 Turn 默认 true |
协议、类型与状态所有权
| 状态或协议 | 所有者 | 生命周期 | 关键不变量 |
|---|---|---|---|
| JSON Schema Value | TurnContext | 一次 Turn,可由输入覆盖 | 不作为文本指令拼接 |
| TextControls.format | ModelClient | 一次请求 | name 固定 codex_output_schema |
| Schema enforcement | Responses 服务端 | 生成期间 | Core 依赖服务合同 |
| 最终 JSON 文本 | Assistant Message/调用方 | Item Done 后 | 通用 Core 不返回已验证 Value |
机制调用链如下:
Op::UserInput(final_output_json_schema)
→ TurnContext snapshot
→ Prompt.output_schema + strict flag
→ create_text_param_for_request
→ text.format{name,type=json_schema,schema,strict}
→ Responses 服务端约束输出
→ Message OutputText
→ Core 原样交付文本
→ 专用消费者可 json.loads/deserialize
机制怎样工作
build_prompt 从 TurnContext 复制 final schema。普通来源把 strict 设为 true,Guardian reviewer 例外为 false。请求编译器只有在 verbosity 或 schema 至少一个存在时才创建 text;schema 被包进固定 name codex_output_schema 和 type json_schema。这部分有纯序列化测试固定字段形状。
响应回来后仍走普通 Message 路径。json_result 集成测试会在测试端把 AgentMessage 文本交给 serde_json::from_str,证明服务端返回符合 Schema 的 JSON,而且 Core 没有改写它;这不是通用 Core 内置的 Schema Validator。Review 等专用流程另行尝试反序列化领域类型,失败时可截取首个 JSON Object 或退回纯文本解释。由此可见,“模型输出受约束”和“客户端拿到强类型对象”之间仍有一层应用解析。
Python 风格伪代码
这段伪代码保留生产实现中会改变结果的状态、分支和异步边界;认证 SDK、遥测字段和 Rust 所有权样板被折叠为明确的领域对象。
def text_controls(verbosity: str | None, schema: dict | None,
strict: bool) -> dict | None:
if verbosity is None and schema is None:
return None
controls: dict = {}
if verbosity is not None:
controls["verbosity"] = verbosity
if schema is not None:
controls["format"] = {
"type": "json_schema",
"name": "codex_output_schema",
"strict": strict,
"schema": schema,
}
return controls
async def consume_structured_result(message: str, decoder: Callable[[dict], T]) -> T:
# 应用层验证;通用模型流只交付 message
value = json.loads(message)
return decoder(value) # 可再用 jsonschema/Pydantic 校验
失败、取消与恢复
| 故障或边界 | 已发生的状态 | 对上层的结果 | 能否直接重试 | 恢复动作 |
|---|---|---|---|---|
| Schema 本身不被服务接受 | 请求未生成响应 | InvalidRequest | 否 | 修正支持的 JSON Schema |
| strict=false 输出偏离 Schema | Message 仍可完成 | 应用解析失败 | 不自动 | 专用 fallback/重新请求 |
| 调用方期待 dict 但收到文本 | Core 合同被误解 | 类型错误 | 否 | 显式 json.loads + validate |
| 流在 Message Done 前断开 | 可能见到半截 JSON Delta | 不提交结果 | 是 | 只解析完整 Message |
设计取舍与验证
把 Schema 交给服务端可在生成阶段约束结构,减少客户端“生成后再拒绝”的浪费。通用 Core 不重复验证保持 Provider 无关和低依赖,代价是调用方若需要强类型保证必须再解析。专用 fallback 提升容错,但不应被宣传为严格 Schema 成功。
| 可验证契约 | 证据方式 | 预期结果 |
|---|---|---|
| strict true/false 精确序列化 | client_common 单元测试 | format 字段逐项相等 |
| 最终 JSON 作为 AgentMessage 交付 | json_result 集成测试 | 调用方可成功 parse |
| 无 schema/verbosity 时省略 text | 序列化测试 | 请求不发空 controls |
Mini Codex 对照
Mini Codex 应把输出约束和结果解析分成 RequestCompiler 与 StructuredResultDecoder[T]。若 Provider 不支持 JSON Schema,必须报告能力缺失或用明确的弱保证 fallback,不能仍声称 strict。
本节边界
本节能证明 wire Schema 和消息交付,不能把服务端实现细节写成本地验证算法。5.25 处理最后一个普通流生命周期问题:取消时暂态、连接与已完成 Item 怎样收尾。
评论
登录后即可评论