SpyBara
Go Premium

agent-sdk/structured-outputs.md 2026-11-09 23:02 UTC to 2026-11-10 21:57 UTC

This page contains 48 additions and 27 deletions.

2026
Tue 10 21:57

Strukturierte Ausgaben von Agenten abrufen

Validiertes JSON aus Agent-Workflows mit JSON Schema, Zod oder Pydantic zurückgeben. Erhalten Sie typsichere, strukturierte Daten nach Multi-Turn-Tool-Nutzung.

Strukturierte Ausgaben ermöglichen es Ihnen, die genaue Form der Daten zu definieren, die Sie von einem Agenten zurückerhalten möchten. Der Agent kann alle erforderlichen Tools verwenden, um die Aufgabe zu erfüllen, und Sie erhalten am Ende immer noch validiertes JSON, das Ihrem Schema entspricht. Definieren Sie ein JSON Schema für die benötigte Struktur, und das SDK validiert die Ausgabe dagegen und fordert bei Nichtübereinstimmung erneut auf. Wenn die Validierung nicht innerhalb des Wiederholungslimits erfolgreich ist, ist das Ergebnis ein Fehler statt strukturierter Daten; siehe Fehlerbehandlung.

Für vollständige Typsicherheit verwenden Sie Zod (TypeScript) oder Pydantic (Python), um Ihr Schema zu definieren und stark typisierte Objekte zurückzuerhalten.

Warum strukturierte Ausgaben?

Agenten geben standardmäßig Freitext zurück. Das funktioniert für Chats, aber nicht, wenn Sie die Ausgabe programmatisch verwenden müssen. Strukturierte Ausgaben liefern Ihnen typisierte Daten, die Sie direkt an Ihre Anwendungslogik, Datenbank oder UI-Komponenten übergeben können.

Nehmen Sie als Beispiel eine Rezept-App, in der ein Agent das Web durchsucht und Rezepte zurückliefert. Ohne strukturierte Ausgaben erhalten Sie Freitext, den Sie selbst parsen müssten. Mit strukturierten Ausgaben definieren Sie die gewünschte Form und erhalten typisierte Daten, die Sie direkt in Ihrer App verwenden können.

[accordion] Ohne strukturierte Ausgaben

Here's a classic chocolate chip cookie recipe!

**Chocolate Chip Cookies**
Prep time: 15 minutes | Cook time: 10 minutes

Ingredients:
- 2 1/4 cups all-purpose flour
- 1 cup butter, softened
...

Um dies in Ihrer App zu verwenden, müssten Sie den Titel herausparsen, „15 minutes“ in eine Zahl umwandeln, Zutaten von Anweisungen trennen und mit uneinheitlicher Formatierung zwischen verschiedenen Antworten umgehen.

[accordion] Mit strukturierten Ausgaben

{
  "name": "Chocolate Chip Cookies",
  "prep_time_minutes": 15,
  "cook_time_minutes": 10,
  "ingredients": [
    { "item": "all-purpose flour", "amount": 2.25, "unit": "cups" },
    { "item": "butter, softened", "amount": 1, "unit": "cup" }
    // ...
  ],
  "steps": ["Preheat oven to 375°F", "Cream butter and sugar" /* ... */]
}

Typisierte Daten, die Sie direkt in Ihrer UI verwenden können.

Schnellstart

Um strukturierte Ausgaben zu verwenden, definieren Sie ein JSON Schema, das die Form der gewünschten Daten beschreibt, und übergeben Sie es dann an query() über die Option outputFormat (TypeScript) oder output_format (Python). Wenn der Agent fertig ist, enthält die Ergebnismeldung ein Feld structured_output mit validierten Daten, die Ihrem Schema entsprechen.

Bevor Sie die Beispiele auf dieser Seite ausführen, installieren Sie das Claude Agent SDK, indem Sie dem Schnellstart folgen. Das folgende Beispiel fordert den Agenten auf, Anthropic zu recherchieren und den Firmennamen, das Gründungsjahr und den Hauptsitz als strukturierte Ausgabe zurückzugeben.

import { query } from "@anthropic-ai/claude-agent-sdk";

// Definieren Sie die Form der Daten, die Sie zurückerhalten möchten
const schema = {
  type: "object",
  properties: {
    company_name: { type: "string" },
    founded_year: { type: "number" },
    headquarters: { type: "string" }
  },
  required: ["company_name"]
};

