mcpField
T
tool-use

tool-use

github.com/thelobbiエージェントワークフロー2154 回インストール1 日前に更新
リポジトリ

tool-use について

tool-useは、Claudeでツール対応のエージェントやワークフローを構築する開発者向けガイドです。スキーマ設計、ツール選択、呼び出しの調整、エラー処理、厳密なスキーマ検証を扱います。

主な機能

  1. 01JSON Schemaによるツール入力の設計
  2. 02ツール選択モードの解説
  3. 03複数ターンと並列呼び出し
  4. 04ツール結果とエラーの処理
  5. 05厳密なスキーマ検証の説明

活用シーン

  1. 01Claudeアプリ向けツールの定義
  2. 02順次または並列のツール呼び出しの調整
  3. 03不正な入力やツール障害への対応

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/thelobbi/claude --skill tool-use

インストール後、Claude Code で/tool-useを入力して読み込まれたか確認します。

同梱ファイルQUICK-REFERENCE.md

詳細

ツール使用スキル

Claude でのツール使用を実装するための包括的なガイドです。スキーマ設計、ツール選択モード、複数ターンの会話、エラー処理パターン、拡張思考や厳密なスキーマ準拠などの高度な機能を扱います。

このスキルを使用する場面

次のような場合に、このスキルを有効にします。

  • JSON スキーマを使ってカスタムツールを定義する場合
  • ツールを使用するエージェント型ワークフローを構築する場合
  • ツールの結果処理を実装する場合
  • 並列または逐次のツールオーケストレーションを構築する場合
  • スキーマ準拠を保証する必要がある場合
  • エラー回復パターンを実装する場合
  • ツールと拡張思考を組み合わせる場合

主な概念

ツール定義スキーマ

すべてのツールには、次の項目を含む JSON Schema 入力定義が必要です。

  • name:ツール識別子(正規表現:^[a-zA-Z0-9_-]{1,64}$)
  • description:目的、使用する場面、動作の詳細な説明(3~4文以上)
  • input_schema:パラメーターを定義する JSON Schema
  • input_examples(任意、ベータ):有効な入力の具体例
ツール定義のベストプラクティス
{
  "name": "get_stock_price",
  "description": "Retrieves the current stock price for a given ticker symbol. The ticker symbol must be a valid symbol for a publicly traded company on a major US stock exchange like NYSE or NASDAQ. The tool will return the latest trade price in USD. Use this when the user asks about the current or most recent price of a specific stock. It will not provide any other information about the stock or company beyond the price.",
  "input_schema": {
    "type": "object",
    "properties": {
      "ticker": {
        "type": "string",
        "description": "The stock ticker symbol, e.g. AAPL for Apple Inc. Must be uppercase."
      },
      "include_historical": {
        "type": "boolean",
        "description": "Optional. Whether to include 52-week high/low prices.",
        "default": false
      }
    },
    "required": ["ticker"],
    "additionalProperties": false
  },
  "input_examples": [
    {"ticker": "AAPL"},
    {"ticker": "MSFT", "include_historical": true},
    {"ticker": "GOOGL"}
  ]
}

主なガイドライン:

  • 説明は最低でも3~4文以上にしてください
  • ツールが何をするか、どのような場面で使うか、何を返すか、制限事項を説明してください
  • 複雑な入れ子のオブジェクトや形式に依存するパラメーターには、input_examples を使用してください
  • 厳密に検証するには、additionalProperties: false を設定してください
  • 値を制限するパラメーターには列挙型を使用してください
ツール選択モード

Claude がツールを使用するかどうか、またその使用方法を決定する動作を制御します。

モード動作使用例
"auto"Claude がツールを使うかどうかを判断します(デフォルト)一般的なツール使用。Claude に判断を任せる場合
"any"Claude は必ず1つのツールを使用しますが、どのツールを使うかは選択できます特定のツールを指定せずにツール使用を強制する場合
"tool"特定のツールを強制します(例:{"type": "tool", "name": "get_weather"})構造化 JSON 出力や特定のツールが必要な場合
"none"すべてのツール使用を禁止します通常のテキストのみの応答
# Allow Claude to decide
# tool_choice="auto" (default)

