SPB Git forge

spb/doc-api

Public
2commits 1branches 0releases
15.7 MBsize
maindefault branch
13 days agolast push
Python 88.3% TypeScript 7.6% Shell 4.1%
5.2 KB

# OpenAI Structured Outputs (JSON Schema) and JSON mode

Status: DOCUMENTED + LIVE_VERIFIED (Responses text.format json_schema strict and Chat response_format json_schema strict, 2026-09-18; JSON-mode guard error verified). Machine-readable: parameter rows text.format(*) in generated/fragments/parameters/openai-responses.json and response_format(*) in openai-chat-completions.json.

Sources

Last verified: 2026-09-18

# 1. Two shapes for the same feature

Responses API Chat Completions API
Plain text (default) "text": {"format": {"type": "text"}} "response_format": {"type": "text"}
Structured Outputs "text": {"format": {"type": "json_schema", "name": "…", "schema": {...}, "strict": true, "description": "…"}} — flat "response_format": {"type": "json_schema", "json_schema": {"name": "…", "schema": {...}, "strict": true, "description": "…"}} — nested wrapper
JSON mode (legacy) "text": {"format": {"type": "json_object"}} "response_format": {"type": "json_object"}
Also available via function tools with strict: true (Responses omits strict → tries strict, falls back to non-strict and returns strict:false) function tools with strict: true (non-strict by default)
Output location output[].content[].text (SDK output_text, parse() → output_parsed) choices[].message.content (SDK parse() → message.parsed)
Refusals output[].content[] part {type:"refusal", refusal} choices[].message.refusal

name (required): a-z A-Z 0-9 _ -, ≤64 chars. strict defaults to false in the spec (docs recommend true). schema is an arbitrary JSON Schema object (additionalProperties: true in the spec).

# 2. Supported schema subset (strict mode)

  • Types: string, number, integer, boolean, object, array, enum, anyOf; $defs/$ref and recursion ("$ref": "#") supported.
  • Constraints: string pattern, format (date-time, time, date, duration, email, hostname, ipv4, ipv6, uuid); number multipleOf, minimum, maximum, exclusiveMinimum, exclusiveMaximum; array minItems, maxItems. (Not for fine-tuned models.)
  • Rules: root must be an object (no root anyOf); all properties required (emulate optional with ["string","null"]); every object needs additionalProperties: false; no allOf, not, dependentRequired, dependentSchemas, if/then/else.
  • Limits: ≤5,000 properties, ≤10 nesting levels, ≤120,000 chars of property/definition/enum/const strings, ≤1,000 enum values (≤15,000 chars of enum strings when >250 values).
  • Output keys follow schema key order. Unsupported schema + strict:true → 400.
  • Models: gpt-4o-mini / gpt-4o-2024-08-06 and later (all GPT-4.1, GPT-5.x, o-series). JSON mode also on gpt-3.5-turbo / gpt-4-*.

# 3. Edge cases to handle

  • status:"incomplete" / finish_reason:"length" → JSON may be truncated; do not parse.
  • Refusal content part / message.refusal → no JSON.
  • content_filter → partial output.
  • JSON mode only guarantees syntactically valid JSON, not schema adherence; the request must mention "JSON" — live p3: text.format.type=json_object with input "Reply with OK." → HTTP 400 Response input messages must contain the word 'json' in some form to use 'text.format' of type 'json_object' (param:"input").
  • Streaming: Responses emits response.output_text.delta fragments of the JSON (SDK stream() yields response.output_text.delta with accumulated snapshot); Chat emits delta.content fragments — parse only when done.
  • Changing text.format/schema invalidates the prompt-cache prefix (prompt_cache_diagnostics.reason:"text_format_changed" on GPT-5.6+).

# 4. Live excerpts (2026-09-18)

Responses (e), gpt-5.4-nano, max_output_tokens 32:

json
request  {"text":{"format":{"type":"json_schema","name":"ok_reply","strict":true,"schema":{"type":"object","properties":{"answer":{"type":"string"}},"required":["answer"],"additionalProperties":false}}}}
response "text":{"format":{"type":"json_schema","description":null,"name":"ok_reply","schema":{…},"strict":true},"verbosity":"medium"}
         output_text = "{\"answer\":\"OK.\"}"   (usage 15 in / 22 out incl. formatting tokens)

Chat (l3), gpt-4.1-nano: response_format.json_schema strict → content = "{\"answer\":\"OK\"}". SDK helpers verified in examples: Python client.responses.parse(text_format=Model) → output_parsed; client.chat.completions.parse(response_format=Model) → message.parsed (see examples/openai/responses/structured_output.py, examples/openai/chat/structured_output.py).

# 5. Migration note

response_format is rejected on /v1/responses (use text.format); text is not a Chat parameter. Flatten json_schema.{name,schema,strict,description} into format when moving to Responses.