try {
  for await (const message of query({
    prompt: "Research Anthropic and provide key company information",
    options: {
      outputFormat: {
        type: "json_schema",
        schema: schema
      }
    }
  })) {
    // Die Ergebnismeldung enthält structured_output mit validierten Daten
    if (message.type === "result" && message.subtype === "success" && !message.is_error && message.structured_output) {
      console.log(message.structured_output);
      // { company_name: "Anthropic", founded_year: 2021, headquarters: "San Francisco, CA" }
    }
  }
} catch (error) {
  // Eine einzelne query() wirft einen Fehler, nachdem ein Fehlerergebnis ausgegeben wurde, z. B.
  // error_max_structured_output_retries; siehe den Abschnitt Fehlerbehandlung.
  console.error(`Session ended with an error: ${error}`);
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage

# Definieren Sie die Form der Daten, die Sie zurückerhalten möchten
schema = {
    "type": "object",
    "properties": {
        "company_name": {"type": "string"},
        "founded_year": {"type": "number"},
        "headquarters": {"type": "string"},
    },
    "required": ["company_name"],
}


async def main():
    try:
        async for message in query(
            prompt="Research Anthropic and provide key company information",
            options=ClaudeAgentOptions(
                output_format={"type": "json_schema", "schema": schema}
            ),
        ):
            # Die Ergebnismeldung enthält structured_output mit validierten Daten
            if (
                isinstance(message, ResultMessage)
                and not message.is_error
                and message.structured_output
            ):
                print(message.structured_output)
                # {'company_name': 'Anthropic', 'founded_year': 2021, 'headquarters': 'San Francisco, CA'}
    except Exception as error:
        # Eine einzelne query() wirft einen Fehler, nachdem ein Fehlerergebnis ausgegeben wurde, z. B.
        # error_max_structured_output_retries; siehe den Abschnitt Fehlerbehandlung.
        print(f"Session ended with an error: {error}")


asyncio.run(main())

Typsichere Schemas mit Zod und Pydantic

Anstatt JSON Schema von Hand zu schreiben, können Sie Zod (TypeScript) oder Pydantic (Python) verwenden, um Ihr Schema zu definieren. Diese Bibliotheken generieren das JSON Schema für Sie und ermöglichen es Ihnen, die Antwort in ein vollständig typisiertes Objekt zu analysieren, das Sie in Ihrer gesamten Codebasis mit Autovervollständigung und Typprüfung verwenden können.

Das folgende Beispiel definiert ein Schema für einen Implementierungsplan für Features mit einer Zusammenfassung, einer Liste von Schritten (jeweils mit Komplexitätsstufe) und potenziellen Risiken. Der Agent plant das Feature und gibt ein typisiertes FeaturePlan-Objekt zurück. Sie können dann auf Eigenschaften wie plan.summary zugreifen und über plan.steps mit vollständiger Typsicherheit iterieren.

Das SDK validiert Schemas mit JSON Schema draft-07, daher werden Schemas, die eine neuere Version deklarieren, abgelehnt. Zod zielt standardmäßig auf draft 2020-12 ab, daher übergeben Sie target: "draft-7" beim Konvertieren Ihres Schemas.

import { z } from "zod";
import { query } from "@anthropic-ai/claude-agent-sdk";

// Definieren Sie das Schema mit Zod
const FeaturePlan = z.object({
  feature_name: z.string(),
  summary: z.string(),
  steps: z.array(
    z.object({
      step_number: z.number(),
      description: z.string(),
      estimated_complexity: z.enum(["low", "medium", "high"])
    })
  ),
  risks: z.array(z.string())
});

type FeaturePlan = z.infer<typeof FeaturePlan>;

// Konvertieren Sie zu JSON Schema mit dem draft-07-Ziel, das das SDK erwartet
const schema = z.toJSONSchema(FeaturePlan, { target: "draft-7" });

// Verwenden Sie in der Abfrage
try {
  for await (const message of query({
    prompt:
      "Plan how to add dark mode support to a React app. Break it into implementation steps.",
    options: {
      outputFormat: {
        type: "json_schema",
        schema: schema
      }
    }
  })) {
    if (message.type === "result" && message.subtype === "success" && !message.is_error && message.structured_output) {
      // Validieren Sie und erhalten Sie ein vollständig typisiertes Ergebnis
      const parsed = FeaturePlan.safeParse(message.structured_output);
      if (parsed.success) {
        const plan: FeaturePlan = parsed.data;
        console.log(`Feature: ${plan.feature_name}`);
        console.log(`Summary: ${plan.summary}`);
        plan.steps.forEach((step) => {
          console.log(`${step.step_number}. [${step.estimated_complexity}] ${step.description}`);
        });
      }
    }
  }
} catch (error) {
  // Eine einzelne query() wirft nach dem Ausgeben eines Fehlerergebnisses, wie z. B.
  // error_max_structured_output_retries; siehe den Abschnitt Fehlerbehandlung.
  console.error(`Session ended with an error: ${error}`);
}
import asyncio
from pydantic import BaseModel
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage


class Step(BaseModel):
    step_number: int
    description: str
    estimated_complexity: str  # 'low', 'medium', 'high'


class FeaturePlan(BaseModel):
    feature_name: str
    summary: str
    steps: list[Step]
    risks: list[str]


async def main():
    try:
        async for message in query(
            prompt="Plan how to add dark mode support to a React app. Break it into implementation steps.",
            options=ClaudeAgentOptions(
                output_format={
                    "type": "json_schema",
                    "schema": FeaturePlan.model_json_schema(),
                }
            ),
        ):
            if (
                isinstance(message, ResultMessage)
                and not message.is_error
                and message.structured_output
            ):
                # Validieren Sie und erhalten Sie ein vollständig typisiertes Ergebnis
                plan = FeaturePlan.model_validate(message.structured_output)
                print(f"Feature: {plan.feature_name}")
                print(f"Summary: {plan.summary}")
                for step in plan.steps:
                    print(
                        f"{step.step_number}. [{step.estimated_complexity}] {step.description}"
                    )
    except Exception as error:
        # Eine einzelne query() wird nach dem Ausgeben eines Fehlerergebnisses ausgelöst, wie z. B.
        # error_max_structured_output_retries; siehe den Abschnitt Fehlerbehandlung.
        print(f"Session ended with an error: {error}")


asyncio.run(main())

Konfiguration des Ausgabeformats

Die Option outputFormat (TypeScript) oder output_format (Python) akzeptiert ein Objekt mit:

  • type: Setzen Sie auf "json_schema" für strukturierte Ausgaben
  • schema: Ein JSON Schema-Objekt, das Ihre Ausgabestruktur definiert. Sie können dies aus einem Zod-Schema mit z.toJSONSchema(schema, { target: "draft-7" }) oder einem Pydantic-Modell mit .model_json_schema() generieren

Das SDK unterstützt Standard-JSON-Schema-Funktionen, einschließlich aller grundlegenden Typen (object, array, string, number, boolean, null), enum, const, required, verschachtelte Objekte und $ref-Definitionen. Die vollständige Liste der unterstützten Funktionen und Einschränkungen finden Sie unter JSON Schema-Einschränkungen.

Ein Schema, das kein gültiges JSON Schema ist, führt beim Start zu einem Fehler, der das Problem benennt. Vor v2.1.205 wurde ein ungültiges Schema stillschweigend ignoriert und der Agent gab unstrukturierten Text zurück.

Das Schlüsselwort format, wie z. B. "format": "email", wird als Anmerkung akzeptiert und wird vom Validator des SDK nicht erzwungen. Vor v2.1.205 wurde jedes Schema, das format enthielt, als ungültig behandelt.

Beispiel: TODO-Tracking-Agent

Dieses Beispiel zeigt, wie strukturierte Ausgaben mit Multi-Step-Tool-Nutzung funktionieren. Der Agent muss TODO-Kommentare in der Codebasis finden und dann für jeden Git-Blame-Informationen nachschlagen. Er entscheidet autonom, welche Tools er verwenden soll (Grep zum Suchen, Bash zum Ausführen von Git-Befehlen) und kombiniert die Ergebnisse in eine einzelne strukturierte Antwort.

Das Schema enthält optionale Felder (author und date), da Git-Blame-Informationen möglicherweise nicht für alle Dateien verfügbar sind. Der Agent füllt aus, was er finden kann, und lässt den Rest weg.

import { query } from "@anthropic-ai/claude-agent-sdk";

// Define structure for TODO extraction
const todoSchema = {
  type: "object",
  properties: {
    todos: {
      type: "array",
      items: {
        type: "object",
        properties: {
          text: { type: "string" },
          file: { type: "string" },
          line: { type: "number" },
          author: { type: "string" },
          date: { type: "string" }
        },
        required: ["text", "file", "line"]
      }
    },
    total_count: { type: "number" }
  },
  required: ["todos", "total_count"]
};

// Agent uses Grep to find TODOs, Bash to get git blame info
try {
  for await (const message of query({
    prompt: "Find all TODO comments in this codebase and identify who added them",
    options: {
      outputFormat: {
        type: "json_schema",
        schema: todoSchema
      }
    }
  })) {
    if (message.type === "result" && message.subtype === "success" && !message.is_error && message.structured_output) {
      const data = message.structured_output as { total_count: number; todos: Array<{ file: string; line: number; text: string; author?: string; date?: string }> };
      console.log(`Found ${data.total_count} TODOs`);
      data.todos.forEach((todo) => {
        console.log(`${todo.file}:${todo.line} - ${todo.text}`);
        if (todo.author) {
          console.log(`  Added by ${todo.author} on ${todo.date}`);
        }
      });
    }
  }
} catch (error) {
  // A single-shot query() throws after yielding an error result, such as
  // error_max_structured_output_retries; see the Error handling section.
  console.error(`Session ended with an error: ${error}`);
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage

# Define structure for TODO extraction
todo_schema = {
    "type": "object",
    "properties": {
        "todos": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "text": {"type": "string"},
                    "file": {"type": "string"},
                    "line": {"type": "number"},
                    "author": {"type": "string"},
                    "date": {"type": "string"},
                },
                "required": ["text", "file", "line"],
            },
        },
        "total_count": {"type": "number"},
    },
    "required": ["todos", "total_count"],
}


