Dive into Anthropic's latest structured output features for Claude models. Learn JSON mode, tool use, and schema enforcement with practical Python and TypeScript examples to supercharge your AI apps.
Imagine you're building an app that needs precise, predictable responses from an AI like Claude. No more parsing messy free-form text or dealing with hallucinations in critical fields. Anthropic just dropped game-changing structured output capabilities on November 13, 2024, making it easier than ever to get JSON-formatted data that matches your exact schema.
These features work across Claude 3.5 Sonnet, Claude 3.7 Sonnet, Claude 4 Sonnet, Claude 3.5 Haiku, Claude 3 Haiku, and Claude 3 Opus. Whether you're extracting entities from emails, generating travel itineraries, or powering agentic workflows, structured outputs ensure reliability. Let's explore how to use them via the Anthropic Python SDK and TypeScript SDK.
Previously, developers relied on JSON mode to coax Claude into spitting out valid JSON. You'd set json_mode=True in the Messages API, but it wasn't foolproof—Claude might add extra text or fail on complex structures.
# Legacy JSON mode example (now deprecated)
message = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1024,
messages=[{"role": "user", "content": "Your prompt here"}],
json_mode=True
)
JSON mode is now deprecated in favor of structured outputs, which give you full control with JSON schemas and tool definitions. This shift aligns with industry standards, similar to OpenAI's structured outputs or tool calling, but Anthropic's implementation shines with schema strictness and broad model support.
At its core, structured outputs leverage tool use (Anthropic's take on function calling). You define tools with JSON schemas, and Claude decides when to invoke them. Key parameters:
tools: Array of tool objects, each with name, description, and input_schema (JSON schema).tool_choice: Controls invocation:
{"type": "auto"}: Claude chooses (default).{"type": "tool", "name": "your_tool"}: Force a specific tool.{"type": "any"}: Any tool.{"type": "none"}: No tools.When Claude calls a tool, the response includes tool_use content with id and input matching your schema.
Suppose you're processing customer support emails. You want to pull out names, emails, issues, and urgency levels reliably.
First, install the SDK: pip install anthropic.
import anthropic
import json
client = anthropic.Anthropic(api_key="your_key")
email_tools = [
{
"name": "email_entities",
"description": "Extract structured info from emails",
"input_schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"email": {"type": "string", "format": "email"},
"issue": {"type": "string"},
"urgency": {"type": "string", "enum": ["low", "medium", "high"]},
},
"required": ["name", "email", "issue", "urgency"],
"additionalProperties": False
}
}
]
response = client.beta.messages.create(
model="claude-3-7-sonnet-20241022",
max_tokens=1024,
tools=email_tools,
tool_choice="auto",
messages=[{"role": "user", "content": "Hi, I'm John Doe (john@example.com) having a login issue. Urgent!"}]
)
# Claude's tool call
if response.stop_reason == "tool_use":
tool_input = json.loads(response.content[0].input)
print(tool_input) # {'name': 'John Doe', 'email': 'john@example.com', ...}
This enforces the schema—no extra fields, valid email format, enum constraints. In production, you'd "execute" the tool by appending results back in a new message.
Need JSON without tools? Use json_schema directly in beta.messages.create.
response = client.beta.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1024,
json_schema={
"type": "object",
"properties": {
"greeting": {"type": "string"},
"mood": {"type": "string", "enum": ["happy", "sad"]},
},
"required": ["greeting", "mood"],
"additionalProperties": False
},
messages=[{"role": "user", "content": "Respond in JSON: Say hi and your mood."}]
)
print(response.json_schema.content[0].text) # Valid JSON
Claude guarantees the output validates against your schema. Add context: Schemas follow JSON Schema draft 2020-12, supporting types like object, array, string (with format, enum, pattern), number, boolean, null.
Let's build something practical—an app that crafts personalized itineraries. Define a detailed schema for flights, hotels, activities.
itinerary_schema = {
"type": "object",
"properties": {
"itinerary": {
"type": "array",
"items": {
"type": "object",
"properties": {
"day": {"type": "integer"},
"activities": {"type": "array", "items": {"type": "string"}},
"flight": {"type": "object", "properties": {"from": "string", "to": "string"}},
},
"required": ["day", "activities"]
}
}
},
"required": ["itinerary"]
}
response = client.beta.messages.create(
model="claude-3-5-haiku-20241022",
max_tokens=2048,
json_schema=itinerary_schema,
messages=[{"role": "user", "content": "Create a 3-day Paris itinerary from NYC, focus on food and art."}]
)
Output: Strictly structured array of days. Haiku handles this efficiently for cost-sensitive apps.
Structured outputs power agents. Claude can call multiple tools sequentially.
In a support bot:
Append tool results:
# After first tool call
messages.append({
"role": "user",
"content": [{"type": "tool_result", "tool_use_id": response.content[0].id, "content": "DB result: Account active"}]
})
# Second call
response2 = client.beta.messages.create(..., messages=messages)
This creates reliable, stateful agents. Pro tip: Use tool_choice to force chains.
Node.js devs, check the TS SDK examples.
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({ apiKey: 'your_key' });
const tools = [ /* same schema */ ];
const response = await client.beta.messages.create({
model: 'claude-3-7-sonnet-20241022',
max_tokens: 1024,
tools,
tool_choice: { type: 'auto' },
messages: [{ role: 'user', content: 'Your prompt' }],
});
Type safety via Zod-like schemas? TS infers perfectly.
temperature=0 for determinism.Real-world app: Integrate into LangChain or LlamaIndex for RAG with structured extraction.
Hands-on? Fork these:
Structured outputs eliminate post-processing hacks, reduce errors in production, and scale AI reliably. From fintech data extraction to e-commerce personalization, it's a must-have. Start experimenting today—your agents will thank you.
(Word count: ~1150)
Discover the essentials of Model Predictive Control (MPC), from its core principles and mathematical foundations to practical Python implementations for dynamic systems control.
Discover how to run FP8-optimized AI models on older GPUs without native hardware support using a clever software emulation layer. Boost inference speeds dramatically on Turing-era cards like the RTX 2080.
Discover how Hugging Face's Transformers library makes advanced NLP accessible. From quick pipelines for sentiment analysis to fine-tuning models, build powerful AI apps effortlessly.
Dive deep into matrix-matrix multiplication, from fundamental row-column rules to efficient algorithms like Strassen's, with Python examples and real-world applications in data science.
Dive into the exciting world of matrix transpose! Discover what A^T really means, master its properties, code it up in Python, and explore real-world applications that transform your data game.
Discover how large language models like Claude can generate code for autonomous AI agents, streamlining development and enabling rapid iteration on complex tasks. This approach turns manual coding into an automated, scalable process.
Workflows from the Neura Market marketplace related to this ChatGPT resource