Extract structured data from Claude in Python using Pydantic models, JSON schema via tool_use, and TypedDict. Working code examples with validation. Updated for Claude Sonnet 4.6 and claude-haiku-4-5.
Claude doesn't have a JSON mode flag, but the tool_use pattern with forced tool choice gives you guaranteed structured output with full schema validation.
import anthropic
from pydantic import BaseModel
client = anthropic.Anthropic()
class ProductInfo(BaseModel):
name: str
price_usd: float
category: str
in_stock: bool
tags: list[str]
# Get JSON schema from Pydantic
schema = ProductInfo.model_json_schema()
# Force Claude to populate the schema
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=512,
tools=[{
"name": "extract_product",
"description": "Extract product information from text.",
"input_schema": schema
}],
tool_choice={"type": "tool", "name": "extract_product"},
messages=[{
"role": "user",
"content": "Parse: 'Ergonomic Mesh Chair – $249.99, Furniture, currently available. Tags: office, ergonomic, adjustable'"
}]
)
for block in response.content:
if block.type == "tool_use":
product = ProductInfo(**block.input)
print(product)
# ProductInfo(name='Ergonomic Mesh Chair', price_usd=249.99, category='Furniture', in_stock=True, tags=['office', 'ergonomic', 'adjustable'])
schema = {
"type": "object",
"properties": {
"sentiment": {"type": "string", "enum": ["positive", "negative", "neutral"]},
"confidence": {"type": "number", "minimum": 0, "maximum": 1},
"key_phrases": {"type": "array", "items": {"type": "string"}},
"summary": {"type": "string"}
},
"required": ["sentiment", "confidence", "key_phrases", "summary"]
}
response = client.messages.create(
model="claude-haiku-4-5-20251001", # Haiku is fast + cheap for classification
max_tokens=256,
tools=[{"name": "analyze_sentiment", "description": "Analyze sentiment.", "input_schema": schema}],
tool_choice={"type": "tool", "name": "analyze_sentiment"},
messages=[{"role": "user", "content": "The product arrived damaged and support took 3 weeks to respond. Terrible experience."}]
)
for block in response.content:
if block.type == "tool_use":
print(block.input)
# {'sentiment': 'negative', 'confidence': 0.97, 'key_phrases': ['arrived damaged', 'support took 3 weeks'], 'summary': 'Customer received damaged product with slow support response.'}
schema = {
"type": "object",
"properties": {
"company": {"type": "string"},
"founded": {"type": "integer"},
"headquarters": {
"type": "object",
"properties": {
"city": {"type": "string"},
"country": {"type": "string"}
},
"required": ["city", "country"]
},
"executives": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"title": {"type": "string"}
},
"required": ["name", "title"]
}
}
},
"required": ["company", "founded", "headquarters", "executives"]
}
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=512,
tools=[{"name": "extract_company", "description": "Extract company info.", "input_schema": schema}],
tool_choice={"type": "tool", "name": "extract_company"},
messages=[{
"role": "user",
"content": "Anthropic was founded in 2021 and is headquartered in San Francisco, USA. Key leaders: Dario Amodei (CEO) and Daniela Amodei (President)."
}]
)
from concurrent.futures import ThreadPoolExecutor
texts = [
"Great product, fast shipping! Love the quality.",
"Broke after one week. Cheap materials.",
"OK for the price. Nothing special.",
]
def classify(text):
r = client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=128,
tools=[{"name": "classify", "description": "Classify sentiment.", "input_schema": schema}],
tool_choice={"type": "tool", "name": "classify"},
messages=[{"role": "user", "content": text}]
)
for b in r.content:
if b.type == "tool_use":
return b.input
return None
with ThreadPoolExecutor(max_workers=5) as pool:
results = list(pool.map(classify, texts))
for text, result in zip(texts, results):
print(f"{result['sentiment']:8s} | {text[:50]}")
For cost estimates on high-volume structured extraction jobs, use the Claude API Cost Calculator. For the full tool_use reference, see the tool use deep-dive. For batch processing large datasets, see Claude Batch API.