async def main():
    # Agent uses Grep to find TODOs, Bash to get git blame info
    try:
        async for message in query(
            prompt="Find all TODO comments in this codebase and identify who added them",
            options=ClaudeAgentOptions(
                output_format={"type": "json_schema", "schema": todo_schema}
            ),
        ):
            if (
                isinstance(message, ResultMessage)
                and not message.is_error
                and message.structured_output
            ):
                data = message.structured_output
                print(f"Found {data['total_count']} TODOs")
                for todo in data["todos"]:
                    print(f"{todo['file']}:{todo['line']} - {todo['text']}")
                    if "author" in todo:
                        print(f"  Added by {todo['author']} on {todo['date']}")
    except Exception as error:
        # A single-shot query() raises after yielding an error result, such as
        # error_max_structured_output_retries; see the Error handling section.
        print(f"Session ended with an error: {error}")


asyncio.run(main())

Den StructuredOutput-Tool-Aufruf erkennen

Wenn Sie outputFormat in TypeScript oder output_format in Python festlegen, enthält Ihr Nachrichtenstream einen Tool-Aufruf namens StructuredOutput, den Sie nie definiert haben. Claude Code fügt dieses Tool der Sitzung hinzu, und der Agent ruft es auf, um seine Antwort zurückzugeben. Die System-Init-Nachricht führt es im Array tools auf, und jeder Aufruf kommt als zwei Blöcke an:

  • Ein tool_use-Block namens StructuredOutput, dessen Eingabe das Objekt ist, das der Agent für Ihr Schema erzeugt hat
  • Ein tool_result-Block mit dem Inhalt Structured output provided successfully

