IzziAPI
TutorialApr 11, 20267 min read

How to Get Structured JSON Output from AI APIs

Extract reliable, typed JSON from Claude, GPT, and Gemini using tool_use, response schemas, and Pydantic validation.

Izzi API Team
Engineering & DevRel
jsonstructured-outputtool-usepydanticizzi-api
How to Get Structured JSON Output from AI APIs

The problem with unstructured AI output

AI models return free-form text. If your app expects JSON, the model might return Here's the JSON: {...} with extra text, or worse — malformed JSON. Here are three reliable patterns to get structured output every time.

Pattern 1: JSON mode (OpenAI-compatible)

Python
from openai import OpenAI

client = OpenAI(
    api_key="izzi-YOUR_KEY_HERE",
    base_url="https://api.izziapi.com/v1"
)

response = client.chat.completions.create(
    model="gpt-5.4",
    response_format={"type": "json_object"},
    messages=[{
        "role": "user",
        "content": 'Extract entities from this text and return as JSON with keys "people", "places", "dates": The meeting with John in Paris on March 15th...'
    }]
)

import json
data = json.loads(response.choices[0].message.content)
print(data["people"])   # ["John"]
print(data["places"])   # ["Paris"]

Pattern 2: Tool use (Claude — most reliable)

Python
import anthropic

client = anthropic.Anthropic(
    api_key="izzi-YOUR_KEY_HERE",
    base_url="https://api.izziapi.com/anthropic"
)

response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1000,
    tools=[{
        "name": "extract_info",
        "description": "Extract structured information from text",
        "input_schema": {
            "type": "object",
            "properties": {
                "sentiment": {"type": "string", "enum": ["positive", "negative", "neutral"]},
                "topics": {"type": "array", "items": {"type": "string"}},
                "confidence": {"type": "number", "minimum": 0, "maximum": 1}
            },
            "required": ["sentiment", "topics", "confidence"]
        }
    }],
    tool_choice={"type": "tool", "name": "extract_info"},
    messages=[{
        "role": "user",
        "content": "Analyze: The new API is incredibly fast but the docs are confusing."
    }]
)

# Tool use guarantees valid JSON matching the schema
result = response.content[0].input
print(result)
# {"sentiment": "neutral", "topics": ["API", "performance", "documentation"], "confidence": 0.85}

Pattern 3: Pydantic validation (safety net)

Python
from pydantic import BaseModel, Field
from openai import OpenAI
import json

class CodeReview(BaseModel):
    severity: str = Field(description="critical, major, minor, or nitpick")
    file: str = Field(description="File path")
    line: int = Field(description="Line number")
    issue: str = Field(description="What's wrong")
    fix: str = Field(description="How to fix it")

def get_structured_review(code: str) -> list[CodeReview]:
    response = client.chat.completions.create(
        model="claude-sonnet-4-20250514",
        messages=[{
            "role": "user",
            "content": f"Review this code. Return a JSON array of issues: {code}"
        }],
        max_tokens=2000
    )
    
    raw = response.choices[0].message.content
    # Strip markdown code fences if present
    raw = raw.strip().removeprefix("```json").removesuffix("```").strip()
    
    issues = json.loads(raw)
    return [CodeReview(**issue) for issue in issues]

Which pattern to use

PatternReliabilityModel supportBest for
JSON modeHighGPT-5, GeminiSimple JSON output
Tool useHighestClaude (best), GPT-5Guaranteed schema compliance
Pydantic validationMedium + safetyAny modelPost-processing validation

What's next

Ready to start building?

Access 38+ AI models through a single API. Free tier available — no credit card required.

MORE

Related articles