A predictable response shape is useful for classifying support tickets or extracting fields. Schema-constrained generation helps, but your program still needs to reject unexpected data and handle model failures.
What you will build
Create a JSON-schema request for a local model and inspect a deterministic output validator before connecting the two.
Before you start
Python 3.10 or later. Run the offline fixture first; a live request additionally requires local Ollama and llama3.2.
1. Create structured_topic.py
import json
from urllib.request import Request, urlopen
schema = {
"type": "object",
"properties": {"topic": {"type": "string", "enum": ["java", "python", "other"]}},
"required": ["topic"],
"additionalProperties": False,
}
payload = {
"model": "llama3.2", "stream": False, "format": schema,
"prompt": "Classify: How do I parse JSON in Python? Return the topic as JSON.",
}
def parse_topic(text):
result = json.loads(text)
if not isinstance(result, dict) or set(result) != {"topic"}:
raise ValueError("Unexpected fields")
if result["topic"] not in ("java", "python", "other"):
raise ValueError("Unknown topic")
return result["topic"]
def classify(endpoint="http://127.0.0.1:11434/api/generate"):
request = Request(endpoint, data=json.dumps(payload).encode(),
headers={"Content-Type": "application/json"}, method="POST")
with urlopen(request, timeout=60) as response:
envelope = json.load(response)
return parse_topic(envelope["response"])
if __name__ == "__main__":
assert parse_topic('{"topic":"python"}') == "python"
print("Offline fixture passed")
# Uncomment to call your own local model:
# print(classify())
2. Run the example
python structured_topic.pyExpected result
Offline fixture passed is printed. After enabling the local call, the expected topic is python, though model correctness must still be evaluated.
How it works
The format parameter contains the requested shape, while stream false requests one response envelope. The generated JSON is itself text inside the response field, so the validator parses that inner value.
The offline assertion checks only your parsing path. It does not demonstrate that a particular model always follows a schema or selects the correct topic. Keep those two kinds of tests separate.
Use a small reviewed set of questions for each class, including ambiguous and unrelated inputs. Record both schema failures and wrong classifications. Treat a model label as data; never let a returned field become executable code or SQL.
The example deliberately keeps a tiny allowlist. If your application adds categories, update the schema, validator and evaluation set together rather than silently accepting any string.
Test the edge cases
- Try an unknown topic and an extra key.
- Stop the model server to exercise the network failure path.
- Check current provider documentation before moving this local schema request to a cloud endpoint.
Keep learning
Browse related tutorials. Reference: official documentation.
Reviewed 7 November 2026. AI-dependent examples require your own local model; generated text varies.