How to generate structured output with the Ollama API

Structured output constrains an Ollama response to JSON or a JSON schema so application code can parse fields instead of scraping prose. It is useful for classification, extraction, routing, and any workflow where free-form text would create fragile downstream logic.

The format field can request generic JSON or provide a schema object. Pair the schema with a direct prompt and deterministic options when the result will be validated automatically.

The local fixture confirmed schema-shaped output with gpt-oss:20b. The same pattern works through api/chat and can be adapted to SDK calls that pass an equivalent schema.

Steps to generate structured output with the Ollama API:

  1. Write the JSON schema that the response must match.
    {
      "type": "object",
      "properties": {
        "name": {"type": "string"},
        "capital": {"type": "string"}
      },
      "required": ["name", "capital"]
    }
  2. Send the schema in the format field of a chat request.
    $ curl -s http://localhost:11434/api/chat -d '{
      "model": "gpt-oss:20b",
      "messages": [{"role":"user","content":"Return a JSON object for Canada with keys name and capital."}],
      "stream": false,
      "format": {
        "type":"object",
        "properties":{"name":{"type":"string"},"capital":{"type":"string"}},
        "required":["name","capital"]
      },
      "options": {"temperature": 0}
    }'
    {"message":{"content":"{\"name\":\"Canada\",\"capital\":\"Ottawa\"}"},"done":true}
  3. Parse and validate the returned content before using it.
    $ python3 - <<'PY'
    import json
    content = '{"name":"Canada","capital":"Ottawa"}'
    obj = json.loads(content)
    assert set(["name", "capital"]).issubset(obj)
    print(obj["capital"])
    PY
    Ottawa
  4. Keep reasoning fields separate from the structured content when using thinking models.
    $ jq '.message.content' response.json
    "{\"name\":\"Canada\",\"capital\":\"Ottawa\"}"

    Do not parse message.thinking as application data.

  5. Reject malformed or missing fields in the caller.
    $ python3 - <<'PY'
    import json
    required = {"name", "capital"}
    obj = json.loads('{"name":"Canada"}')
    print(required <= obj.keys())
    PY
    False