Free learning / 40-minute structured-output lab
Your first output contract: shape is not truth
Connect ordinary response fields to real JSON Schema validation, then compare a valid shape with the source that should support it.
No account needed. Use your own copy for writing and keep the original as a reference.
Engineering lab library / Run locally
Make the output contract visible.
Run real JSON parsing and schema validation against nine small responses. Compare shape failures with a correct-looking response that the source does not support.
Synthetic records. No provider key or model inference. Package setup needs package-registry access.
Start here / Real library, SDK or framework · Scripted inputs
First output contract
Reproduce nine responses and explain the first boundary that holds each one.
Python 3.11+ · Pinned jsonschema validator · No model
An assistant extracts a machine's condition from a note. Another program needs to know which source was used, which version it was, what was observed and what supports the observation. A paragraph may be readable to a person without being a stable interface for that program.
This original 40-minute exercise teaches that interface using a small JSON response, an actual JSON Schema validator and one fictional source. There is no model call, external action or claim of measured model accuracy.
1. Give the answer a usable shape
Structured output is data arranged to an agreed contract. Prompting describes a task and context to a model. Asking for a shape and validating the returned value are different jobs.
Think of a typed function result. A caller expects particular fields, but an annotation in your code cannot prove that incoming text from an external service has those fields. A runtime validator inspects the actual value.
JSON, JavaScript Object Notation, is a text data format used across languages. JSON Schema describes rules for JSON values. Neither is an AI model, a database or a guarantee that a statement is true.
Here is the complete fictional source:
NOTE-7 · revision 3
Pump P7 is running. Temperature is 41 C. No shutdown is recorded.Here is the supported response in this exercise. Save it as answer.json when you reach the local setup:
{
"source_id": "NOTE-7",
"source_revision": 3,
"condition": "running",
"evidence": "Pump P7 is running."
}The four fields answer four questions: which note, which version, what condition, and what evidence? This is a draft finding. It does not operate a machine.
2. Run the local contract
Download these files into one folder:
Use Python 3.11 or later. On macOS or Linux:
python3 -m venv .venv-schema
. .venv-schema/bin/activate
python -m pip install -r fde-first-schema-requirements.txt
python fde-first-schema.py test
python fde-first-schema.py compareOn Windows, use Command Prompt:
py -3 -m venv .venv-schema
.venv-schema\Scripts\activate.bat
python -m pip install -r fde-first-schema-requirements.txt
python fde-first-schema.py test
python fde-first-schema.py compareInstallation needs internet access. The exercise commands block socket connections and DNS lookup. The actual jsonschema 4.26.0 validator uses a local Draft 2020-12 schema with no remote references. It needs no provider account, key, collector or model.
Eight checks cover stage order, downstream skips, different failure reasons, type handling, source mismatch, parser limits, diagnostic privacy and local repeatability. The report is deterministic for the pinned environment.
3. Read before validating
The first boundary is a parser:
Response text
|
v
Read JSON ---- unreadable or ambiguous ----> hold
|
v
Check shape -- violates the contract ------> hold
|
v
Compare note - unsupported or old source --> hold
|
v
Supported draft within this fixtureA parser turns text into values. JSON object property names are quoted strings; the values may be strings, numbers, booleans, null, arrays or objects. The number 3 and the string "3" are different.
The supplied parser refuses a trailing comma, duplicate property names and nonstandard NaN or Infinity values. It does not silently choose one of two conflicting duplicate fields. Inputs are limited to 4 KiB.
Run:
python fde-first-schema.py run --case syntaxRead first_stop: "parse". The schema and source stages say not-run. That is neither a pass nor a second diagnosis of the response.
4. Make the field rules explicit
The schema's properties entry describes the fields:
| Field | Shape rule | What that rule cannot establish |
|---|---|---|
source_id | Nonempty string, at most 40 characters | Whether the note exists or is accessible |
source_revision | Integer, at least 1 | Whether this is the current version |
condition | String: running, stopped or unknown | Whether the source supports that value |
evidence | Nonempty string, at most 180 characters | Whether the quote supports the claim |
All four fields also appear in required. Merely describing a property does not make it mandatory. additionalProperties is false here, so an unexpected execute property is refused.
Run these examples and predict the rule keyword first:
python fde-first-schema.py run --case wrong-type
python fde-first-schema.py run --case missing
python fde-first-schema.py run --case null
python fde-first-schema.py run --case extra
python fde-first-schema.py run --case enum| Change | First stop | Rule keyword |
|---|---|---|
Revision is "3" | Schema | type |
| Evidence is omitted | Schema | required |
Evidence is null | Schema | type |
Extra execute field | Schema | additionalProperties |
Condition is idle | Schema | enum |
Null is a value, not an omitted property. An enum is a permitted-value list, not a truth test. Validation does not fill missing knowledge or coerce a quoted number into an integer. The path /evidence identifies that field; / identifies a rule on the object itself.
5. Challenge a perfectly shaped response
python fde-first-schema.py run --case unsupported
python fde-first-schema.py run --case staleThe first response says stopped. That word is in the enum, so the schema passes. The note says running, so the separate source comparison holds it.
The second names revision 2. It is a valid positive integer, so the schema passes. The supplied source is revision 3, so the source check holds it.
This comparison is intentionally narrow: it checks the identifier, revision, condition and quote against explicit values for one fixture. It is not a general semantic evaluator, and it cannot determine whether arbitrary prose is true. In a real system, a quote may occur in a document without supporting the conclusion. The receiving workflow needs appropriate evidence and review.
The accepted outcome is supported-draft, not an executed action. Schema validity does not authenticate a caller, authorize a tool or prove that an external operation completed.
6. Change one value and explain the boundary
Save the example from section 1 as answer.json, then run:
python fde-first-schema.py check --file answer.jsonChange one thing at a time:
- Change
3to"3". Predict a type failure. - Restore the number, then change it to
2. Predict a source revision failure. - Restore revision 3, then omit evidence. Predict a required-field failure.
- Restore evidence, then use
null. Predict a type failure. - Restore the quote, then add an
executefield. Predict an additional-field failure.
The check command returns bounded diagnostics without echoing the submitted text. Its exit code indicates whether the command ran. Inspect first_stop and outcome for the response decision; a successful process exit is not acceptance of the response.
Keep the contract and source unchanged during this comparison. Changing the schema to make a failing response green changes what you are claiming to test.
7. Connect the exercise to a real model integration
A provider's structured-output feature may constrain generation to a supported shape. That differs from a prompt that simply says “return JSON.” This lab tests the local receiving checks with supplied responses; it does not exercise provider generation or measure a model.
When integrating a provider, verify its current schema support and completion states. Explicitly handle refusal and incomplete generation. A successful HTTP response does not alone establish complete usable content. Keep a bounded repair policy instead of retrying indefinitely.
Final structured responses and structured tool arguments have different consumers. The latter proposes a function's arguments; it grants no permission to run that function. Current access, source support and action policy remain application responsibilities.
8. Keep a receiving-engineer note
Keep:
- The schema version and meaning of each field.
- A response that stops at parsing, one at shape validation, and one at source comparison.
- A supported draft and an explanation of what it still cannot authorize.
- A proposed negative test for changed sources or a changed consumer contract.
The next lesson develops source acceptance and human review: Open structured-results practice. The advanced structured agent output lab uses actual LangChain ToolStrategy validation and repair.
Primary references
Checked 20 October 2026. These references support the concepts; the fictional note, exercise and teaching sequence are original LockedIn Labs material.