Appearance
Structured Output & Format Control
"Return your response as JSON" is not enough. The model needs to know the exact schema, what each field means, and what to do when data is missing. Structured output turns a text generator into a reliable API endpoint. This lesson covers JSON mode, XML tags, markdown formatting, and programmatic validation with Pydantic.

What you'll learn
- JSON mode (
response_format) forces valid JSON, but you still need to describe the schema - XML tags (
<finding>...</finding>) work well with Claude, which has strong XML parsing in training - Always validate the output against a schema before using it, Pydantic or a JSON Schema validator
Build it
JSON with schema description
Explicitly defining a JSON schema within the prompt ensures the model returns data in a predictable format.
python
prompt = """Analyze the following code. Return your response as JSON with this exact schema:
{
"bugs": [
{
"line": int,
"severity": "high" | "medium" | "low",
"description": "string explaining the bug",
"fix": "string with the suggested fix"
}
],
"style_issues": [
{"line": int, "rule": "string", "fix": "string"}
],
"summary": "one-sentence summary"
}
Code:
{code}"""Programmatic validation
Using Pydantic allows you to enforce strict validation rules on the structured output returned by the model.
python
from pydantic import BaseModel, Field
from typing import Literal
class Bug(BaseModel):
line: int
severity: Literal["high", "medium", "low"]
description: str
fix: str
class CodeReview(BaseModel):
bugs: list[Bug] = Field(default_factory=list)
style_issues: list[dict] = Field(default_factory=list)
summary: str
def review_code(code):
response = call_llm(prompt.format(code=code))
return CodeReview.model_validate_json(response)XML tags (Claude-optimized)
XML tags provide a robust alternative to JSON for structuring output, particularly when working with models trained heavily on markup.
python
prompt = """<task>Analyze the following code</task>
<code>{code}</code>
<format>
For each bug found:
<finding>
<severity>high|medium|low</severity>
<line>number</line>
<description>what's wrong</description>
<fix>how to fix it</fix>
</finding>
</format>"""What goes wrong
| Mistake | How you notice it | The fix |
|---|---|---|
| Model returns invalid JSON | json.loads() or Pydantic raises an error | Feed the error back: "Your response was not valid JSON. Please fix: {error}" |
| Model returns valid JSON but wrong schema | Missing fields, wrong types | Describe the schema explicitly. Use required fields. Validate with Pydantic |
| Model adds commentary outside the JSON | "Here's my analysis: {json}" | Add "Return ONLY the JSON object, no other text" to the prompt |
| JSON mode rejects valid-but-unusual values | response_format is too strict | Use Pydantic validation instead of API-level JSON mode for more flexibility |
Confirm it worked
Validate the parsed output against your expected data models to catch hallucinations or schema violations early.
python
response = review_code("print('hello')")
assert isinstance(response, CodeReview)
assert isinstance(response.bugs, list)
assert isinstance(response.summary, str)