SpyBara
Go Premium

agent-sdk/structured-outputs.md 2026-10-29 23:57 UTC to 2026-10-30 23:01 UTC

This page contains 2 additions and 2 deletions.

2026
Wed 7 23:59 Tue 20 23:00 Wed 21 23:02 Thu 22 22:58 Fri 23 22:59 Fri 30 23:01

エージェントから構造化された出力を取得する

JSON Schema、Zod、または Pydantic を使用して、エージェントワークフローから検証済みの JSON を返します。マルチターンツール使用後に型安全で構造化されたデータを取得します。

構造化された出力を使用すると、エージェントから返してほしいデータの正確な形状を定義できます。エージェントはタスクを完了するために必要なツールを使用でき、最後にスキーマに一致する検証済み JSON を取得できます。必要な構造の JSON Schema を定義すると、SDK は出力をそれに対して検証し、不一致の場合は再プロンプトします。検証が再試行制限内に成功しない場合、結果は構造化データではなくエラーになります。エラーハンドリング を参照してください。

完全な型安全性のために、Zod(TypeScript)または Pydantic(Python)を使用してスキーマを定義し、強く型付けされたオブジェクトを取得します。

構造化された出力が必要な理由

エージェントはデフォルトでは自由形式のテキストを返します。これはチャットには機能しますが、出力をプログラムで使用する必要がある場合には機能しません。構造化された出力は、アプリケーションロジック、データベース、または UI コンポーネントに直接渡すことができる型付きデータを提供します。

エージェントがウェブを検索してレシピを取得するレシピアプリを考えてみてください。構造化された出力がない場合、自分で解析する必要がある自由形式のテキストが得られます。構造化された出力を使用すると、必要な形状を定義し、アプリで直接使用できる型付きデータを取得できます。

[accordion] 構造化された出力なし

これは古典的なチョコレートチップクッキーのレシピです!

**チョコレートチップクッキー**
準備時間:15 分 | 調理時間:10 分

材料:
- 2 1/4 カップ 薄力粉
- 1 カップ バター、柔らかくしたもの
...

これをアプリで使用するには、タイトルを解析し、'15 分'を数値に変換し、材料と手順を分離し、応答全体で一貫性のない形式を処理する必要があります。

[accordion] 構造化された出力あり

{
  "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" /* ... */]
}

UI で直接使用できる型付きデータ。

クイックスタート

構造化された出力を使用するには、必要なデータの形状を説明する JSON Schema を定義し、outputFormat オプション(TypeScript)または output_format オプション(Python)を使用して query() に渡します。エージェントが完了すると、結果メッセージにはスキーマに一致する検証済みデータを含む structured_output フィールドが含まれます。

このページの例を実行する前に、クイックスタートに従って Claude Agent SDK をインストールしてください。以下の例は、エージェントに Anthropic を調査し、会社名、設立年、本社を構造化された出力として返すよう求めています。

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

// 返してほしいデータの形状を定義
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
      }
    }
  })) {
    // 結果メッセージには検証済みデータを含む structured_output が含まれます
    if (message.type === "result" && message.subtype === "success" && message.structured_output) {
      console.log(message.structured_output);
      // { company_name: "Anthropic", founded_year: 2021, headquarters: "San Francisco, CA" }
    }
  }
} catch (error) {
  // 単一ショットの query() はエラー結果(error_max_structured_output_retries など)を生成した後にスローされます。エラーハンドリングセクションを参照してください。
  console.error(`Session ended with an error: ${error}`);
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage

# 返してほしいデータの形状を定義
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}
            ),
        ):
            # 結果メッセージには検証済みデータを含む structured_output が含まれます
            if isinstance(message, ResultMessage) and message.structured_output:
                print(message.structured_output)
                # {'company_name': 'Anthropic', 'founded_year': 2021, 'headquarters': 'San Francisco, CA'}
    except Exception as error:
        # 単一ショットの query() はエラー結果(error_max_structured_output_retries など)を生成した後にレイズされます。エラーハンドリングセクションを参照してください。
        print(f"Session ended with an error: {error}")


asyncio.run(main())

Zod と Pydantic を使用した型安全なスキーマ

JSON Schema を手書きする代わりに、Zod(TypeScript)または Pydantic(Python)を使用してスキーマを定義できます。これらのライブラリは JSON Schema を生成し、応答を完全に型付けされたオブジェクトに解析できるため、オートコンプリートと型チェックを使用してコードベース全体で使用できます。

以下の例は、概要、ステップのリスト(各ステップに複雑さレベルを含む)、および潜在的なリスクを含む機能実装計画のスキーマを定義しています。エージェントは機能を計画し、型付けされた FeaturePlan オブジェクトを返します。その後、plan.summary などのプロパティにアクセスし、完全な型安全性を備えて plan.steps を反復処理できます。

SDK は JSON Schema draft-07 でスキーマを検証するため、より新しいバージョンを宣言するスキーマは拒否されます。Zod はデフォルトで draft 2020-12 をターゲットとするため、スキーマを変換する際に target: "draft-7" を渡してください。

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

// Define schema with 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>;

// Convert to JSON Schema using the draft-07 target the SDK expects
const schema = z.toJSONSchema(FeaturePlan, { target: "draft-7" });

// Use in query
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.structured_output) {
      // Validate and get fully typed result
      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) {
  // 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 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 message.structured_output:
                # Validate and get fully typed result
                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:
        # 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())

出力形式の設定

outputFormat(TypeScript)または output_format(Python)オプションは、以下を含むオブジェクトを受け入れます:

  • type:構造化された出力の場合は "json_schema" に設定
  • schema:出力構造を定義する JSON Schema オブジェクト。Zod スキーマから z.toJSONSchema(schema, { target: "draft-7" }) で、または Pydantic モデルから .model_json_schema() で生成できます。

SDK は、すべての基本型(object、array、string、number、boolean、null)、enum、const、required、ネストされたオブジェクト、および $ref 定義を含む標準 JSON Schema 機能をサポートしています。サポートされている機能と制限の完全なリストについては、JSON Schema の制限 を参照してください。

有効な JSON Schema ではないスキーマは、問題を示すエラーで起動時に実行に失敗します。v2.1.205 より前は、無効なスキーマは暗黙的に無視され、エージェントは非構造化テキストを返していました。

"format": "email" などの format キーワードは、注釈として受け入れられ、SDK のバリデーターによって強制されません。v2.1.205 より前は、format を含むスキーマは無効として扱われていました。

例:TODO トラッキングエージェント

この例は、マルチステップツール使用で構造化された出力がどのように機能するかを示しています。エージェントはコードベース内の TODO コメントを見つけ、各コメントの git blame 情報を調べる必要があります。実行中に使用するツール(検索用の Grep、git コマンド実行用の Bash)を自律的に決定し、結果を単一の構造化応答に組み合わせます。

スキーマには、すべてのファイルで git blame 情報が利用できない可能性があるため、オプションフィールド(author と date)が含まれています。エージェントは見つけられるものを埋め、残りは省略します。

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

// TODO 抽出用の構造を定義
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"]
};

// エージェントは Grep を使用して TODO を見つけ、Bash を使用して git blame 情報を取得
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.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) {
  // 単一ショットの query() は、error_max_structured_output_retries などのエラー結果を生成した後にスロー
  // エラーハンドリングセクションを参照してください。
  console.error(`Session ended with an error: ${error}`);
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage

# TODO 抽出用の構造を定義
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():
    # エージェントは Grep を使用して TODO を見つけ、Bash を使用して git blame 情報を取得
    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 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:
        # 単一ショットの query() は、error_max_structured_output_retries などのエラー結果を生成した後にレイズ
        # エラーハンドリングセクションを参照してください。
        print(f"Session ended with an error: {error}")


asyncio.run(main())

StructuredOutput ツール呼び出しを認識する

TypeScript で outputFormat を、Python で output_format を設定すると、メッセージストリームには自分で定義していない StructuredOutput という名前のツール呼び出しが含まれます。Claude Code はこのツールをセッションに追加し、エージェントはこれを呼び出して回答を返します。システム init メッセージでは tools 配列にこのツールが含まれており、各呼び出しは次の 2 つのブロックとして届きます。

  • StructuredOutput という名前の tool_use ブロック。その入力は、エージェントがスキーマに沿って生成したオブジェクトです
  • Structured output provided successfully という内容の tool_result ブロック

そのオブジェクトがスキーマに一致しない場合、tool_result には代わりに is_error: true が含まれ、エージェントは StructuredOutput を再度呼び出します。そのため、1 つのクエリに対してストリームに複数の呼び出しが含まれることがあります。検証済みのデータは、tool_use ブロックからではなく、結果メッセージの structured_output から読み取ってください。どの試行も成功しなかった場合に返される結果については、エラー処理を参照してください。

アプリケーションでツール呼び出しを表示したりログに記録したりする場合は、この仕組みがエージェントの選択したステップとして表示されないように、StructuredOutput という名前の呼び出しをスキップしてください。tool_result ブロックにはツール名が含まれず、応答先の呼び出しの tool_use_id のみが含まれるため、これをスキップした各呼び出しの id と照合してください。

エラーハンドリング

構造化された出力の生成は、エージェントがスキーマに一致する有効な JSON を生成できない場合に失敗する可能性があります。これは通常、スキーマがタスクに対して複雑すぎる場合、タスク自体が曖昧な場合、またはエージェントが検証エラーを修正しようとして再試行制限に達した場合に発生します。また、検証の失敗がなくても発生する可能性があります。モデルフォールバックは既に完了した出力をストリーム中に取り消すことができ、再試行がそれを置き換えない場合、実行は同じエラーで終了します。スキーマをデバッグする前に、エラー結果メッセージの errors リストを確認して、2 つの原因を区別してください。

エラーが発生すると、結果メッセージには何が問題かを示す subtype があります:

Subtype 意味
success 出力が正常に生成および検証されました
error_max_structured_output_retries 複数の試行後に有効な出力が残りませんでした(検証の失敗、または成功した再試行のないモデルフォールバックによる取り消し)

結果は subtype が success でも structured_output 値がない場合に終了することもあります。例えば、実行がエージェントによる構造化出力の生成なしに完了した場合です。その場合も失敗として扱ってください。トラブルシューティングエントリ structured_output is None but the result says success がこのケースをカバーしています。以下の例は、subtype が success で structured_output が存在する場合にのみ結果を成功として扱い、他のすべての結果を失敗として処理します:

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.structured_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 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 message.structured_output:
                    # 検証済み出力を使用
                    print(message.structured_output)
                elif message.subtype == "error_max_structured_output_retries":
                    print("Could not produce valid output")
                else:
                    print("Run ended 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())

エラーを回避するためのヒント:

  • スキーマを焦点を絞ったものにしてください。 多くの必須フィールドを持つ深くネストされたスキーマは満たすのが難しいです。シンプルに始めて、必要に応じて複雑さを追加してください。
  • スキーマをタスクに合わせてください。 タスクがスキーマが必要とするすべての情報を持たない可能性がある場合、それらのフィールドをオプションにしてください。
  • 明確なプロンプトを使用してください。 曖昧なプロンプトは、エージェントが何を出力するかを知るのを難しくします。

関連リソース

  • JSON Schema ドキュメント:ネストされたオブジェクト、配列、列挙型、検証制約を含む複雑なスキーマを定義するための JSON Schema 構文を学習します
  • API 構造化出力:ツール使用なしの単一ターンリクエストの場合、Claude API で直接構造化された出力を使用します
  • カスタムツール:構造化された出力を返す前に実行中にエージェントが呼び出すカスタムツールを提供します