Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
Agents often produce structured data, not prose: a JSON object, a function-call schema, a row of fields. Free-form text outputs are fragile to parse, hallucinate fields, and break downstream code. Structured outputs (Anthropic 'tool use as response', OpenAI JSON mode, Outlines/Instructor for local models) force the model to emit data matching a schema. The result is bulletproof parsing and dramatically lower failure rates.
Patterns: (1) Tool calling as response — define an output tool with your schema; force the model to call it. (2) OpenAI structured outputs with response_format: json_schema. (3) Pydantic + Instructor for local validation. The trick: a schema with explicit field types and descriptions prevents 95% of 'the model gave me a string when I wanted a number' bugs. Combine with retry-on-validation-fail for the remaining 5%.
# --- Pick your provider (set the matching API key env var) ---
# Anthropic: from anthropic import Anthropic; client = Anthropic() # ANTHROPIC_API_KEY
# OpenAI: from openai import OpenAI; client = OpenAI() # OPENAI_API_KEY
# Gemini: from google import genai; client = genai.Client() # GEMINI_API_KEY
# Pattern: structured outputs via tool calling
from pydantic import BaseModel, Field
class TicketClassification(BaseModel):
category: str = Field(description="one of: billing, technical, sales, other")
urgency: int = Field(description="1-5, where 5 is most urgent")
summary: str = Field(description="1-sentence summary")
requires_human: bool = Field(description="true if a human should handle this")
# Anthropic: use tool calling to force structure
OUTPUT_TOOL = {
"name": "submit_classification",
"description": "Submit the classification result.",
"input_schema": TicketClassification.model_json_schema(),
}
def classify_ticket(ticket_text):
resp = client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=300,
tools=[OUTPUT_TOOL],
tool_choice={"type": "tool", "name": "submit_classification"}, # force this tool
messages=[{"role": "user", "content": f"Classify this ticket:\n{ticket_text}"}],
)
# The model MUST call submit_classification; the input is the structured result
for block in resp.content:
if block.type == "tool_use" and block.name == "submit_classification":
return TicketClassification(**block.input)
raise ValueError("no structured output returned")
# OpenAI: use response_format with json_schema (since gpt-4o-2024-08-06)
from openai import OpenAI
oai = OpenAI()
resp = oai.chat.completions.create(
model="gpt-4o-2024-08-06",
messages=[{"role": "user", "content": ticket}],
response_format={
"type": "json_schema",
"json_schema": {
"name": "ticket_classification",
"strict": True,
"schema": TicketClassification.model_json_schema(),
}
}
)
result = TicketClassification.parse_raw(resp.choices[0].message.content)python3 main.py