Inference API
Structured outputs (JSON mode)
Constrain the response to syntactically valid JSON at decode time, then validate the shape against your schema.
Set response_format: {"type": "json_object"} and the model's output is constrained while it generates, the response parses as JSON every time, with no markdown fences and no prose preamble. Every model in the catalog supports it, including the reasoning models.
Syntax is guaranteed, your schema is not
JSON mode promises valid JSON of some shape, not your shape. Left without instructions, a model may invent its own keys. The reliable pattern has three parts: spell out the exact keys in the prompt, enable JSON mode, and validate the result before using it:
import os
from openai import OpenAI
from pydantic import BaseModel, ValidationError
client = OpenAI(
base_url="https://inference.pearlresearch.ai/v1",
api_key=os.environ.get("PEARL_API_KEY"),
)
class Person(BaseModel):
name: str
age: int
SYSTEM = (
"Extract the person from the user's text. "
"Respond ONLY with a JSON object with exactly two keys: "
"name (string) and age (number)."
)
response = client.chat.completions.create(
model="zai-org/GLM-5.2",
messages=[
{"role": "system", "content": SYSTEM},
{"role": "user", "content": "John is 30 years old."},
],
response_format={"type": "json_object"},
)
raw = response.choices[0].message.content
try:
person = Person.model_validate_json(raw) # schema is YOUR job, validate
print(person)
except ValidationError as err:
print("valid JSON, wrong shape:", err) # retry with the error in the promptWhen validation fails, retry once with the validation error appended to the conversation, models are good at repairing a named mistake. The stricter json_schema response format (server-enforced schemas) is not available yet, so client-side validation is the contract.
Pitfalls
- Truncation. If
max_tokenscuts generation off, you get invalid JSON withfinish_reason: "length", check it before parsing, and sizemax_tokensfor your largest expected object. - Example contamination. Models copy example JSON from the prompt very literally, keep any inline example minimal and syntactically perfect, or describe the keys in words instead.
- Streaming. JSON mode streams like any response, but the object is only parseable once complete, accumulate deltas and parse at the end.
- Numbers as strings. If a field must be numeric, say so explicitly ("age (number, not a string)"), and let your validator coerce or reject.
Extraction tasks run fine on the smaller models, start with Gemma 4 31B or DeepSeek V4 Flash and keep the bigger models for inputs that need judgment, not just parsing.