# Force any tool to be used
tool_choice={"type": "any"}

# Force specific tool (useful for JSON output)
tool_choice={"type": "tool", "name": "record_summary"}

# Prevent tool use
tool_choice={"type": "none"}

拡張思考に関する重要な制約:

  • 拡張思考でサポートされる tool_choice は {"type": "auto"} または {"type": "none"} のみです
  • 拡張思考では {"type": "any"} または {"type": "tool"} は使用できません
  • ツールを使った複雑な推論には、代わりに専用の「think」ツールを使用してください
厳密なスキーマ準拠(ベータ)

strict: true を設定すると、スキーマ検証が保証されます。

tools=[{
    "name": "search_flights",
    "strict": True,  # Enable strict mode
    "input_schema": {
        "type": "object",
        "properties": {
            "destination": {"type": "string"},
            "departure_date": {"type": "string", "format": "date"},
            "passengers": {"type": "integer"}
        },
        "required": ["destination", "departure_date"],
        "additionalProperties": False
    }
}]

メリット:

  • 型安全なパラメーターが保証されます(2 の代わりに "2" が使われることはありません)
  • 必須フィールドの欠落がありません
  • 実行時のスキーマ検証が不要です
  • 本番環境で信頼性の高い動作が実現します

制限事項:

  • 拒否応答はスキーマより優先されます(安全性が優先されます)
  • トークン制限による切り捨てで、スキーマが崩れる場合があります
  • 一部の再帰スキーマはサポートされていません
  • structured-outputs-2025-11-13 ベータヘッダーが必要です

単一ツール使用パターン

基本パターン:ツールを定義 → Claude がツールを呼び出す → 結果を返す → Claude が応答する

import anthropic

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    tools=[{
        "name": "get_weather",
        "description": "Get current weather in a location",
        "input_schema": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "City and state, e.g. San Francisco, CA"
                }
            },
            "required": ["location"]
        }
    }],
    messages=[{"role": "user", "content": "What's the weather in SF?"}]
)

# Check if Claude wants to use tool
if response.stop_reason == "tool_use":
    tool_use = next(b for b in response.content if b.type == "tool_use")
    print(f"Tool: {tool_use.name}")
    print(f"Input: {tool_use.input}")

    # Execute tool (simulate)
    tool_result = "68°F, partly cloudy"

    # Return result to Claude
    response = client.messages.create(
        model="claude-sonnet-5",
        max_tokens=1024,
        tools=[...],  # Same tools
        messages=[
            {"role": "user", "content": "What's the weather in SF?"},
            {"role": "assistant", "content": response.content},
            {"role": "user", "content": [{
                "type": "tool_result",
                "tool_use_id": tool_use.id,
                "content": tool_result
            }]}
        ]
    )

    print(response.content[0].text)

複数ターンのツール会話

あるツールの出力を別のツールに渡す、逐次的な呼び出しが必要になることはよくあります。

# User asks: "What's the weather where I am?"
# Flow: get_location() → get_weather(location)

response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    tools=[
        {
            "name": "get_location",
            "description": "Get user's location from IP address",
            "input_schema": {"type": "object", "properties": {}}
        },
        {
            "name": "get_weather",
            "description": "Get weather for location",
            "input_schema": {
                "type": "object",
                "properties": {
                    "location": {"type": "string"}
                },
                "required": ["location"]
            }
        }
    ],
    messages=[{"role": "user", "content": "What's the weather where I am?"}]
)

# Claude calls get_location first
tool_use = next(b for b in response.content if b.type == "tool_use")
location_result = "San Francisco, CA"

# Send location result back
response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    tools=[...],
    messages=[
        {"role": "user", "content": "What's the weather where I am?"},
        {"role": "assistant", "content": response.content},
        {"role": "user", "content": [{
            "type": "tool_result",
            "tool_use_id": tool_use.id,
            "content": location_result
        }]}
    ]
)

# Claude now calls get_weather with the location
tool_use2 = next(b for b in response.content if b.type == "tool_use")
weather_result = "68°F, sunny"

