CLAUDE LABEN
FORK — Claude Code 2.1.212で/forkの挙動が変わりました。会話を新しいバックグラウンドセッションへ複製し、作業を続けたまま並走できます。従来のセッション内サブエージェントは/subtaskに移りましたLIMITS — WebSearchの呼び出しがセッション単位で既定200回に制限されました。サブエージェントの起動も既定200回が上限で、暴走した検索・委譲のループを止められますMCPBG — 2分を超えるMCPツール呼び出しは自動的にバックグラウンドへ移り、セッションが固まらなくなりました。しきい値はCLAUDE_CODE_MCP_AUTO_BACKGROUND_MSで調整できますPLANFIX — プランモードがtouchやrmといったファイルを変更するBashコマンドを、許可プロンプトもcanUseToolコールバックも通さずに実行してしまう不具合が修正されましたSONNET5 — Claude Sonnet 5は導入価格として入力100万トークンあたり2ドル、出力10ドルで提供中です。8月31日を過ぎると3ドルと15ドルに戻りますIPO — Anthropicが早ければ10月の株式公開を視野に、引受銀行が投資家との面談を組み始めたと報じられていますFORK — Claude Code 2.1.212で/forkの挙動が変わりました。会話を新しいバックグラウンドセッションへ複製し、作業を続けたまま並走できます。従来のセッション内サブエージェントは/subtaskに移りましたLIMITS — WebSearchの呼び出しがセッション単位で既定200回に制限されました。サブエージェントの起動も既定200回が上限で、暴走した検索・委譲のループを止められますMCPBG — 2分を超えるMCPツール呼び出しは自動的にバックグラウンドへ移り、セッションが固まらなくなりました。しきい値はCLAUDE_CODE_MCP_AUTO_BACKGROUND_MSで調整できますPLANFIX — プランモードがtouchやrmといったファイルを変更するBashコマンドを、許可プロンプトもcanUseToolコールバックも通さずに実行してしまう不具合が修正されましたSONNET5 — Claude Sonnet 5は導入価格として入力100万トークンあたり2ドル、出力10ドルで提供中です。8月31日を過ぎると3ドルと15ドルに戻りますIPO — Anthropicが早ければ10月の株式公開を視野に、引受銀行が投資家との面談を組み始めたと報じられています
記事一覧/API & SDK
API & SDK/2026-05-26上級

Claude API の構造化レスポンスを本番で安定させる — tool_use と JSON Schema、多層検証の実装メモ

Claude API の応答を JSON で受け取る実装は数行で書けますが、本番運用では「形は正しいが意味が壊れている」レスポンスにどう備えるかが分かれ目になります。tool_use・JSON Schema・ドメイン検証を組み合わせた多層パイプラインを、壁紙アプリの分類処理での実体験を交えて整理しました。

claude-api81tool-use21json-schema2validation2production87anthropic-sdk3

プレミアム記事

壁紙アプリで Claude API を使ってカテゴリ分類を始めた頃、最初に困ったのは「JSON は返ってくるのに、たまに気持ち悪い壊れ方をする」現象でした。"categories": ["自然", "風景"] と返してほしい場面で、"categories": "自然, 風景" という文字列が混ざる。スキーマには合っていないのに 200 OK で返ってくる。LLM の癖を知らないまま実装すると、こうした「形だけ正しくない」入力に毎日少しずつ削られて、運用1ヶ月後には監視ダッシュボードが警告だらけになります。

アーティスト・クリエイターの廣川政樹です。個人で12年ほどアプリ開発を続けてきて、累計5,000万ダウンロードを超えるアプリ群を1人で運用しています。日々の運用で Claude API を呼び出す処理は、テキスト生成だけでなく、機械処理に渡すための「構造化された値」を取り出す用途が圧倒的に多くなりました。その積み重ねの中で固まった「壊れにくい構造化レスポンス設計」を、tool_use・JSON Schema・多層検証の3つの軸で書き出します。

構造化レスポンスが「形だけ」では足りない理由

