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 prompt

When 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_tokens cuts generation off, you get invalid JSON with finish_reason: "length", check it before parsing, and size max_tokens for 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.

Structured outputs (JSON mode), Pearl Inference Docs