ankuro.dev
← ブログ一覧に戻る
【CCA Foundations対策 / Claude API編 #8】Tool Useの基礎①——ツール定義とスキーマ設計
2026-04-02#Claude#API#Python#生成AI#入門#Claude Certified Architect

【CCA Foundations対策 / Claude API編 #8】Tool Useの基礎①——ツール定義とスキーマ設計

Anthropic Academyの「Claude APIを使用した構築」コースをもとに解説しています。

Claude APIはデフォルトでは訓練データの範囲内の知識しか持たない。「今日の株価は?」「最新の在庫数は?」のような質問に対して、正直に「リアルタイムの情報は持っていない」と返すしかない。Tool Useはこの限界を突破する仕組みで、Claudeが外部APIやデータベースに問い合わせを要求し、その結果を使って回答できるようになる。

この記事(#8)では「ツールをどう定義するか」に絞って解説する。Claudeにツールを渡してレスポンスを読む実装は次回(#9)で扱う。

この記事でわかること:

  • Tool Useの全体フローと「なぜClaudeはリアルタイム情報を取得できないのか」
  • ツール関数の書き方——命名・バリデーション・エラーメッセージの3原則
  • JSON schemaの構造と、descriptionが選択信頼性を左右する理由
  • ToolParam 型を使った型安全な実装

Tool Useの全体像

Tool Useのフローは「Claude ↔ アプリ」の往復で構成される:

① ユーザーの質問 + ツール定義 → Claudeに送信
② Claude が「このツールを実行してほしい」とリクエストを返す
③ アプリがツール(Python関数)を実行して結果を取得
④ 結果を Claudeに返す
⑤ Claude が結果を使って最終回答を生成

ポイントは、Claudeは直接外部APIを呼べないことにある。Claudeができるのは「どのツールを・どんな引数で呼び出してほしいか」を伝えることだけで、実際にAPIを叩くのはアプリ側のコードになる。

この往復の制御は stop_reason というフィールドで判断する(詳細は #9 で解説する)。


ツール関数を定義する

Tool Useに必要な準備の第一歩は、Python関数としてツールを実装すること。Claudeが「この情報が必要だ」と判断したとき、アプリ側でこの関数を呼び出し、結果をClaudeに返す。

ここでは「株価取得ツール」を例に使う。

3つの設計原則

① 関数名と引数名は説明的に

関数名と引数名はClaudeが読む情報でもある。f(x) より get_stock_price(ticker_symbol) の方が、Claudeが「何を渡せばいいか」を理解しやすい。

② 入力を必ずバリデーションする

不正な入力に対してはすぐにエラーを発生させる。Claude側でエラーメッセージが確認でき、引数を修正して再試行できる。

③ エラーメッセージは具体的に

「エラーが発生しました」ではなく「ticker_symbol には英字のみ使用できます(例: AAPL, GOOG)」のように書く。Claudeがエラーの内容を読んで次のアクションを判断するため、具体的なメッセージが修正を早める。

実装例

import re

def get_stock_price(ticker_symbol: str, currency: str = "USD") -> dict:
    """指定した銘柄の株価を取得する"""
    if not ticker_symbol:
        raise ValueError("ticker_symbol は必須です(例: AAPL)")
    if not re.match(r'^[A-Z]{1,5}$', ticker_symbol.upper()):
        raise ValueError(
            f"ticker_symbol には大文字英字のみ使用できます(例: AAPL, GOOG)。"
            f"受け取った値: {ticker_symbol!r}"
        )
    if currency not in ("USD", "JPY", "EUR"):
        raise ValueError(
            f"currency は USD / JPY / EUR のいずれかを指定してください。"
            f"受け取った値: {currency!r}"
        )

    # 実際の実装では外部APIを呼び出す
    # ここではデモ用にモックデータを返す
    mock_prices = {
        "AAPL": 189.50,
        "GOOG": 175.30,
        "MSFT": 420.10,
    }
    price = mock_prices.get(ticker_symbol.upper(), 100.00)
    return {
        "ticker": ticker_symbol.upper(),
        "price": price,
        "currency": currency,
    }
# 正常系
get_stock_price("AAPL")
# → {"ticker": "AAPL", "price": 189.5, "currency": "USD"}

# バリデーションエラー
get_stock_price("aapl123")
# → ValueError: ticker_symbol には大文字英字のみ使用できます(例: AAPL, GOOG)。受け取った値: 'aapl123'

エラーメッセージをClaudeが読む、という前提で書くのがポイント。「受け取った値」を含めることで、Claudeが何を誤ったのかを認識して正しい引数で再試行しやすくなる。


ツールスキーマを書く

ツール関数を定義したら、次はClaudeに「このツールの使い方」を伝えるためのJSON schemaを書く。これがClaudeとアプリの「契約書」に相当する。

スキーマの構造

from anthropic.types import ToolParam

get_stock_price_schema = ToolParam({
    "name": "get_stock_price",
    "description": (
        "指定した株式銘柄(ティッカーシンボル)の現在の株価を取得する。"
        "リアルタイムの株価情報が必要なときに使用する。"
        "ticker_symbol には AAPL(Apple)や GOOG(Google)のような英字のティッカーシンボルを渡す。"
        "戻り値は ticker(銘柄)・price(株価)・currency(通貨)を含む辞書。"
    ),
    "input_schema": {
        "type": "object",
        "properties": {
            "ticker_symbol": {
                "type": "string",
                "description": (
                    "株式銘柄のティッカーシンボル(大文字英字、1〜5文字)。"
                    "例: AAPL(Apple)、GOOG(Google)、MSFT(Microsoft)"
                ),
            },
            "currency": {
                "type": "string",
                "description": "株価を表示する通貨。USD(米ドル)/ JPY(日本円)/ EUR(ユーロ)のいずれか。省略時はUSD。",
                "enum": ["USD", "JPY", "EUR"],
                "default": "USD",
            },
        },
        "required": ["ticker_symbol"],
    },
})

3つのフィールドの役割

フィールド 役割
name Claude がツールを参照するときの識別子。関数名と合わせる
description Claudeがツールを選択する際の主要判断材料。詳しくは後述
input_schema 引数の型・必須かどうか・説明を定義する JSON schema

descriptionの重要性

description はClaudeがツールを選ぶときに読む説明文で、選択信頼性を最も左右するフィールド

たとえば似た名前のツールが2つある場合を考える:

# ❌ 説明が曖昧なスキーマ
{
    "name": "get_stock_price",
    "description": "株式情報を取得する",
    ...
}
{
    "name": "get_company_info",
    "description": "企業情報を取得する",
    ...
}

この2つは説明が短すぎて、Claudeが「ユーザーが株価を知りたいとき」にどちらを呼ぶべきか判断しにくい。「株式情報」と「企業情報」の境界が曖昧で、誤選択が起きやすい。

# ✅ 境界を明確にした説明
{
    "name": "get_stock_price",
    "description": (
        "指定した銘柄の現在の株価(数値)を取得する。"
        "ユーザーが「〇〇の株価は?」「今の値段は?」と聞いたときに使用。"
        "会社概要・事業内容・財務情報は返さない。価格のみ。"
    ),
    ...
}
{
    "name": "get_company_info",
    "description": (
        "指定した銘柄の企業概要を取得する。"
        "事業内容・設立年・従業員数・CEOなどのプロフィール情報を返す。"
        "株価・時価総額などの市場データは含まない。"
    ),
    ...
}

改善のポイントは2つ:

  • いつ使うか(「〜と聞かれたとき」)を書く
  • 何を返さないか(境界条件)を書く

「何を返さないか」を書くことで、Claudeが誤って別のツールを選ぶリスクを減らせる。

📋 試験ガイドより
公式試験ガイドのDomain 2(Tool Design & MCP Integration)Task 2.1では、ツール記述(description)がLLMのツール選択における主要な判断材料であり、説明が短いと類似ツール間で誤選択が起きると明記されている。「いつ使うか・何を返さないか」を含む3〜4文の説明が、選択信頼性を高める設計として取り上げられている。

ToolParam 型を使う理由

スキーマを素の辞書として定義してもAPIは動作するが、ToolParam 型でラップしておくと型チェックが効いてIDEで補完が使えるようになる。実装上のメリットが大きいため、プロダクションコードでは積極的に使う。

from anthropic.types import ToolParam

# ToolParam でラップする(スキーマの内容は同じ)
schema = ToolParam({
    "name": "...",
    "description": "...",
    "input_schema": { ... },
})

よくある誤解まとめ

誤解 実際
Claude が直接外部APIを呼び出している Claudeは「どのツールを呼んでほしいか」を伝えるだけ。実際にAPIを呼ぶのはアプリ側のコード
ツール関数のエラーメッセージは開発者だけが読む Claudeがエラーメッセージを読んで引数を修正して再試行する。具体的なメッセージが重要
description は短くてよい descriptionはClaudeがツールを選択する主要判断材料。短すぎると類似ツールとの誤選択が起きる
required に含めれば引数は必ず渡される required はClaudeへの指示だが、バリデーションはコード側でも行う必要がある
input_schematype だけ書けば十分 description フィールドを各引数に書くと、Claudeが何を渡すべきかをより正確に理解できる

設計の判断基準

場面 やりがちな選択 正しい選択 判断の根拠
Claudeが正しいツールを選ばない プロンプトに「〇〇ツールを使え」と追記する descriptionを「いつ使うか・何を返さないか」を含む説明に書き直す ツール選択はdescriptionが主判断材料。プロンプト指示より確実で根本的
ツールのエラーが繰り返し発生する デフォルト値を返して処理を続行する 「受け取った値・正しい形式の例」を含む具体的なエラーメッセージをtool_resultで返す Claudeがエラーを読んで引数を修正して再試行する。具体的な情報がないと同じ誤りを繰り返す
似た機能のツールが2つある 1つの大きなツールに統合する 用途の境界を明確にしてdescriptionで「何を返さないか」を明示する 統合するとClaudeが引数で使い分けられなくなる。分割+境界説明が正しい設計

まとめ

  • Tool Useは「Claudeがツール呼び出しを要求 → アプリが実行 → 結果をClaudeに返す」という往復の仕組み
  • ツール関数は命名・バリデーション・具体的なエラーメッセージの3原則で設計する
  • JSON schemaの description はClaudeがツールを選択する主要判断材料。何を返さないか(境界条件)も書く
  • 似た名前・機能のツールが複数あるときほど、descriptionの差別化が選択信頼性に直結する
  • 次回(#9)ではスキーマをAPIに渡してClaudeのレスポンスを読み、ツールを実行してループを回す実装を扱う

← 前回:プロンプトの書き方②次回:Tool Useの基礎②