# Final result
response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    tools=[...],
    messages=[
        {"role": "user", "content": "What's the weather where I am?"},
        {"role": "assistant", "content": response.content},
        {"role": "user", "content": [{
            "type": "tool_result",
            "tool_use_id": tool_use.id,
            "content": location_result
        }]},
        {"role": "assistant", "content": response.content},
        {"role": "user", "content": [{
            "type": "tool_result",
            "tool_use_id": tool_use2.id,
            "content": weather_result
        }]}
    ]
)

print(response.content[0].text)

並列ツール使用パターン

Claude は、互いに独立した複数のツールを同時に呼び出せます。

response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    tools=[...],
    messages=[{
        "role": "user",
        "content": "What's the weather in SF and NYC? What time is it there?"
    }]
)

# Claude makes 4 parallel tool calls (2 weather + 2 time)
tool_uses = [b for b in response.content if b.type == "tool_use"]
print(f"Parallel calls: {len(tool_uses)}")  # 4

# Execute all tools and collect results
tool_results = []
for tool_use in tool_uses:
    if tool_use.name == "get_weather":
        if "San Francisco" in str(tool_use.input):
            result = "68°F, partly cloudy"
        else:
            result = "45°F, clear"
    else:  # get_time
        if "Los_Angeles" in str(tool_use.input):
            result = "2:30 PM PST"
        else:
            result = "5:30 PM EST"

    tool_results.append({
        "type": "tool_result",
        "tool_use_id": tool_use.id,
        "content": result
    })

# IMPORTANT: Return all results in ONE user message
response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    tools=[...],
    messages=[
        {"role": "user", "content": "What's the weather in SF and NYC? What time is it there?"},
        {"role": "assistant", "content": response.content},
        {"role": "user", "content": tool_results}  # All results together!
    ]
)

print(response.content[0].text)

並列ツールの重要な形式ルール:

  • すべてのツール結果を1つのユーザーメッセージに含める必要があります
  • コンテンツ配列では、ツール結果ブロックを最初に配置する必要があります
  • 必要に応じて、ツール結果の後にテキストを追加できます
  • 誤った形式は、Claude が並列呼び出しを避けるよう学習する原因になります

ツール結果の処理

基本的なツール結果の形式
{
    "type": "tool_result",
    "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
    "content": "15 degrees"
}
画像を含むツール結果
{
    "type": "tool_result",
    "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
    "content": [
        {"type": "text", "text": "Current weather screenshot:"},
        {
            "type": "image",
            "source": {
                "type": "base64",
                "media_type": "image/jpeg",
                "data": "/9j/4AAQSkZJRg..."
            }
        }
    ]
}
ドキュメントを含むツール結果
{
    "type": "tool_result",
    "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
    "content": [
        {"type": "text", "text": "Document content:"},
        {
            "type": "document",
            "source": {
                "type": "text",
                "media_type": "text/plain",
                "data": "Full document content here"
            }
        }
    ]
}
ツール結果のエラー処理
# Tool execution error
{
    "type": "tool_result",
    "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
    "content": "ConnectionError: Weather API is unavailable (HTTP 500)",
    "is_error": True
}

# Missing parameter error
{
    "type": "tool_result",
    "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
    "content": "Error: Missing required 'location' parameter",
    "is_error": True
}

エラー回復パターン

パターン1:適切なエラー報告

ツールの実行に失敗した場合は、エラーを報告すると、Claude は修正を加えて再試行します。

if tool_execution_failed:
    tool_result = {
        "type": "tool_result",
        "tool_use_id": tool_use.id,
        "content": f"Error: {error_message}",
        "is_error": True
    }

通常、Claude はユーザーに謝罪する前に2~3回再試行します。

パターン2:厳密なスキーマ適用

strict: true を指定すると、無効なパラメーターは実行前に拒否されます。

# With strict: true, Claude CANNOT send invalid parameters
# Invalid type: "passengers": "two" → prevented by schema
# Missing required field → prevented by schema
# Type mismatch: int vs string → prevented by schema
パターン3:最大トークン数の処理

ツール使用中に応答が途切れた場合は、上限を増やして再試行します。