Wenn dieses Objekt nicht Ihrem Schema entspricht, enthält das tool_result stattdessen is_error: true, und der Agent ruft StructuredOutput erneut auf, sodass Ihr Stream mehrere Aufrufe für eine Abfrage enthalten kann. Lesen Sie die validierten Daten aus structured_output in der Ergebnisnachricht statt aus einem tool_use-Block, und unter Fehlerbehandlung finden Sie das Ergebnis, das Sie erhalten, wenn kein Versuch erfolgreich ist.

Wenn Ihre Anwendung Tool-Aufrufe anzeigt oder protokolliert, überspringen Sie diejenigen mit dem Namen StructuredOutput, damit der Mechanismus nicht als Schritt erscheint, den der Agent gewählt hat. Ein tool_result-Block enthält keinen Tool-Namen, sondern nur die tool_use_id des Aufrufs, auf den er antwortet. Gleichen Sie diese daher mit der id jedes übersprungenen Aufrufs ab.

Fehlerbehandlung

Die Generierung strukturierter Ausgaben kann fehlschlagen, wenn der Agent kein gültiges JSON erzeugen kann, das Ihrem Schema entspricht. Dies geschieht normalerweise, wenn das Schema für die Aufgabe zu komplex ist, die Aufgabe selbst mehrdeutig ist, oder der Agent sein Wiederholungslimit beim Versuch, Validierungsfehler zu beheben, erreicht. Es kann auch ohne Validierungsfehler geschehen: Ein Modell-Fallback kann eine bereits abgeschlossene Ausgabe mitten im Stream zurückziehen, und wenn kein erfolgreicher Wiederholungsversuch sie ersetzt, endet der Durchlauf mit demselben Fehler. Überprüfen Sie die errors-Liste der Fehler-Ergebnismeldung, um die beiden Ursachen auseinanderzuhalten, bevor Sie Ihr Schema debuggen.

