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-16中級

Claude API の Tool Use でスキーマ定義ミスが出たとき:実際に遭遇した3つのパターンと診断手順

Claude API の Tool Use でよく起きるスキーマ定義ミス・invalid_tool_use・Claude がツールを呼ばない問題を、実際のアプリ開発で遭遇したケースをもとに診断手順と修正パターンで解説します。

tool-use21api38troubleshooting61python22error-handling10

Tool Use(Function Calling)を実装し始めた当初、私はスキーマ定義を誤ってしまうことが多くありました。2014年からアプリ開発を続けてきた中で、Beautiful HD Wallpapers に Claude API の画像分類機能を組み込もうとしたとき、最初に詰まったのは「スキーマが通らない」でも「Claude がツールを呼んでくれない」でもなく、メッセージスレッドへの tool_result の返し方が微妙にずれていたことでした。

エラーメッセージが invalid_request_error の一種として返ってくるため、一見すると「リクエストの構造が壊れている」としか分かりません。原因の切り分けに時間がかかったので、同じところで詰まる方のために診断フローをまとめます。

なお、Tool Use は Python SDK と TypeScript SDK のいずれも公式サポートしており、コードの構造はほぼ同じです。本記事の例は Python を使用していますが、TypeScript でも tools 配列の構造と tool_result の返し方は同一です。SDK を使う場合は tool_usetool_result がオブジェクトとして型付けされているので、辞書の組み立てミスを減らせます。

Tool Use の3層構造を理解すると診断が速くなる

Tool Use のやりとりは3段階に分かれています。第1段階は「ツール定義を渡す」で、tools パラメータに JSON Schema 形式のスキーマを含めます。第2段階は「Claude がツールを呼ぶ」で、応答のコンテンツブロックに tool_use が含まれます。第3段階は「結果を返す」で、tool_result を含む user ターンを追加して次の応答を受け取ります。

この3段階のどこでエラーが起きているかを特定することが、診断の出発点です。エラーが返ってくる段階によって、原因はほぼ絞り込めます。第1段階のリクエスト送信直後にエラーが返るなら、スキーマの構造問題です。第3段階で返るなら、tool_result の形式や tool_use_id の不一致が疑われます。エラーが出ないのに Claude がツールを呼ばない場合は、description の曖昧さかプロンプト設計の問題です。

import anthropic
 
client = anthropic.Anthropic()
 
# 第1段階: ツール定義(ここのスキーマ構造が重要)
tools = [
    {
        "name": "get_image_category",
        "description": "画像のカテゴリを分類して返します。ユーザーが画像の分類・カテゴリ特定を求めたときに呼び出してください",
        "input_schema": {
            "type": "object",
            "properties": {
                "image_url": {
                    "type": "string",
                    "description": "分類する画像のURL"
                },
                "categories": {
                    "type": "array",
                    "items": {"type": "string"},
                    "description": "候補カテゴリのリスト"
                }
            },
            "required": ["image_url", "categories"]
        }
    }
]
 
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    tools=tools,
    messages=[{"role": "user", "content": "この画像を分類してください: https://example.com/photo.jpg"}]
)

パターン1: required の位置と type の省略が原因の場合

最もよくある原因は、input_schema の構造が JSON Schema の仕様から外れていることです。Claude API の Tool Use は JSON Schema Draft 7 をベースにしており、細かい制約があります。

required フィールドの位置は、スキーマのトップレベル(properties と同じ階層)に配列として書く必要があります。プロパティ定義の中に required: true のように書いても、無視されるかエラーになります。もう一つよくあるのが、プロパティの type フィールドの省略です。properties の各項目には必ず type を指定する必要があり、description だけ書いても invalid_request_error になります。

# ❌ よくある誤り: required が properties の中にある
"input_schema": {
    "type": "object",
    "properties": {
        "query": {
            "type": "string",
            "required": True  # ← ここには書けない
        }
    }
}
 
# ✅ 正しい書き方: required はトップレベルの配列
"input_schema": {
    "type": "object",
    "properties": {
        "query": {
            "type": "string",
            "description": "検索クエリ文字列"
        }
    },
    "required": ["query"]  # ← トップレベルに文字列の配列として書く
}

スキーマを事前に検証したい場合は、jsonschema パッケージの Draft7Validator.check_schema() が使えます。API に投げる前にローカルで構造チェックをするだけで、原因不明の invalid_request_error に悩む時間が大幅に減ります。

パターン2: tool_result の返し方がずれている場合

Claude が tool_use ブロックを返した後、結果を返すメッセージの構造には決まったフォーマットがあります。私が最初に詰まったのもここでした。よくある間違いは、ツール実行結果をプレーンな文字列メッセージとして返してしまうことです。tool_result ブロックを content 配列に含める形にする必要があります。

tool_use_id は Claude が返したブロックの ID と完全に一致させる必要があります。同じセッション内で複数のツールを並列で呼んだ場合、それぞれの ID を正確に対応させなければいけません。ID を tool_use_block.id でコピーするのが最も確実です。

# ❌ 誤り: tool_result を使わずに文字列メッセージとして返す
messages.append({
    "role": "user",
    "content": "分類結果はlandscapeです"  # ← これは tool_result にならない
})
 
# ✅ 正しい: tool_result ブロックを content 配列に含める
if response.stop_reason == "tool_use":
    tool_use_block = next(b for b in response.content if b.type == "tool_use")
    tool_result = execute_my_tool(tool_use_block.input)  # 実際のツール実行
 
    messages.append({
        "role": "user",
        "content": [
            {
                "type": "tool_result",
                "tool_use_id": tool_use_block.id,  # Claude が返した ID をそのままコピー
                "content": str(tool_result)
            }
        ]
    })