if response.stop_reason == "max_tokens":
    last_block = response.content[-1]
    if last_block.type == "tool_use":
        # Incomplete tool use, retry with more tokens
        response = client.messages.create(
            model="claude-sonnet-5",
            max_tokens=4096,  # Increased
            messages=messages,
            tools=tools
        )

構造化 JSON 出力のためのツール使用

ツールを実行せずに、ツールを使って構造化 JSON 出力を保証します。

response = client.beta.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    betas=["structured-outputs-2025-11-13"],
    tools=[{
        "name": "record_summary",
        "description": "Record structured image summary",
        "input_schema": {
            "type": "object",
            "properties": {
                "key_colors": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "r": {"type": "number"},
                            "g": {"type": "number"},
                            "b": {"type": "number"},
                            "name": {"type": "string"}
                        },
                        "required": ["r", "g", "b", "name"]
                    }
                },
                "description": {"type": "string"},
                "estimated_year": {"type": "integer"}
            },
            "required": ["key_colors", "description"]
        }
    }],
    tool_choice={"type": "tool", "name": "record_summary"},
    messages=[{
        "role": "user",
        "content": [
            {"type": "image", "source": {"type": "url", "url": "https://..."}},
            {"type": "text", "text": "Describe this image"}
        ]
    }]
)

# Extract structured output from tool use input
tool_use = next(b for b in response.content if b.type == "tool_use")
structured_data = tool_use.input

ツールの並列使用に関するベストプラクティス

並列実行の促進

より強力な並列ツール使用を促すため、システムプロンプトに追加します。

<use_parallel_tool_calls>
For maximum efficiency, whenever you perform multiple independent operations,
invoke all relevant tools simultaneously rather than sequentially. Prioritize
calling tools in parallel whenever possible. When reading 3 files, run 3 tool
calls in parallel. When running multiple commands like 'ls' or 'list_dir',
always run all commands in parallel.
</use_parallel_tool_calls>
並列ツール使用の測定
def measure_parallel_efficiency(messages):
    # Find assistant messages with tool use
    tool_call_messages = [
        msg for msg in messages
        if msg.get("role") == "assistant"
        and any(b.get("type") == "tool_use" for b in msg.get("content", []))
    ]

    total_tools = sum(
        len([b for b in msg.get("content", []) if b.get("type") == "tool_use"])
        for msg in tool_call_messages
    )

    if not tool_call_messages:
        return 0

    avg_per_message = total_tools / len(tool_call_messages)
    print(f"Average tools per message: {avg_per_message}")
    # > 1.0 indicates parallel tool use working

拡張思考の統合

拡張思考の制約
# ✅ ALLOWED with extended thinking
response = client.messages.create(
    model="claude-opus-4-8",
    thinking={"type": "adaptive"},
    tools=[...],
    tool_choice={"type": "auto"},  # Default
    messages=[...]
)

# ✅ ALLOWED with extended thinking
tool_choice={"type": "none"}  # No tools

# ❌ NOT ALLOWED with extended thinking
# tool_choice={"type": "any"}  → Error
# tool_choice={"type": "tool", "name": "..."}  → Error
複雑な推論のための「think」ツール

ツールを使った拡張推論が必要な場合は、「think」ツールを使用します。

tools=[{
    "name": "think",
    "description": "Pause and think carefully before proceeding",
    "input_schema": {
        "type": "object",
        "properties": {
            "reasoning": {
                "type": "string",
                "description": "Your detailed reasoning"
            }
        },
        "required": ["reasoning"]
    }
}, {
    "name": "get_weather",
    "description": "Get weather information",
    "input_schema": {...}
}]

SDK ツールランナー(簡易実装)

Python および TypeScript の SDK には、ツールを自動実行するツールランナーが用意されています。

import anthropic
from anthropic import beta_tool

client = anthropic.Anthropic()

@beta_tool
def get_weather(location: str, unit: str = "fahrenheit") -> str:
    """Get current weather in a location.

    Args:
        location: City and state, e.g. San Francisco, CA
        unit: Temperature unit, either 'celsius' or 'fahrenheit'
    """
    # Tool implementation
    return '{"temperature": "20°C", "condition": "Sunny"}'

# Tool runner automatically handles tool execution loop
runner = client.beta.messages.tool_runner(
    model="claude-sonnet-5",
    max_tokens=1024,
    tools=[get_weather],
    messages=[{"role": "user", "content": "What's the weather in Paris?"}]
)

# Iterate through responses
for message in runner:
    print(message.content[0].text)

# Or get final message directly
final_message = runner.until_done()

JSON Schema のサポートと制限事項

サポートされる機能
  • すべての基本型:object、array、string、integer、number、boolean、null
  • 値を制限するための enum
  • 固定値のための const
  • 複合型のための anyOf、allOf
  • スキーマを構成するための $ref、$def、definitions
  • 文字列形式:date-time、time、date、duration、email、hostname、uri、ipv4、ipv6、uuid
  • 配列の minItems(0 と 1 のみ)
サポートされない機能
  • 再帰スキーマ(ネストの深さに制限を設けてください)
  • enum 内の複合型
  • 外部 $ref(例:HTTP URL)
  • 数値の制約(minimum、maximum、multipleOf)
  • 文字列の制約(minLength、maxLength)
  • 高度な配列の制約
  • false 以外の値を指定する additionalProperties
  • 正規表現パターン内の後方参照

一般的なユースケース

データ抽出
tools=[{
    "name": "extract_info",
    "description": "Extract structured data from text",
    "input_schema": {
        "type": "object",
        "properties": {
            "name": {"type": "string"},
            "email": {"type": "string"},
            "company": {"type": "string"}
        },
        "required": ["name", "email"]
    }
}]
API 統合
tools=[{
    "name": "search_api",
    "description": "Search external API",
    "input_schema": {
        "type": "object",
        "properties": {
            "query": {"type": "string"},
            "limit": {"type": "integer", "minimum": 1, "maximum": 100}
        },
        "required": ["query"]
    }
}]
複数ステップのオーケストレーション
tools=[
    {"name": "validate_input", ...},
    {"name": "process_data", ...},
    {"name": "save_result", ...}
]
# Claude orchestrates the workflow

パフォーマンスに関する考慮事項

ツールのトークンコスト
  • ツール定義は入力トークンに追加されます
  • リクエスト/レスポンス内のツール使用ブロックはトークンとしてカウントされます
  • ツール結果ブロックはトークンとしてカウントされます
  • ツール使用のシステムプロンプト:tool_choice に応じて 313~346 トークン
文法のコンパイル
  • スキーマの初回使用時:文法のコンパイルによる追加のレイテンシーが発生します
  • 2 回目以降の使用時:文法は 24 時間キャッシュされます
  • スキーマまたはツールセットを変更すると、キャッシュは無効になります
  • 名前や説明の変更では、キャッシュは無効になりません
コンテキストウィンドウの管理

長い会話では、ツール使用によってコンテキストがすぐに消費されることがあります。次の方法を活用してください。

  1. 圧縮:ツールの結果を要約します
  2. チャンク化:大規模な操作を小さなリクエストに分割します
  3. ツールランナー:必要に応じてコンテキストを自動的に圧縮します
  4. チェックポイント:フェーズ間で会話の状態を保存します

ツール使用の強制(構造化出力)

tool_choice を使用して、特定の動作を強制します。

# Force use of a tool (for JSON output)
response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    tools=[sentiment_tool],
    tool_choice={"type": "tool", "name": "sentiment_tool"},
    messages=[{"role": "user", "content": "Analyze this text..."}]
)

# No prefilled explanations with forced tool_choice
# Claude goes straight to tool use

# For explanations WITH tool use, use tool_choice="auto" (default)
# and add instruction: "Use the sentiment_tool in your response"

停止理由の処理

tool_use

Claude はツールの使用を要求しています。ツール使用ブロックを抽出して、ツールを実行します。

end_turn

Claude はレスポンスの生成を完了しました。追加のツール呼び出しはありません。

max_tokens

レスポンスが途中で切れました。最後のブロックが未完了の tool_use である場合は、max_tokens を増やして再試行します。

pause_turn(サーバーツール使用時)

長時間の操作が一時停止しました。会話を続けて再開します。


リソース

コメント