Überprüfen Sie den subtype der Ergebnismeldung:

Subtype Bedeutung
success Der Durchlauf endete ohne einen Fehler-Subtype
error_max_structured_output_retries Keine gültige Ausgabe überstand mehrere Versuche (Validierungsfehler oder ein Modell-Fallback-Rückzug ohne erfolgreichen Wiederholungsversuch)

Ein success-Subtype allein bedeutet nicht, dass der Durchlauf eine Antwort erzeugt hat. Behandeln Sie ein Ergebnis als Fehler, wenn is_error des Ergebnisses true ist oder structured_output fehlt:

  • is_error des Ergebnisses ist true: Beispielsweise endete die letzte Modellanfrage mit einem API-Fehler oder einer Ablehnung. Verwenden Sie bei einem solchen Ergebnis keinen structured_output-Wert.
  • structured_output fehlt: Um die Ursache zu finden, siehe structured_output ist None, aber das Ergebnis sagt success

Das folgende Beispiel wendet diese Prüfungen an:

import { query } from "@anthropic-ai/claude-agent-sdk";

const contactSchema = {
  type: "object",
  properties: {
    name: { type: "string" },
    email: { type: "string" }
  },
  required: ["name"]
};

try {
  for await (const msg of query({
    prompt: "Extract contact info from the document",
    options: {
      outputFormat: {
        type: "json_schema",
        schema: contactSchema
      }
    }
  })) {
    if (msg.type === "result") {
      if (msg.subtype === "success" && !msg.is_error && msg.structured_output) {
        // Use the validated output
        console.log(msg.structured_output);
      } else if (msg.subtype === "error_max_structured_output_retries") {
        console.error("Could not produce valid output");
      } else {
        console.error("Run ended with an error or without a structured output");
      }
    }
  }
} catch (error) {
  // A single-shot query() throws after yielding an error result. If the
  // failure was an error result, the error subtype branches above have
  // already run; connection or process failures yield no result message.
  console.log(`Session ended with an error: ${error}`);
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage

contact_schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "email": {"type": "string"},
    },
    "required": ["name"],
}


async def main():
    try:
        async for message in query(
            prompt="Extract contact info from the document",
            options=ClaudeAgentOptions(
                output_format={"type": "json_schema", "schema": contact_schema}
            ),
        ):
            if isinstance(message, ResultMessage):
                if (
                    message.subtype == "success"
                    and not message.is_error
                    and message.structured_output
                ):
                    # Use the validated output
                    print(message.structured_output)
                elif message.subtype == "error_max_structured_output_retries":
                    print("Could not produce valid output")
                else:
                    print("Run ended with an error or without a structured output")
    except Exception as error:
        # A single-shot query() raises after yielding an error result. If the
        # failure was an error result, the error subtype branches above have
        # already run; connection or process failures yield no result message.
        print(f"Session ended with an error: {error}")


asyncio.run(main())

Tipps zur Vermeidung von Fehlern:

  • Halten Sie Schemas fokussiert. Tief verschachtelte Schemas mit vielen erforderlichen Feldern sind schwerer zu erfüllen. Beginnen Sie einfach und fügen Sie Komplexität nach Bedarf hinzu.
  • Passen Sie das Schema an die Aufgabe an. Wenn die Aufgabe möglicherweise nicht alle Informationen hat, die Ihr Schema erfordert, machen Sie diese Felder optional.
  • Verwenden Sie klare Prompts. Mehrdeutige Prompts machen es für den Agenten schwieriger zu wissen, welche Ausgabe er erzeugen soll.

Verwandte Ressourcen

  • JSON Schema-Dokumentation: Erfahren Sie mehr über JSON Schema-Syntax zum Definieren komplexer Schemas mit verschachtelten Objekten, Arrays, Enums und Validierungsbeschränkungen
  • API Structured Outputs: Verwenden Sie strukturierte Ausgaben direkt mit der Claude API für Single-Turn-Anfragen ohne Tool-Nutzung
  • Custom tools: Geben Sie Ihrem Agenten benutzerdefinierte Tools, die während der Ausführung aufgerufen werden können, bevor strukturierte Ausgaben zurückgegeben werden