Structured outputs with JSON schemas

Ollama · Practical · 12 min

Programs need reliable fields, and schema-constrained output makes even small local models dependable for extraction.

Asking "reply in JSON" in the prompt works most of the time. For code that depends on the result, most of the time isn't enough. Ollama can constrain the output to a JSON schema (a description of the fields and their types), so the reply always parses.

Pass the schema in the format parameter. In Python, the easy way to write a schema is Pydantic, a library where you describe data as a class: a named template listing fields and their types. Pydantic converts it to a JSON schema and later checks the reply:

class Country(BaseModel):
    name: str
    capital: str
    languages: list[str]

response = chat(model="gpt-oss", messages=[...], format=Country.model_json_schema())
country = Country.model_validate_json(response.message.content)

country.capital is now a real field you can use.

Tips from the docs and practice:

  • Set temperature to 0 for consistent extraction.
  • Also describe the expected fields in the prompt; it helps the model fill them with the right content.
  • format="json" only guarantees valid JSON of any shape; a schema is stricter.
  • The schema guarantees shape, not truth: values can still be wrong or invented. Validate important values in code and allow empty or optional fields when data may be missing.
  • Over the REST API, put the schema object in the "format" field. The OpenAI-compatible API supports structured output through response_format.

Structured outputs are a local feature; the docs note Ollama's cloud does not support them.

Example

from typing import Literal, Optional
from ollama import chat
from pydantic import BaseModel

class Ticket(BaseModel):
    category: Literal["billing", "bug", "other"]
    urgency: int                       # 1 (low) to 5 (critical)
    order_id: Optional[str] = None     # None if not mentioned

text = "I was charged twice for order A-1042, please fix this today!"
response = chat(
    model="gpt-oss",
    messages=[{"role": "user", "content":
               f"Extract category, urgency (1-5) and order_id from: {text}"}],
    format=Ticket.model_json_schema(),  # constrain the reply to this schema
    options={"temperature": 0},
)
ticket = Ticket.model_validate_json(response.message.content)
print(ticket)                          # category='billing' urgency=5 order_id='A-1042'
print(ticket.order_id)                 # A-1042

Remember

  • format=Model.model_json_schema() constrains output to a schema
  • Model.model_validate_json(...) parses and checks the reply
  • Schemas guarantee shape, not correctness; use temperature 0 and validate values

Watch out for

  • Trusting a schema-valid reply as correct, when the model may still have invented a value such as an order ID.

Check yourself

  1. What does passing a JSON schema in format guarantee?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.ollama.com/capabilities/structured-outputs