Structured outputs
When the answer feeds a program rather than a person, ask for JSON. JSON mode makes the model emit a single valid JSON object; a schema in the prompt makes it the object you expect.
JSON mode#
Set response_format to {"type":"json_object"} on any model whose catalog entry has json_mode true. The model then returns a syntactically valid JSON object and nothing else: no prose around it, no code fences.
curl https://api.ahurasense.com/v1/chat/completions \
-H "Authorization: Bearer $AHURA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-5.4-mini",
"response_format": {"type": "json_object"},
"messages": [
{"role": "system", "content": "Extract the fields. Reply with a JSON object with keys name, email, intent (one of: sales, support, other)."},
{"role": "user", "content": "Hi, Priya here ([email protected]). My invoice from last month looks wrong."}
]
}'{ "name": "Priya", "email": "[email protected]", "intent": "support" }Schemas#
JSON mode guarantees valid JSON, not a particular shape. To pin the shape, put the schema in the prompt, in words or as a JSON Schema block, and validate the answer on your side. On backends that support it, a response_format of type json_schema is passed through unchanged and enforces the schema at generation time; where the backend does not support it, the request is refused with upstream_rejected_request, so keep the prompt-plus-validation path as the fallback.
from pydantic import BaseModel, EmailStr
from typing import Literal
class Lead(BaseModel):
name: str
email: EmailStr
intent: Literal["sales", "support", "other"]
completion = client.chat.completions.create(
model="openai/gpt-5.4-mini",
response_format={"type": "json_object"},
messages=[
{"role": "system", "content": f"Reply with JSON matching this schema: {Lead.model_json_schema()}"},
{"role": "user", "content": text},
],
temperature=0,
)
lead = Lead.model_validate_json(completion.choices[0].message.content)Tool calling as structured output#
Another reliable route is a single tool whose parameters are the schema you want, with tool_choice forcing that tool. The arguments come back typed by the schema and many models are more accurate this way than with free-form JSON. See Tool calling.
Habits that help#
- Use
temperature: 0. Extraction wants the most likely answer, and it makes repeats cacheable. - Give one example of the exact object you want when the shape has nesting.
- Set a
max_tokenslarge enough for the whole object; a truncated object is not valid JSON. - Validate. A schema violation should be a retry with the error appended to the conversation, not a crash.
Something missing or wrong on this page? Tell us, and quote the page title.