パターン3: Claude がツールを呼ばない場合

スキーマが正しくても、Claude がツールを呼ばずに直接テキストで回答してしまうことがあります。これは技術的なエラーではなく、プロンプトと description の設計問題です。

description は Claude がツールを「いつ使うべきか」を判断するほぼ唯一の手がかりです。「データを処理します」のような抽象的な説明では、Claude はテキスト回答を選びがちになります。「ユーザーが〇〇を求めたときに呼び出す」のように、使いどころを具体的に書くことで呼び出し率が上がります。

また、Claude が内部的に「ツールを使わなくてもテキストで答えられる」と判断してしまう場合があります。そのような場合は tool_choice パラメータで呼び出しを強制できます。type: "any" を使うと、Claude はいずれかのツールを必ず呼ぶ応答を返します。type: "tool"name を指定すると、特定のツールを強制的に呼ばせられます。

# ツール呼び出しを強制する(どれかのツールを必ず呼ぶ)
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    tools=tools,
    tool_choice={"type": "any"},
    messages=[{"role": "user", "content": "画像を分類してください"}]
)
 
# 特定のツールを指定して強制
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    tools=tools,
    tool_choice={"type": "tool", "name": "get_image_category"},
    messages=[{"role": "user", "content": "この画像を分析して"}]
)

スキーマ設計で押さえておきたい細かい注意点

Tool Use を本番環境で使い続けると、初期実装ではすり抜けた細かい問題が出てくることがあります。実際の運用で気づいたいくつかの点を補足します。

enum で候補を絞る場合の型"type": "string""enum": ["a", "b", "c"] を組み合わせると、Claude は必ずその候補の中から値を選びます。ただし、Claude が出力する文字列の大文字・小文字が enum の定義と一致しないケースがあります。API 側での大文字小文字の正規化を忘れないでください。

ネストしたオブジェクトproperties の中にさらにオブジェクトを含める場合も、すべての階層で "type": "object" を明示する必要があります。ネストしたオブジェクトの properties は親と同じ構造を繰り返します。ネストが深くなると定義が冗長になりがちですが、スキーマを省略すると Claude が構造を誤解することがあります。

additionalProperties: false — スキーマに含まれていないフィールドを Claude が返してきた場合に、アプリ側でエラーにならないよう防御したいときは "additionalProperties": false を追加できます。ただし、これを指定すると Claude が余分なフィールドを追加しようとした際に tool_use 自体が失敗することがあるため、まず動かしてから必要に応じて追加するのが安全です。

description の長さdescription が長すぎると、コンテキストの使用量が増えます。「いつ呼ぶか」の条件と「何をするか」の説明を2〜3文にまとめるのが実用的なバランスです。特に複数ツールを同時に定義する場合は、各ツールの description が長くなりすぎないよう意識することが大切です。累計5,000万DLを超えるアプリ群に AI 機能を追加してきた経験から言うと、description の整理はコスト最適化にも直結します。

これらは小さな注意点ですが、本番でのエラー率に影響します。スキーマ設計の段階で一度見直しておく価値があります。

診断フローの実践

エラーが出たときの確認順序をまとめます。invalid_request_error がリクエスト送信直後に返る場合は、input_schema の構造を疑います。required の位置、各プロパティの type の有無、スキーマルートの "type": "object" の存在を順番に確認します。

tool_result を返したあとにエラーが出る場合は、tool_use_id の一致と tool_result ブロックの構造を確認します。content が配列になっているか、type フィールドが "tool_result" になっているかをチェックします。

エラーが出ないのに Claude がツールを呼ばない場合は、description の具体性を上げるか、まず tool_choice: {"type": "any"} で強制して動作を確認します。それでもツールが呼ばれるなら、プロンプト側の問題です。

Tool Use のデバッグは「3段階のどこで詰まっているか」を特定することがほぼすべてです。エラーメッセージだけ読んでいると迷子になりやすいですが、段階を意識すると原因が見えてきます。私自身、cumulative 5,000万DL超のアプリ群に AI 機能を組み込んできた経験から言うと、Tool Use のエラーの9割はスキーマの required 位置と tool_result の返し方で説明がつきます。

まず上記のチェックリストを上から確認してみてください。それだけで多くの場合は解決します。

シェア

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

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

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

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

API & SDK2026-05-06
Claude API × Python 実践:ツール呼び出しとストリーミングを組み合わせてAIアシスタントを作る
Claude API の Tool Use とStreamingを同時に使うPython実装を解説。ツールを定義してリアルタイム応答するAIアシスタントの完成コードと、組み合わせ時に詰まりやすいポイントを丁寧に解説します。
API & SDK2026-05-05
Claude API のツール実行エラーを Claude 自身に診断させる — 自己修正ループの設計と本番実装
Tool Use実装で避けられないツール実行エラーの対処法を解説。is_errorフラグを活用してエラー情報をClaudeに返し、自己診断・修正ループを実装する実践的なPythonコードと本番でのアンチパターンも紹介します。
API & SDK2026-04-30
Claude API の『messages.X.role must alternate』を1分で直す — 400 invalid_request_error の典型パターン
Claude API で頻発する『messages.X.role must alternate』エラーの原因と直し方を、user/assistant の交互ルール・tool_use と tool_result の対応関係・履歴管理の落とし穴に分けて、実例コード付きで整理します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →