「Claude APIのレスポンスをそのまま使ったら、毎回パース処理が大変で…」そんな経験をしたことはありませんか?

AIが返す文章はとても柔軟ですが、それがアプリ開発では逆に困ることがあります。「ちゃんとJSONで返ってくると思ったら、説明文が混じってた」「キーの名前が微妙に違う」など、レスポンスのブレに悩まされるケースが多いんですよね。

そこで今回は、Claude APIの構造化出力(JSON mode)Pydanticを組み合わせて、型安全なAIレスポンスを取得する方法を解説します。

この記事を読めば、AIの出力を「確実に決まった形で受け取る」設計ができるようになります。アプリ開発の品質がぐっと上がりますよ 🎯

対象読者と前提知識

structured data Python
structured data Python / Photo by Seraphfim Gallery via Pexels
  • Claude APIをPythonで使ったことがある方
  • Pydanticをなんとなく知っているか、これから学びたい方
  • AIのレスポンスをアプリに組み込んで使いたい中級者

Claude APIの基本的な使い方については、このブログの入門記事を先にご覧いただくとよりスムーズです。

構造化出力(JSON mode)とは?

まず「構造化出力」という言葉を整理しておきましょう。

通常、Claude APIに質問すると、自然な文章(テキスト)で返ってきます。これはチャットには最適ですが、アプリに組み込む場合は困ります。なぜなら、プログラムは「どこに何が書いてあるか」を正確に知る必要があるからです。

たとえば「この商品レビューの感情分析をして」と頼んだとき、次のような返答では困りますよね。

このレビューはポジティブです。スコアは0.85くらいです。
キーワードとしては「品質」「コスパ」などが目立ちます。

アプリが欲しいのは、こっちです。

{
  "sentiment": "positive",
  "score": 0.85,
  "keywords": ["品質", "コスパ"]
}

これが構造化出力の考え方です。AIに「必ずこの形式で返して」と指定して、プログラムが扱いやすいデータ構造にするわけです 📦

Pydanticが活躍する理由

PydanticはPythonのデータバリデーションライブラリで、「このデータはこういう型・構造であるべき」を宣言的に定義できます。

Claude APIと組み合わせると、次のような流れになります。

  1. Pydanticでレスポンスの「型定義(スキーマ)」を書く
  2. そのスキーマをJSON Schema形式でClaudeに渡す
  3. ClaudeがそのスキーマにぴったりなJSONを返す
  4. PydanticでパースしてPythonオブジェクトとして使う

型の不一致があれば即エラーになるので、「なんか動いてるけど中身がおかしい」という沼にはまりにくくなります。これが型安全ということです。

実践!Pydantic × Claude APIで感情分析を型安全に実装する

では実際にコードを見ていきましょう。まずは必要なライブラリをインストールします。

pip install anthropic pydantic

STEP 1|Pydanticでレスポンス型を定義する

from pydantic import BaseModel, Field
from typing import Literal

# AIに返してほしいデータの「型」を定義
class SentimentAnalysis(BaseModel):
    sentiment: Literal["positive", "negative", "neutral"] = Field(
        description="テキストの感情(positive / negative / neutral)"
    )
    score: float = Field(
        ge=0.0, le=1.0,
        description="感情スコア(0.0〜1.0)"
    )
    keywords: list[str] = Field(
        description="感情に関連するキーワードのリスト"
    )
    summary: str = Field(
        description="一言での感情サマリー"
    )

ポイントをまとめるとこんな感じです。

  • Literal["positive", "negative", "neutral"]で選択肢を限定できる
  • Field(ge=0.0, le=1.0)で数値の範囲を制限できる
  • descriptionがそのままClaudeへの指示になる

STEP 2|スキーマをClaudeに渡してJSONを取得する

import anthropic
import json

client = anthropic.Anthropic()

def analyze_sentiment(text: str) -> SentimentAnalysis:
    # PydanticのスキーマをJSON Schema形式に変換
    schema = SentimentAnalysis.model_json_schema()

    message = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=1024,
        system="""あなたはテキスト感情分析の専門家です。
必ず指定されたJSONスキーマに従って、JSONのみを返してください。
説明文や前置きは不要です。""",
        messages=[
            {
                "role": "user",
                "content": f"""以下のテキストを感情分析してください。

## テキスト
{text}

## 出力スキーマ(このJSONの形式で返してください)
{json.dumps(schema, ensure_ascii=False, indent=2)}"""
            }
        ]
    )

    # レスポンスをPydanticでパース(型チェック込み)
    response_text = message.content[0].text
    result = SentimentAnalysis.model_validate_json(response_text)
    return result


# 実行してみよう
review = "このイヤホンは音質が最高で、コスパも抜群です!デザインもシンプルで気に入っています。"
result = analyze_sentiment(review)

print(f"感情: {result.sentiment}")
print(f"スコア: {result.score}")
print(f"キーワード: {result.keywords}")
print(f"サマリー: {result.summary}")

