Building a Local LLM · 15/30 · API and Document Search
Full series and learning sequence · Practice code ZIP
An answer passed to another program needs a predictable structure. Even a greeting before a JSON object can prevent parsing. Check the response format separately from the correctness of the values inside it.
We use the common functions from Part 13. It sequentially checks JSON grammar, field data types, and consistency with the original text.
JSON Schema definition
By passing JSON Schema to Ollama’s format field, you can specify the required fields and data types. It helps the program get a readable format. However, it is not possible to judge from the schema alone whether a person in charge or a date that was not in the original text was created.
Items not found are marked as null in this example. It is easier to handle unspecified items if you separate them from empty strings. Standards for interpreting units, time zones, and dates are also defined for actual business data.
Comparison of extracted values with the original text
import json
from llm_http import post, MODEL
schema = {
"type": "object",
"properties": {
"time": {"type": ["string", "null"]},
"retention_days": {"type": ["integer", "null"]},
"owner": {"type": ["string", "null"]}
},
"required": ["time", "retention_days", "owner"],
"additionalProperties": False
}
response = post("/api/chat", {
"model": MODEL,
"messages": [{"role": "user", "content":
"메모: 백업은 매일 02시에 실행하고 14일 보관한다. "
"스키마에 맞춰 추출하라. 없는 값은 null. 스키마: " + json.dumps(schema)}],
"format": schema, "stream": False,
"options": {"temperature": 0, "num_ctx": 4096, "num_predict": 256}
})
data = json.loads(response["message"]["content"])
if set(data) != {"time", "retention_days", "owner"}:
raise ValueError("Unexpected fields")
if data["time"] != "02시" or type(data["retention_days"]) is not int:
raise ValueError("Check time format and number type")
if data["retention_days"] != 14 or data["owner"] is not None:
raise ValueError("Extracted facts do not match this sample")
print(json.dumps(data, ensure_ascii=False, indent=2))
.\.venv\Scripts\python.exe .\structured_demo.py
The sample specifies the hour as 02 followed by the Korean hour suffix. If the output is 02:00, distinguish a different display format from a factually wrong time. Production code can normalize time values before comparison. json.loads parses JSON syntax; it does not validate a complete JSON Schema.
Grammar, schema, and business rule inspection
| inspection | Problems that can be caught |
|---|---|
| JSON parsing | Incorporation of unclosed parentheses and explanatory text |
| Schema validation | Missing field, wrong data type, unexpected item |
| work rules | Storage period is negative/exceeds acceptable range |
| original text comparison | Making up people in charge and misreading numbers |
The code below directly checks the fields and textual facts of a small sample. If it is a complex app, it is better to separate the inspection of libraries such as jsonschema from the inspection of business rules. Pass validation before saving the model results or converting them into commands.
Validation failures and retry limits
If validation fails, check to see if the input is ambiguous or if you are putting too much work into the model. You can ask again by telling us the reason for the failure, but limiting the number of times and for how long. Values that are not confirmed until the end are not automatically saved and are left for manual review.
Requesting complex objects from a small model at once may result in omissions. Another way is to separate document-specific item extraction and final assembly. In this case, the document ID and source location are kept together to prevent values from different original texts from being mixed.
reference material
Documentation and model tags checked: October 18, 2026. Primary lab environment: Windows 11 x64.



