Use an explicit JSON Schema when a local Ollama workflow needs predictable keys and value types. Pass the schema in the request’s format field, tell the model how to handle missing facts, and validate the returned content before another program uses it. A valid JSON object can still contain the wrong date or an invented value.
Design the output your program actually needs
Start with the downstream task. A meeting note importer might need the task, owner, and due date. A shopping list might need item names and quantities. Write one example of the output before designing the prompt. Give each field a single meaning. If a field can be absent, decide whether the consumer expects a missing property, a null value, or another explicit representation. Keep the choice consistent.
Use a simple schema first. For a one-task extraction, require a string for the task and allow the owner to be a string or null. If the source only contains a team name and no person, the prompt can ask the model to leave the owner null. A required field can still allow null. Required describes whether the key appears, and the value type describes what can be inside it.
Keep formatting separate from meaning. A schema can constrain the result to a string, but a string typed as an owner can still name a person absent from the source. Add instructions that say where the answer should come from and how to handle uncertainty. For long material, use our local AI document guide to preserve source labels and verify the excerpt before sending it.
Send the schema to a local Ollama model
Start with a model you have downloaded and tested. If you are new to the setup, see our local AI setup guide. Ollama’s structured outputs documentation describes passing a JSON Schema in the format field. You can use an API client or an application that exposes that field. A chat interface that accepts only plain prompts may not provide the same control.
Here is an example request body for the local chat API. Replace the model name with one installed on your computer. The message contains a made-up task with no named owner. Setting stream to false lets you inspect one complete response while testing. The same output schema is also useful for checking the response after the call completes.
{
"model": "YOUR_INSTALLED_MODEL",
"stream": false,
"messages": [
{
"role": "user",
"content": "Extract one task and its owner. Use null if nobody is named. Source: File the receipt on Friday."
}
],
"format": {
"type": "object",
"properties": {
"task": {
"type": "string"
},
"owner": {
"type": [
"string",
"null"
]
}
},
"required": [
"task",
"owner"
],
"additionalProperties": false
}
}
Parse the returned content and check its meaning
The chat response contains an envelope with the model’s message. Parse the JSON text inside the message content, then validate it against the schema with a suitable library for your language. Handle parsing errors, unexpected fields, missing keys, and types explicitly. If you use a different endpoint, check which field holds the generated content. Do not feed the entire response envelope into an importer expecting a task object.
For the sample, check that the task refers to filing the receipt and that the owner is null. If the model returns a plausible name, the output may still be valid JSON while the extracted fact is wrong. Compare fields that affect decisions with their source. For a larger document, keep a section label or short supporting excerpt with each candidate value so a reviewer can find it quickly.
Test the response before wiring it to a write action. For a task tracker, display a proposed entry for review. For a spreadsheet import, write to a temporary sheet or preview first. Make rejected entries visible with a clear reason so you can distinguish invalid syntax from unsupported facts. Keep the original source available while reviewing and avoid sending unrelated personal information in a test prompt.
Test edge cases before using the workflow regularly
Run examples with a named owner, a missing owner, and a sentence that mentions multiple people without assigning the work. Add examples with quotes or unexpected punctuation in the task text. Check that the output can be parsed and that the exact owner rule holds across the examples. Keep an expected result for each case. Our local model benchmark guide explains how to compare quality and speed on your own tasks.
If an example fails, preserve the input and response, and fix the narrow issue first. For example, if a meeting note says someone suggested an action but nobody accepted it, clarify that a suggestion does not assign ownership. If the output has the correct shape but changes the task, ask the model to extract the wording more closely. Test that change against the earlier examples before relying on it.
Keep the model version, schema, and prompt together. An update can change extraction behavior even when the field names stay the same. If you change the schema later, check that the consumer knows which version it receives. A narrower schema can make validation easier, but it can also discard information the consumer needs. Decide which facts should be preserved before adding more properties or asking for a more complex answer.
When the source exceeds the model’s active context, extract smaller labeled sections and reconcile their results before import. Check the setting using our context length guide. If two sections produce different owners for the same task, keep both references visible and review the original. A schema that permits only one owner cannot resolve the disagreement by itself. In a recurring workflow, add that conflict to your test set and decide how the importer should represent an unresolved assignment. Record the decision in the prompt and validate it before you use a real note.
To make a first test easier to review, submit one record at a time and save the raw response beside the parsed result. If a batch later fails, you can compare the individual inputs without repeating the whole job. Assign a local identifier to each source excerpt so the same record can be retried safely. Before accepting retries into a downstream system, check whether that identifier already has an accepted result.
Frequently asked questions
Is valid JSON the same as a valid extraction?
No. Parse the text, check the schema, and verify key values against the source.
What is the difference between null and a missing field?
Null is a value on a present property. A missing field is absent. Define which one your consumer expects and test that case.
Do I need a schema if I only want readable notes?
A schema is useful when another program needs consistent fields. For notes intended for a person, simpler text can be enough.
What should the app do when validation fails?
Keep the source and report the error. You can try a controlled retry or send the item for review. Avoid importing it as if it passed.