実行するとこんな感じの出力が得られます 🎉

STEP 3|複数アイテムを一括分析する応用例

次は、複数のレビューをまとめて分析するケースを見てみましょう。ネストした構造にも対応できます。

from pydantic import BaseModel, Field
from typing import Literal
import anthropic
import json

client = anthropic.Anthropic()

class SingleReview(BaseModel):
    id: int = Field(description="レビューのID")
    sentiment: Literal["positive", "negative", "neutral"]
    score: float = Field(ge=0.0, le=1.0)
    top_keyword: str = Field(description="最も重要なキーワード1つ")

class BatchAnalysis(BaseModel):
    reviews: list[SingleReview] = Field(description="全レビューの分析結果リスト")
    overall_sentiment: Literal["positive", "negative", "neutral"] = Field(
        description="全体的な感情傾向"
    )
    average_score: float = Field(ge=0.0, le=1.0, description="平均スコア")


def batch_analyze(reviews: list[dict]) -> BatchAnalysis:
    schema = BatchAnalysis.model_json_schema()

    reviews_text = "\n".join(
        [f"ID {r['id']}: {r['text']}" for r in reviews]
    )

    message = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=2048,
        system="JSONスキーマに従い、JSONのみ返してください。説明文は不要です。",
        messages=[
            {
                "role": "user",
                "content": f"""以下の複数レビューを一括分析してください。

## レビュー一覧
{reviews_text}

## 出力スキーマ
{json.dumps(schema, ensure_ascii=False, indent=2)}"""
            }
        ]
    )

    return BatchAnalysis.model_validate_json(message.content[0].text)


# テスト実行
sample_reviews = [
    {"id": 1, "text": "とても使いやすくて満足しています!"},
    {"id": 2, "text": "梱包が雑でがっかりしました。"},
    {"id": 3, "text": "普通の商品です。可もなく不可もなく。"},
]

result = batch_analyze(sample_reviews)
print(f"全体感情: {result.overall_sentiment}")
print(f"平均スコア: {result.average_score:.2f}")
for r in result.reviews:
    print(f"  [ID:{r.id}] {r.sentiment} ({r.score:.2f}) キーワード: {r.top_keyword}")

ここが重要です。

  • ネストしたBaseModelもそのままスキーマに変換できる
  • list[SingleReview]のような複雑な型定義も問題なし
  • model_validate_json()が型チェックしながらパースしてくれる

よくあるハマりポイントと対処法


❌ Claudeが余計な説明文を返してくる

システムプロンプトに「JSONのみ返してください。説明文は不要です。」と明示するのが効果的です。それでもブレる場合は、レスポンステキストから{}部分だけを正規表現で抽出する前処理を挟む方法もあります。

import re

def extract_json(text: str) -> str:
    # ```json ... ``` や { ... } を抽出
    match = re.search(r'\{.*\}', text, re.DOTALL)
    if match:
        return match.group()
    raise ValueError("JSONが見つかりませんでした")

❌ Pydanticのバリデーションエラーが出る

model_validate_json()が失敗する場合は、スキーマのdescriptionをより具体的に書くと改善されることが多いです。「0.0から1.0の浮動小数点」のように、AIが迷わない表現を心がけましょう。

まとめ


今回はClaude APIの構造化出力(JSON mode)Pydanticを組み合わせた、型安全なレスポンス取得の方法を解説しました。

  • ✅ Pydanticで型定義 → model_json_schema()でスキーマ生成
  • ✅ スキーマをプロンプトに埋め込んでClaudeに指示
  • model_validate_json()でパースして型安全なオブジェクトに

この設計パターンを使うと、AIのレスポンスが「プログラムが確実に扱える形」で届くようになります。本番アプリへの組み込みも、ぐっとやりやすくなりますよ 🚀

ぜひ自分のプロジェクトでも試してみてください。型定義を工夫するだけで、AIがどんどん「使いやすい部品」になっていくのを実感できるはずです!

📚 関連商品・おすすめ書籍

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

もしも

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

初心者に定番のPython入門書

Amazonで見る

実践Claude Code入門―現場で活用するためのAIコーディングの思考法

もしも

実践Claude Code入門―現場で活用するためのAIコーディングの思考法

AIコーディングの現場活用法を学ぶ一冊

Amazonで見る

Python Web開発実践入門 ―― FastAPIによるWebAPI開発と非同期処理

もしも

Python Web開発実践入門 ―― FastAPIによるWebAPI開発と非同期処理

FastAPIでWebAPI開発を実践的に学ぶ

Amazonで見る

※本記事にはアフィリエイトリンクが含まれます。

ABOUT ME
やまちゃん
これまで学生と社会人を合わせて5000人以上にプログラミング学習を指導。 ゼロからイチをわかりやすく解説する専門家として活動しており、本業ではArduinoを用いたIoT開発とロボットプログラミングが専門。 Pythonを用いたアプリ開発、ウェブアプリケーションの開発で業務の効率化をサポートしています。