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.
{
"type": "object",
"properties": {
"name": {"type": "string"},
"capital": {"type": "string"}
},
"required": ["name", "capital"]
}
$ 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}
$ python3 - <<'PY'
import json
content = '{"name":"Canada","capital":"Ottawa"}'
obj = json.loads(content)
assert set(["name", "capital"]).issubset(obj)
print(obj["capital"])
PY
Ottawa
$ jq '.message.content' response.json "{\"name\":\"Canada\",\"capital\":\"Ottawa\"}"
Do not parse message.thinking as application data.
$ python3 - <<'PY'
import json
required = {"name", "capital"}
obj = json.loads('{"name":"Canada"}')
print(required <= obj.keys())
PY
False