Skip to main content
Watch: Claude Code Just Killed After Effects
Structured Output

Get structured output from LLMs with Anthropic

Anthropic's Claude models support structured output through tool use with forced tool calls. Define a schema as a tool, force Claude to use it, and extract the structured data from the tool call arguments.

Prerequisites

  • +Node 20+ or Python 3.10+
  • +Anthropic API key
  • +Understanding of Zod or JSON Schema

Step-by-Step

  1. 1

    Install the SDK

    The official Anthropic SDK handles schema conversion.

    pnpm add @anthropic-ai/sdk zod
  2. 2

    Define a tool for structured extraction

    Create a tool whose input schema matches your desired output structure.

    import Anthropic from '@anthropic-ai/sdk';
    import { z } from 'zod';
    import { zodToJsonSchema } from 'zod-to-json-schema';
    
    const ExtractedData = z.object({
      name: z.string(),
      email: z.string().email(),
      company: z.string(),
      interests: z.array(z.string()),
    });
    
    const tool = {
      name: 'extract_contact',
      description: 'Extract structured contact information from text',
      input_schema: zodToJsonSchema(ExtractedData),
    };
  3. 3

    Force the tool call

    Use tool_choice to make Claude always use your extraction tool.

    const client = new Anthropic();
    const message = await client.messages.create({
      model: 'claude-sonnet-4-5-20250514',
      max_tokens: 1024,
      tools: [tool],
      tool_choice: { type: 'tool', name: 'extract_contact' },
      messages: [{
        role: 'user',
        content: 'Extract contact info: John Smith, john@acme.com, works at Acme Corp, interested in AI and ML'
      }],
    });
  4. 4

    Parse the tool call arguments

    The structured data is in the tool_use content block's input field.

    const toolUse = message.content.find((b) => b.type === 'tool_use');
    if (toolUse && toolUse.type === 'tool_use') {
      const data = ExtractedData.parse(toolUse.input);
      console.log(data.name, data.email);
    }
  5. 5

    Add validation with Zod

    Always validate the extracted data against your schema. Claude follows schemas closely but validation adds safety.

    try {
      const validated = ExtractedData.parse(toolUse.input);
    } catch (e) {
      console.error('Extraction failed validation:', e);
    }
  6. 6

    Handle complex nested structures

    Claude handles nested objects and arrays well. Keep descriptions clear for each field.

    const Order = z.object({
      customer: z.object({ name: z.string(), address: z.string() }),
      items: z.array(z.object({ product: z.string(), quantity: z.number(), price: z.number() })),
      total: z.number(),
    });

Common Pitfalls

  • !Forgetting tool_choice - without it, Claude may respond with text instead of using the tool.
  • !Overly complex schemas without descriptions. Claude needs context to fill fields correctly.
  • !Not handling the case where the model cannot extract required fields (validation will fail).
  • !Using stop_sequences that interrupt the tool call JSON.
From the Developers Digest stack

DevDigest Academy

Structured AI engineering courses with hands-on labs. Build production-ready apps faster.

What's Next

  • ->Build extraction chains that process documents in batches.
  • ->Combine with Claude's extended thinking for complex extraction tasks.
  • ->Add post-processing validation for business rules beyond schema.

Compare Tools

    More Get structured output from LLMs

    AI Development Stack

    Get Smarter About AI Dev

    New tutorials, open-source projects, and deep dives on coding agents - delivered weekly.

    One email per weekReal code, not theoryFree forever