Learning objectives
By the end of this module, you should be able to:
- Define a structured output schema and validate model output against it.
- Design tool definitions with narrow arguments and explicit authorization outside the model.
- Explain why tool calling is a proposal, not permission to perform a side effect.
Structured output is an interface contract
If downstream code needs fields, types or enumerated states, define them explicitly. Valid JSON alone is weaker than schema-conforming output: keys, types and allowed values matter.
Validation still belongs in application code
Schema-constrained generation improves reliability but your application still handles refusals, truncation, unavailable tools, business validation and authorization. Never deserialize model output directly into a privileged action without checks.
A tool call is a request from the model
The application decides whether the requested tool exists, whether the caller is authorized, whether arguments are valid and whether confirmation is required. The model must not be the security boundary.
Minimize tool authority
Prefer narrow read-only functions over generic shell/SQL/network tools. Side-effecting tools should be idempotent where possible and carry explicit scopes, limits and audit records.
Separate planning from execution
For high-impact actions, generate a proposed plan or structured change first, validate it, show it to a human or policy engine, and only then execute the bounded operation.
Worked examples
Response schema
{
"type":"object",
"required":["status","answer","source_ids"],
"properties":{
"status":{"enum":["ANSWERED","INSUFFICIENT_EVIDENCE"]},
"answer":{"type":"string"},
"source_ids":{"type":"array","items":{"type":"string"}}
}
}
- Schema-constrained output is easier to validate and route than free-form prose.
Tool security boundary
model proposes tool(name,args)
→ application validates schema
→ application checks user/tool policy
→ optional confirmation
→ executor runs bounded function
→ result returned as data
- The model never grants itself authority.
Try it · core lab · account-free
Lab 04 — Validate structured output and a tool proposal
Goal: Build deterministic validators around model-shaped JSON.
Before you start
- No paid API or cloud account is required for the core lab.
- Core labs use Python 3 and local files only.
- Running case: you are engineering 'Atlas Assist', an internal support assistant over a small approved knowledge base with one read-only inventory tool.
- Carry requirements, eval cases, threat assumptions and operational evidence forward across modules instead of starting over.
STEP 1Validate an answer contract
python3 - <<'PY2'
import json
obj={"status":"ANSWERED","answer":"Reset requires approval.","source_ids":["kb-17"]}
assert obj['status'] in {'ANSWERED','INSUFFICIENT_EVIDENCE'}
assert isinstance(obj['answer'],str) and isinstance(obj['source_ids'],list)
assert all(isinstance(x,str) for x in obj['source_ids'])
print('PASS: response contract')
PY2
STEP 2Reject an over-broad tool argument
python3 - <<'PY2'
proposal={"name":"lookup_asset","arguments":{"asset_id":"*"}}
asset=proposal['arguments']['asset_id']
allowed=asset.startswith('srv-') and asset[4:].isdigit()
print('authorized?',allowed)
assert not allowed
print('PASS: tool proposal rejected before execution')
PY2
STEP 3Design confirmation policy
Mark each tool in your design as read-only, reversible write, or irreversible/high-impact. State which classes require human confirmation.
Verify
- Invalid business arguments are rejected even if JSON is syntactically valid.
- Authorization is represented outside the tool description.
Expected outcome
- A response validator plus a bounded tool proposal policy.
Break / fix · diagnose
- If the model decides authorization, move the decision into trusted application code.
- If one generic tool can execute arbitrary commands, redesign it into narrow functions.
Production viewStructured outputs and function tools turn model behaviour into software interfaces that can be validated, authorized and observed.
Local real-tool practicum · optional but recommended
Optional practicum — schema-constrained Ollama output
Ask a local model for a schema-constrained response and inspect the resulting JSON.
Prerequisites
- Ollama installed and reachable on http://127.0.0.1:11434 for the real-tool path.
Resources created
- Only local disposable files/processes used by the practicum.
Cost / risk
- No cloud account required; model downloads consume disk and network bandwidth.
TOOL 1MODEL=${MODEL:-qwen3:8b}; curl -s http://127.0.0.1:11434/api/chat -H 'Content-Type: application/json' -d "{\"model\":\"$MODEL\",\"messages\":[{\"role\":\"user\",\"content\":\"Classify this ticket: database timeout\"}],\"stream\":false,\"format\":{\"type\":\"object\",\"properties\":{\"category\":{\"type\":\"string\"},\"severity\":{\"type\":\"integer\"}},\"required\":[\"category\",\"severity\"]}}" | python3 -m json.tool | head -100
Verify
- The model response content can be parsed as the requested structure.
Cleanup
- Remove only the disposable files created for the lab; keep model caches only if you intend to reuse them.
Warnings
- Schema validity does not prove factual correctness or authorization; those are separate gates.
Avoid these traps
Common mistakes
- Using JSON mode when a concrete schema is required.
- Executing model tool arguments without business validation.
- Exposing generic privileged tools.
- Assuming a schema removes the need for refusal/truncation handling.
Knowledge check
Can you connect the AI behaviour to a system control?
Concept and scenario checks. Reveal the answer only after you commit to a decision.
1What is the difference between JSON mode and structured output?
JSON mode targets syntactically valid JSON; structured output constrains the response to a defined schema.
2Who authorizes a model-requested tool call?
Trusted application policy, not the model.
3Why prefer narrow tools?
They reduce the blast radius and make validation, authorization and auditing tractable.
4Scenario: the model requests delete_account with valid JSON for a user who lacks permission. What should happen?
The application must deny the operation because schema validity is not authorization.