構造化レスポンスを本番に載せると、最初に直面するのは「形は合っているが、意味が壊れている」レスポンスです。たとえば次のような失敗パターンが、運用しているとどんどん見つかります。

  • スキーマには合っているが、enum 外の値が入っている("category": "その他" のような未定義値)
  • 配列の中に空文字列が混じる(["風景", "", "自然"]
  • 数値フィールドに "5""unknown" などの文字列が紛れる
  • 必須フィールドが欠落していて、SDK 側のパースは通るがアプリ側で undefined になる
  • 同じプロンプトでも、ストリーミングで途中切断されると JSON 末尾が壊れたまま完了扱いになる

形式だけを検証する単純な実装は、これらを「成功」として通過させてしまいます。SDK 側の型は静的型でしかなく、ランタイムでフィールドが揃っている保証は別の話です。tool_use を使うと Anthropic 側で JSON 検証が行われるため一段安全になりますが、それでも「意味の正しさ」までは保証してくれません。

私が壁紙アプリの分類処理で導入した方針は単純です。検証を3層に分け、層ごとに失敗時の戦略を変えることでした。後述しますが、これだけで分類処理の手動修正率が月平均で約 4.2% から 0.7% まで下がりました。1日約 1,200 枚を捌くパイプラインで、月に何百件かの手作業が消えるとそれなりにきく数字です。

tool_use・response_format・prompt-only の比較と使い分け

Claude API で構造化レスポンスを得る方法は、大まかに次の3通りに整理できます。それぞれ得意な領域が違います。

方式厳密さ実装コスト失敗時の挙動得意な場面
prompt-only(プロンプトで JSON を要求)弱い最小壊れた JSON が混じる単発の小タスク・PoC
tool_use(input_schema で構造を強制)強いスキーマ違反は API 側でリジェクトされる本番の構造化抽出全般
extended thinking + tool_use最強中〜高推論経路を踏まえてスキーマ通り返す複雑な分岐・合成タスク

response_format 相当の指定は API リファレンス上は提供されていないため、Anthropic 側で構造を強制したい場合は実質 tool_use を使うことになります。私の運用では tool_use を本番の標準にしていて、prompt-only は使い捨ての検証スクリプトに限定しています。

判断軸は2つだけ意識しています。第一に「失敗をどう受け取りたいか」。tool_use なら API レスポンスが構造として返ってこない場合の処理を一本化できます。第二に「コストとレイテンシの差」。tool_use 自体のオーバーヘッドはほぼ誤差ですが、複雑な extended thinking を併用すると入力トークンが膨らむため、扱うタスクの単価と相談して決めます。壁紙の単純分類なら extended thinking なし、契約書から条項を抽出するなら extended thinking ありで設計しています。

# Before — prompt-only に依存していた頃の素朴な実装
from anthropic import Anthropic
import json
 
client = Anthropic()
 
def classify_wallpaper_naive(prompt: str) -> dict:
    resp = client.messages.create(
        model="claude-haiku-4-5",
        max_tokens=512,
        messages=[{"role": "user", "content": f"次の画像を分類してJSONで返してください。\n{prompt}"}],
    )
    text = resp.content[0].text
    return json.loads(text)  # ← ここで時々壊れる
# After — tool_use で「構造を返すしかない」状態に追い込む
TOOL_SCHEMA = {
    "name": "classify_wallpaper",
    "description": "壁紙画像のカテゴリ分類を返す",
    "input_schema": {
        "type": "object",
        "properties": {
            "primary_category": {
                "type": "string",
                "enum": ["nature", "abstract", "city", "minimal", "people", "other"],
            },
            "tags": {
                "type": "array",
                "items": {"type": "string", "minLength": 1, "maxLength": 16},
                "minItems": 1,
                "maxItems": 6,
            },
            "confidence": {
                "type": "number",
                "minimum": 0.0,
                "maximum": 1.0,
            },
            "needs_human_review": {"type": "boolean"},
        },
        "required": ["primary_category", "tags", "confidence", "needs_human_review"],
        "additionalProperties": False,
    },
}
 
def classify_wallpaper_tool(image_block: dict) -> dict:
    resp = client.messages.create(
        model="claude-haiku-4-5",
        max_tokens=512,
        tools=[TOOL_SCHEMA],
        tool_choice={"type": "tool", "name": "classify_wallpaper"},
        messages=[{
            "role": "user",
            "content": [image_block, {"type": "text", "text": "上の壁紙を分類してください"}],
        }],
    )
    for block in resp.content:
        if block.type == "tool_use" and block.name == "classify_wallpaper":
            return block.input  # ← 構造化済みの dict
    raise RuntimeError("tool_use block not found")

注目したいのは tool_choice={"type": "tool", "name": "..."} で強制している点です。これがないと「テキストで答えようとして tool_use を呼ばない」ケースが時々発生します。本番では強制が原則だと考えています。

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
tool_use と response_format と prompt-only の3方式を、実コストと壊れにくさで比較する判断基準
JSON Schema を「最大限厳密」ではなく「壊れにくいギリギリの粒度」で書くための具体パターン
ストリーミング中に partial JSON を扱うときの parse 戦略と、失敗時の fallback 設計
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

API & SDK2026-05-22
Claude API の tool_result could not be submitted が再発しないための回復ハンドラ設計
Claude API でエージェントを長時間動かしていると、ある日突然 'tool_result could not be submitted' が連発し始めることがあります。再試行しても直らない、ストリーミング途中で死ぬ、そして次のセッションでもまた出る — 個人開発で運営している6サイトの自動投稿パイプラインで実際に踏み抜いた4種類の原因と、TypeScript で書いた回復ハンドラの実装を整理しました。
API & SDK2026-05-09
Claude API の 400/422/529 を“呼ぶ前”に消す5層プリフライト設計 — 月数百件の失敗呼び出しをゼロにした実装
Claude API の 400/422/529 エラーを“呼ぶ前”に止める5層プリフライト設計を、TypeScript の完全実装と運用1ヶ月分の数値でまとめました。失敗呼び出しのコスト・リトライ・通知ノイズを同時に削減できます。
API & SDK2026-04-26
Claude API でジェネレーティブ UI を本番投入する — JSON Schema と Tool Use で動的コンポーネントをストリーミング描画する実装パターン
Claude API のツール呼び出しと部分 JSON ストリーミングを組み合わせ、AI が動的に組み立てた UI コンポーネントを安全に描画する本番設計を、コンポーネントレジストリ・型安全性・フォールバック含めて解説します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →