Why "ask nicely" isn't enough
You could prompt any model with "reply in JSON with keys title, year, and director" and most of the time, with a capable model, it would work. "Most of the time" is the problem: a real program parsing that reply needs it to work every time, and free-form prompting gives you no actual guarantee, just a good habit the model has picked up from training.
Ollama's format parameter solves this properly: instead of hoping the model formats its answer correctly, it constrains generation itself so the model is structurally unable to produce a token that would break the schema. This is the same idea behind LangChain's with_structured_output() and pydantic_ai's typed outputs, just happening locally against your own model.
The code, piece by piece
class Movie(BaseModel): title: str year: int director: strAn ordinary Pydantic model, nothing Ollama-specific about it. This is the exact same tool the pydantic_ai course builds an entire course around, and it's already part of this project's dependencies.
response = ollama.chat( model="llama3.2", messages=[...], format=Movie.model_json_schema(), options={"temperature": 0},)Movie.model_json_schema() turns the class definition into a JSON Schema dict, a format both Pydantic and Ollama understand. temperature=0 is a sensible default here, from Lesson 6, extraction tasks like this want a steady, most-likely answer, not creative variation.
movie = Movie.model_validate_json(response.message.content)Because the schema constrained what the model could generate, response.message.content is guaranteed valid JSON matching Movie's shape. Parsing it back into a real Movie object should never raise a validation error the way parsing arbitrary free-form text would.
A note on speed
Constrained decoding has real overhead: the model has to check, at every single token, which continuations are still legal under the schema. For small, simple schemas like this one it's barely noticeable; very large or deeply nested schemas can measurably slow generation down. Worth knowing before you reach for format on a huge, complicated schema and wonder why it's suddenly slow.
Checkpoint
format=<json schema>: constrains generation so the output is structurally guaranteed to match the schema, not just prompted to.- Why it's stronger than prompting: the model can't generate a token that would break the schema, there's no "usually works" here.
Movie.model_json_schema(): Pydantic already knows how to produce the schema Ollama needs, no extra library required.- Tradeoff: constrained decoding has overhead, larger schemas can measurably slow generation.
If anything here still feels unclear, ask before moving to Lesson 11.