ollamalocal-llmstructured-outputpydanticai

Structured JSON from Local LLMs with Ollama

·8 min read·AI & JSON

Reliable JSON without a cloud API

Running models locally with Ollama gives you privacy and zero per-token cost — but a raw local model is just as happy to wrap its answer in prose as any cloud model. Since version 0.3.0, Ollama solves this with the `format` parameter: pass a JSON Schema and Ollama applies constrained decoding during inference, masking any token that would break the schema. The output is guaranteed to parse, and — counterintuitively — it's usually *faster*, because the model never spends tokens deliberating about formatting.

Passing a JSON Schema directly

Send your schema as the format value. Every generated token is constrained to keep the output valid:

python
import ollama

schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "age": {"type": "integer"},
        "skills": {"type": "array", "items": {"type": "string"}},
    },
    "required": ["name", "age", "skills"],
}

resp = ollama.chat(
    model="llama3.1",
    messages=[{"role": "user", "content": "Describe a fictional software engineer."}],
    format=schema,
)
print(resp["message"]["content"])   # always valid JSON matching the schema

Using Pydantic for schema + validation in one step

You rarely want to hand-write JSON Schema. Define a Pydantic model, generate the schema with model_json_schema(), and validate the reply with model_validate_json() — schema and parsing from one source of truth:

python
from pydantic import BaseModel
import ollama

class Engineer(BaseModel):
    name: str
    age: int
    skills: list[str]

resp = ollama.chat(
    model="llama3.1",
    messages=[{"role": "user", "content": "Describe a fictional software engineer."}],
    format=Engineer.model_json_schema(),
)
engineer = Engineer.model_validate_json(resp["message"]["content"])

Why it's faster, and how to keep it reliable

In direct measurements, the same prompt has run several times faster with format than without — one reported case dropped from ~32s to ~5s — because constrained decoding removes the model's freedom to ramble. Constrained decoding guarantees *shape*, not *correctness*, so a few habits still matter:

  • Keep schemas flat. Deeply nested structures are harder for smaller local models; flatten where you can.
  • Reach for a bigger model when fields go wrong. A larger or instruction-tuned variant (e.g. a 12B) improves semantic accuracy even though the shape is already guaranteed.
  • Still validate. The JSON will match the schema, but business rules (a price that must be positive, an enum you actually accept) belong in a Pydantic validator or a schema validation pass.
  • Use the tools parameter for function calling on capable models (Llama 3.1+, Qwen 2.5+, Mistral) when you want the model to *choose* an action rather than fill a fixed shape.

To build the schema you'll pass, prototype a sample and generate a JSON Schema from it, or convert a sample to Python to get the Pydantic model. For the cloud-vs-local trade-offs, compare with LLM JSON Mode & Structured Outputs and TOON vs JSON for trimming prompt tokens on local hardware.

Frequently asked questions

Yes. It applies constrained decoding, masking any token that would violate the schema, so the output always parses and matches the structure. It does not guarantee the *values* are correct — validate business rules separately.

Constrained decoding removes the model's need to decide on formatting and stops it generating explanatory prose, so it emits fewer tokens and reaches a valid stop point sooner — often several times faster in practice.

Yes, and it's the recommended path: generate the schema with model_json_schema(), pass it to format, then validate and parse the reply in one step with model_validate_json().

Shape is guaranteed, but semantics aren't. Flatten the schema, add clear field descriptions, and switch to a larger or instruction-tuned model. Keep validation on to catch values that are well-formed but wrong.

Try JSON Schema Generator

Generate the JSON Schema to pass to Ollama's format parameter.