Structured Output: Getting Reliable JSON from Claude
AI agents frequently need to parse Claude's output programmatically. Reliable structured output is not optional — it is the foundation of robust agentic pipelines.
Technique 1: Instruct + Parse
The simplest approach: instruct Claude to output JSON, then parse it.
import json
import anthropic
client = anthropic.Anthropic()
def extract_entities(text: str) -> dict:
response = client.messages.create(
model="claude-haiku-4-5",
max_tokens=1024,
system="""Extract entities from text.
Respond ONLY with valid JSON. No markdown, no explanation.
Schema: {"people": [], "organizations": [], "locations": [], "dates": []}""",
messages=[{"role": "user", "content": text}],
)
raw = response.content[0].text.strip()
# Remove markdown code fences if present
if raw.startswith("```"):
raw = raw.split("```")[1]
if raw.startswith("json"):
raw = raw[4:]
raw = raw.strip()
return json.loads(raw)
result = extract_entities(
"Apple CEO Tim Cook announced a new product in Cupertino on March 15th."
)
print(result)
# {"people": ["Tim Cook"], "organizations": ["Apple"], "locations": ["Cupertino"], "dates": ["March 15th"]}
Technique 2: Pydantic + Instructor
The instructor library wraps the Anthropic SDK and automatically validates output against a Pydantic schema:
import instructor
import anthropic
from pydantic import BaseModel, Field
client = instructor.from_anthropic(anthropic.Anthropic())
class ProductReview(BaseModel):
sentiment: str = Field(description="positive, negative, or neutral")
score: int = Field(ge=1, le=5, description="Rating from 1 to 5")
key_points: list[str] = Field(description="Main points from the review")
would_recommend: bool
review_text = "Great battery life and build quality. Camera could be better. Overall happy with purchase."
result = client.chat.completions.create(
model="claude-haiku-4-5",
max_tokens=512,
response_model=ProductReview,
messages=[{"role": "user", "content": f"Analyze this review: {review_text}"}],
)
print(result.sentiment) # positive
print(result.score) # 4
print(result.would_recommend) # True
JavaScript with Zod Validation
import Anthropic from "@anthropic-ai/sdk";
import { z } from "zod";
const client = new Anthropic();
const ContactSchema = z.object({
name: z.string(),
email: z.string().email(),
phone: z.string().optional(),
company: z.string().optional(),
});
async function extractContact(text: string) {
const response = await client.messages.create({
model: "claude-haiku-4-5",
max_tokens: 512,
system:
"Extract contact information as JSON. Output only valid JSON, no markdown.",
messages: [{ role: "user", content: text }],
});
const raw = response.content[0].text.trim();
const parsed = JSON.parse(raw);
return ContactSchema.parse(parsed); // Throws if schema invalid
}
const contact = await extractContact(
"Reach out to Sarah Chen at sarah@acme.com or call 555-0100."
);
Always validate parsed JSON against a schema. Never assume Claude's output matches your expected format without checking.