Loading...
    • ビルド
    • 管理
    • モデルと料金
    • クライアントSDK
    • APIリファレンス
    Search...
    ⌘K
    はじめに
    Claudeの概要クイックスタート
    Claudeで構築する
    機能概要Messages APIの使用停止理由の処理
    モデルの機能
    拡張思考適応的思考エフォート高速モード(ベータ:リサーチプレビュー)構造化出力引用ストリーミングメッセージバッチ処理検索結果ストリーミング拒否多言語サポート埋め込み
    ツール
    概要ツール使用の仕組みウェブ検索ツールウェブフェッチツールコード実行ツールメモリツールBashツールコンピューター使用ツールテキストエディタツール
    ツールインフラ
    ツール検索プログラムによるツール呼び出し細粒度ツールストリーミング
    コンテキスト管理
    コンテキストウィンドウコンパクションコンテキスト編集プロンプトキャッシュトークンカウント
    ファイルの操作
    Files APIPDFサポート画像とビジョン
    スキル
    概要クイックスタートベストプラクティスエンタープライズ向けスキルAPIのスキル
    MCP
    リモートMCPサーバーMCPコネクター
    プロンプトエンジニアリング
    概要プロンプトのベストプラクティスConsoleプロンプトツール
    テストと評価
    成功の定義と評価の構築ConsoleでのEvaluation Toolの使用レイテンシの削減
    ガードレールの強化
    幻覚の低減出力の一貫性向上ジェイルブレイクの軽減プロンプトリークの低減
    リソース
    用語集
    リリースノート
    Claude Platform
    Console
    Log in
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...

    Solutions

    • AI agents
    • Code modernization
    • Coding
    • Customer support
    • Education
    • Financial services
    • Government
    • Life sciences

    Partners

    • Amazon Bedrock
    • Google Cloud's Vertex AI

    Learn

    • Blog
    • Catalog
    • Courses
    • Use cases
    • Connectors
    • Customer stories
    • Engineering at Anthropic
    • Events
    • Powered by Claude
    • Service partners
    • Startups program

    Company

    • Anthropic
    • Careers
    • Economic Futures
    • Research
    • News
    • Responsible Scaling Policy
    • Security and compliance
    • Transparency

    Learn

    • Blog
    • Catalog
    • Courses
    • Use cases
    • Connectors
    • Customer stories
    • Engineering at Anthropic
    • Events
    • Powered by Claude
    • Service partners
    • Startups program

    Help and security

    • Availability
    • Status
    • Support
    • Discord

    Terms and policies

    • Privacy policy
    • Responsible disclosure policy
    • Terms of service: Commercial
    • Terms of service: Consumer
    • Usage policy
    Documentation

    チュートリアル: ツール使用エージェントの構築

    単一のツール呼び出しから本番環境対応のエージェンティックループまでの段階的なガイド。

    Was this page helpful?

    • 円1: 単一ツール、単一ターン
    • 円2: エージェンティックループ
    • 円3: 複数ツール、並列呼び出し
    • 円4: エラーハンドリング
    • 円5: Tool Runner SDKの抽象化

    このチュートリアルでは、5つの同心円で構成されたカレンダー管理エージェントを構築します。各円は完全に実行可能なプログラムであり、その前の円に正確に1つの概念を追加します。最終的には、エージェンティックループを手書きで実装してから、Tool Runner SDKの抽象化に置き換えます。

    例として使用するツールはcreate_calendar_eventです。そのスキーマはネストされたオブジェクト、配列、オプショナルフィールドを使用しているため、単一のフラット文字列ではなく、現実的な入力形状をClaudeがどのように処理するかを確認できます。

    すべての円は独立して実行されます。任意の円を新しいファイルにコピーすれば、以前の円のコードなしで実行できます。

    円1: 単一ツール、単一ターン

    最小限のツール使用プログラム: 1つのツール、1つのユーザーメッセージ、1つのツール呼び出し、1つの結果。コードには詳細なコメントが付いているため、各行をツール使用ライフサイクルにマップできます。

    リクエストはユーザーメッセージと一緒にtools配列を送信します。Claudeがツールを呼び出すことを決定すると、レスポンスはstop_reason: "tool_use"と、ツール名、一意のid、構造化されたinputを含むtool_useコンテンツブロックで返されます。コードはツールを実行し、その結果をtool_use_idが呼び出しのidと一致するtool_resultブロックで送り返します。

    #!/bin/bash
    # Ring 1: Single tool, single turn.
    # Source for <CodeSource> in build-a-tool-using-agent.mdx.
    
    # Define one tool as a JSON fragment. The input_schema is a JSON Schema
    # object describing the arguments Claude should pass when it calls this
    # tool. This schema includes nested objects (recurrence), arrays
    # (attendees), and optional fields, which is closer to real-world tools
    # than a flat string argument.
    TOOLS='[
      {
        "name": "create_calendar_event",
        "description": "Create a calendar event with attendees and optional recurrence.",
        "input_schema": {
          "type": "object",
          "properties": {
            "title": {"type": "string"},
            "start": {"type": "string", "format": "date-time"},
            "end": {"type": "string", "format": "date-time"},
            "attendees": {
              "type": "array",
              "items": {"type": "string", "format": "email"}
            },
            "recurrence": {
              "type": "object",
              "properties": {
                "frequency": {"enum": ["daily", "weekly", "monthly"]},
                "count": {"type": "integer", "minimum": 1}
              }
            }
          },
          "required": ["title", "start", "end"]
        }
      }
    ]'
    
    USER_MSG="Schedule a 30-minute sync with [email protected] and [email protected] next Monday at 10am."
    
    # Send the user's request along with the tool definition. Claude decides
    # whether to call the tool based on the request and the tool description.
    RESPONSE=$(curl -s https://api.anthropic.com/v1/messages \
      -H "x-api-key: $ANTHROPIC_API_KEY" \
      -H "anthropic-version: 2023-06-01" \
      -H "content-type: application/json" \
      -d "$(jq -n \
        --argjson tools "$TOOLS" \
        --arg msg "$USER_MSG" \
        '{
          model: "claude-opus-4-6",
          max_tokens: 1024,
          tools: $tools,
          tool_choice: {type: "auto", disable_parallel_tool_use: true},
          messages: [{role: "user", content: $msg}]
        }')")
    
    # When Claude calls a tool, the response has stop_reason "tool_use"
    # and the content array contains a tool_use block alongside any text.
    echo "stop_reason: $(echo "$RESPONSE" | jq -r '.stop_reason')"
    
    # Find the tool_use block. A response may contain text blocks before the
    # tool_use block, so filter by type rather than assuming position.
    TOOL_USE=$(echo "$RESPONSE" | jq '.content[] | select(.type == "tool_use")')
    TOOL_USE_ID=$(echo "$TOOL_USE" | jq -r '.id')
    echo "Tool: $(echo "$TOOL_USE" | jq -r '.name')"
    echo "Input: $(echo "$TOOL_USE" | jq -c '.input')"
    
    # Execute the tool. In a real system this would call your calendar API.
    # Here the result is hardcoded to keep the example self-contained.
    RESULT='{"event_id": "evt_123", "status": "created"}'
    
    # Send the result back. The tool_result block goes in a user message and
    # its tool_use_id must match the id from the tool_use block above. The
    # assistant's previous response is included so Claude has the full history.
    ASSISTANT_CONTENT=$(echo "$RESPONSE" | jq '.content')
    FOLLOWUP=$(curl -s https://api.anthropic.com/v1/messages \
      -H "x-api-key: $ANTHROPIC_API_KEY" \
      -H "anthropic-version: 2023-06-01" \
      -H "content-type: application/json" \
      -d "$(jq -n \
        --argjson tools "$TOOLS" \
        --arg msg "$USER_MSG" \
        --argjson assistant "$ASSISTANT_CONTENT" \
        --arg tool_use_id "$TOOL_USE_ID" \
        --arg result "$RESULT" \
        '{
          model: "claude-opus-4-6",
          max_tokens: 1024,
          tools: $tools,
          tool_choice: {type: "auto", disable_parallel_tool_use: true},
          messages: [
            {role: "user", content: $msg},
            {role: "assistant", content: $assistant},
            {role: "user", content: [
              {type: "tool_result", tool_use_id: $tool_use_id, content: $result}
            ]}
          ]
        }')")
    
    # With the tool result in hand, Claude produces a final natural-language
    # answer and stop_reason becomes "end_turn".
    echo "stop_reason: $(echo "$FOLLOWUP" | jq -r '.stop_reason')"
    echo "$FOLLOWUP" | jq -r '.content[] | select(.type == "text") | .text'

    期待される出力

    Output
    stop_reason: tool_use
    Tool: create_calendar_event
    Input: {'title': 'Sync', 'start': '2026-03-30T10:00:00', 'end': '2026-03-30T10:30:00', 'attendees': ['[email protected]', '[email protected]']}
    stop_reason: end_turn
    I've scheduled your 30-minute sync with Alice and Bob for next Monday at 10am.

    最初のstop_reasonはtool_useです。これはClaudeがカレンダーの結果を待っているためです。結果を送信した後、2番目のstop_reasonはend_turnとなり、コンテンツはユーザー向けの自然言語です。

    円2: エージェンティックループ

    円1ではClaudeが正確に1回ツールを呼び出すと想定していました。実際のタスクでは複数の呼び出しが必要なことがよくあります。Claudeはイベントを作成し、確認を読み、その後別のイベントを作成するかもしれません。解決策は、stop_reasonが"tool_use"でなくなるまでツールを実行し続け、結果をフィードバックするwhileループです。

    もう1つの変更は会話履歴です。各リクエストでmessages配列をゼロから再構築する代わりに、実行中のリストを保持し、それに追加します。すべてのターンで完全な以前のコンテキストが表示されます。

    期待される出力

    Output
    I've set up your weekly team standup for the next 4 Mondays at 9am with Alice, Bob, and Carol invited.

    ループはClaudeがタスクをどのように分解するかに応じて、1回または複数回実行される可能性があります。コードは事前に知る必要がなくなります。

    円3: 複数ツール、並列呼び出し

    エージェントは通常、1つの機能だけを持ちません。2番目のツールlist_calendar_eventsを追加して、Claudeが新しいものを作成する前に既存のスケジュールを確認できるようにします。

    Claudeが複数の独立したツール呼び出しを行う場合、単一のレスポンスで複数のtool_useブロックを返す可能性があります。ループはそれらすべてを処理し、すべての結果を1つのユーザーメッセージで一緒に送り返す必要があります。最初のものだけでなく、response.content内のすべてのtool_useブロックを反復処理します。

    期待される出力

    Output
    I checked your calendar for next Monday and found an existing meeting from 2pm to 3pm. I've scheduled the planning session for 10am to 11am to avoid the conflict.

    並列実行と順序保証の詳細については、並列ツール使用を参照してください。

    円4: エラーハンドリング

    ツールは失敗します。カレンダーAPIが参加者が多すぎるイベントを拒否するか、日付が不正な形式である可能性があります。ツールがエラーを発生させた場合、クラッシュする代わりにis_error: trueでエラーメッセージを送り返します。Claudeはエラーを読み、修正された入力で再試行したり、ユーザーに説明を求めたり、制限事項を説明したりできます。

    期待される出力

    Output
    I tried to schedule the all-hands but the calendar only allows 10 attendees per event. I can split this into two sessions, or you can let me know which 10 people to prioritize.

    is_errorフラグは成功した結果との唯一の違いです。Claudeはフラグとエラーテキストを見て、それに応じて応答します。完全なエラーハンドリングリファレンスについては、ツール呼び出しの処理を参照してください。

    円5: Tool Runner SDKの抽象化

    円2から4では、同じループを手書きで実装しました: APIを呼び出し、stop_reasonをチェックし、ツールを実行し、結果を追加し、繰り返します。Tool Runnerはこれをあなたの代わりに行います。各ツールを関数として定義し、リストをtool_runnerに渡し、ループが完了したら最終メッセージを取得します。エラーラッピング、結果フォーマット、会話管理は内部で処理されます。

    Python SDKは@beta_toolデコレータを使用して、型ヒントとdocstringからスキーマを推論します。TypeScript SDKはZodスキーマでbetaZodToolを使用します。

    Tool RunnerはPython、TypeScript、およびRuby SDKで利用可能です。ShellおよびCLIタブはコードの代わりにメモを表示します。シェルベースのスクリプトの場合は円4のループを保持してください。

    期待される出力

    Output
    I checked your calendar for next Monday and found an existing meeting from 2pm to 3pm. I've scheduled the planning session for 10am to 11am to avoid the conflict.

    出力は円3と同じです。違いはコードにあります: 行数が約半分、手動ループなし、スキーマが実装の隣に存在します。

    構築したもの

    単一のハードコードされたツール呼び出しから始まり、複数のツール、並列呼び出し、エラーを処理する本番環境対応のエージェントで終わり、その後すべてをTool Runnerに折りたたみました。その過程で、ツール使用プロトコルのすべての部分を見ました: tool_useブロック、tool_resultブロック、tool_use_idマッチング、stop_reasonチェック、およびis_errorシグナリング。

    次のステップ

    スキーマを磨く

    スキーマ仕様とベストプラクティス。

    Tool Runnerの詳細解説

    完全なSDK抽象化リファレンス。

    トラブルシューティング

    一般的なツール使用エラーを修正します。

    #!/bin/bash
    # Ring 2: The agentic loop.
    # Source for <CodeSource> in build-a-tool-using-agent.mdx.
    
    TOOLS='[
      {
        "name": "create_calendar_event",
        "description": "Create a calendar event with attendees and optional recurrence.",
        "input_schema": {
          "type": "object",
          "properties": {
            "title": {"type": "string"},
            "start": {"type": "string", "format": "date-time"},
            "end": {"type": "string", "format": "date-time"},
            "attendees": {"type": "array", "items": {"type": "string", "format": "email"}},
            "recurrence": {
              "type": "object",
              "properties": {
                "frequency": {"enum": ["daily", "weekly", "monthly"]},
                "count": {"type": "integer", "minimum": 1}
              }
            }
          },
          "required": ["title", "start", "end"]
        }
      }
    ]'
    
    run_tool() {
      local name="$1"
      local input="$2"
      if [ "$name" = "create_calendar_event" ]; then
        local title=$(echo "$input" | jq -r '.title')
        jq -n --arg title "$title" '{event_id: "evt_123", status: "created", title: $title}'
      else
        echo "{\"error\": \"Unknown tool: $name\"}"
      fi
    }
    
    # Keep the full conversation history in a JSON array so each turn sees prior context.
    MESSAGES='[{"role": "user", "content": "Schedule a weekly team standup every Monday at 9am for the next 4 weeks. Invite the whole team: [email protected], [email protected], [email protected]."}]'
    
    call_api() {
      curl -s https://api.anthropic.com/v1/messages \
        -H "x-api-key: $ANTHROPIC_API_KEY" \
        -H "anthropic-version: 2023-06-01" \
        -H "content-type: application/json" \
        -d "$(jq -n --argjson tools "$TOOLS" --argjson messages "$MESSAGES" \
          '{model: "claude-opus-4-6", max_tokens: 1024, tools: $tools, tool_choice: {type: "auto", disable_parallel_tool_use: true}, messages: $messages}')"
    }
    
    RESPONSE=$(call_api)
    
    # Loop until Claude stops asking for tools. Each iteration runs the requested
    # tool, appends the result to history, and asks Claude to continue.
    while [ "$(echo "$RESPONSE" | jq -r '.stop_reason')" = "tool_use" ]; do
      TOOL_USE=$(echo "$RESPONSE" | jq '.content[] | select(.type == "tool_use")')
      TOOL_NAME=$(echo "$TOOL_USE" | jq -r '.name')
      TOOL_INPUT=$(echo "$TOOL_USE" | jq -c '.input')
      TOOL_USE_ID=$(echo "$TOOL_USE" | jq -r '.id')
      RESULT=$(run_tool "$TOOL_NAME" "$TOOL_INPUT")
    
      ASSISTANT_CONTENT=$(echo "$RESPONSE" | jq '.content')
      MESSAGES=$(echo "$MESSAGES" | jq \
        --argjson assistant "$ASSISTANT_CONTENT" \
        --arg tool_use_id "$TOOL_USE_ID" \
        --arg result "$RESULT" \
        '. + [
          {role: "assistant", content: $assistant},
          {role: "user", content: [{type: "tool_result", tool_use_id: $tool_use_id, content: $result}]}
        ]')
    
      RESPONSE=$(call_api)
    done
    
    echo "$RESPONSE" | jq -r '.content[] | select(.type == "text") | .text'
    #!/bin/bash
    # Ring 3: Multiple tools, parallel calls.
    # Source for <CodeSource> in build-a-tool-using-agent.mdx.
    
    TOOLS='[
      {
        "name": "create_calendar_event",
        "description": "Create a calendar event with attendees and optional recurrence.",
        "input_schema": {
          "type": "object",
          "properties": {
            "title": {"type": "string"},
            "start": {"type": "string", "format": "date-time"},
            "end": {"type": "string", "format": "date-time"},
            "attendees": {"type": "array", "items": {"type": "string", "format": "email"}},
            "recurrence": {
              "type": "object",
              "properties": {
                "frequency": {"enum": ["daily", "weekly", "monthly"]},
                "count": {"type": "integer", "minimum": 1}
              }
            }
          },
          "required": ["title", "start", "end"]
        }
      },
      {
        "name": "list_calendar_events",
        "description": "List all calendar events on a given date.",
        "input_schema": {
          "type": "object",
          "properties": {"date": {"type": "string", "format": "date"}},
          "required": ["date"]
        }
      }
    ]'
    
    run_tool() {
      case "$1" in
        create_calendar_event)
          jq -n --arg title "$(echo "$2" | jq -r '.title')" '{event_id: "evt_123", status: "created", title: $title}' ;;
        list_calendar_events)
          echo '{"events": [{"title": "Existing meeting", "start": "14:00", "end": "15:00"}]}' ;;
        *)
          echo "{\"error\": \"Unknown tool: $1\"}" ;;
      esac
    }
    
    MESSAGES='[{"role": "user", "content": "Check what I have next Monday, then schedule a planning session that avoids any conflicts."}]'
    
    call_api() {
      curl -s https://api.anthropic.com/v1/messages \
        -H "x-api-key: $ANTHROPIC_API_KEY" \
        -H "anthropic-version: 2023-06-01" \
        -H "content-type: application/json" \
        -d "$(jq -n --argjson tools "$TOOLS" --argjson messages "$MESSAGES" \
          '{model: "claude-opus-4-6", max_tokens: 1024, tools: $tools, messages: $messages}')"
    }
    
    RESPONSE=$(call_api)
    
    while [ "$(echo "$RESPONSE" | jq -r '.stop_reason')" = "tool_use" ]; do
      # A single response can contain multiple tool_use blocks. Process all of
      # them and return all results together in one user message.
      TOOL_RESULTS='[]'
      while read -r block; do
        NAME=$(echo "$block" | jq -r '.name')
        INPUT=$(echo "$block" | jq -c '.input')
        ID=$(echo "$block" | jq -r '.id')
        RESULT=$(run_tool "$NAME" "$INPUT")
        TOOL_RESULTS=$(echo "$TOOL_RESULTS" | jq --arg id "$ID" --arg result "$RESULT" \
          '. + [{type: "tool_result", tool_use_id: $id, content: $result}]')
      done < <(echo "$RESPONSE" | jq -c '.content[] | select(.type == "tool_use")')
    
      MESSAGES=$(echo "$MESSAGES" | jq \
        --argjson assistant "$(echo "$RESPONSE" | jq '.content')" \
        --argjson results "$TOOL_RESULTS" \
        '. + [{role: "assistant", content: $assistant}, {role: "user", content: $results}]')
    
      RESPONSE=$(call_api)
    done
    
    echo "$RESPONSE" | jq -r '.content[] | select(.type == "text") | .text'
    #!/bin/bash
    # Ring 4: Error handling.
    # Source for <CodeSource> in build-a-tool-using-agent.mdx.
    
    TOOLS='[
      {
        "name": "create_calendar_event",
        "description": "Create a calendar event with attendees and optional recurrence.",
        "input_schema": {
          "type": "object",
          "properties": {
            "title": {"type": "string"},
            "start": {"type": "string", "format": "date-time"},
            "end": {"type": "string", "format": "date-time"},
            "attendees": {"type": "array", "items": {"type": "string", "format": "email"}},
            "recurrence": {
              "type": "object",
              "properties": {
                "frequency": {"enum": ["daily", "weekly", "monthly"]},
                "count": {"type": "integer", "minimum": 1}
              }
            }
          },
          "required": ["title", "start", "end"]
        }
      },
      {
        "name": "list_calendar_events",
        "description": "List all calendar events on a given date.",
        "input_schema": {
          "type": "object",
          "properties": {"date": {"type": "string", "format": "date"}},
          "required": ["date"]
        }
      }
    ]'
    
    run_tool() {
      case "$1" in
        create_calendar_event)
          local count=$(echo "$2" | jq '.attendees | length // 0')
          if [ "$count" -gt 10 ]; then
            echo "ERROR: Too many attendees (max 10)"
            return 1
          fi
          jq -n --arg title "$(echo "$2" | jq -r '.title')" '{event_id: "evt_123", status: "created", title: $title}' ;;
        list_calendar_events)
          echo '{"events": [{"title": "Existing meeting", "start": "14:00", "end": "15:00"}]}' ;;
        *)
          echo "ERROR: Unknown tool: $1"
          return 1 ;;
      esac
    }
    
    EMAILS=$(seq 0 14 | sed 's/.*/user&@example.com/' | paste -sd, -)
    MESSAGES="[{\"role\": \"user\", \"content\": \"Schedule an all-hands with everyone: $EMAILS\"}]"
    
    call_api() {
      curl -s https://api.anthropic.com/v1/messages \
        -H "x-api-key: $ANTHROPIC_API_KEY" \
        -H "anthropic-version: 2023-06-01" \
        -H "content-type: application/json" \
        -d "$(jq -n --argjson tools "$TOOLS" --argjson messages "$MESSAGES" \
          '{model: "claude-opus-4-6", max_tokens: 1024, tools: $tools, messages: $messages}')"
    }
    
    RESPONSE=$(call_api)
    
    while [ "$(echo "$RESPONSE" | jq -r '.stop_reason')" = "tool_use" ]; do
      TOOL_RESULTS='[]'
      while read -r block; do
        NAME=$(echo "$block" | jq -r '.name')
        INPUT=$(echo "$block" | jq -c '.input')
        ID=$(echo "$block" | jq -r '.id')
        if OUTPUT=$(run_tool "$NAME" "$INPUT"); then
          TOOL_RESULTS=$(echo "$TOOL_RESULTS" | jq --arg id "$ID" --arg result "$OUTPUT" \
            '. + [{type: "tool_result", tool_use_id: $id, content: $result}]')
        else
          # Signal failure so Claude can retry or ask for clarification.
          TOOL_RESULTS=$(echo "$TOOL_RESULTS" | jq --arg id "$ID" --arg result "$OUTPUT" \
            '. + [{type: "tool_result", tool_use_id: $id, content: $result, is_error: true}]')
        fi
      done < <(echo "$RESPONSE" | jq -c '.content[] | select(.type == "tool_use")')
    
      MESSAGES=$(echo "$MESSAGES" | jq \
        --argjson assistant "$(echo "$RESPONSE" | jq '.content')" \
        --argjson results "$TOOL_RESULTS" \
        '. + [{role: "assistant", content: $assistant}, {role: "user", content: $results}]')
    
      RESPONSE=$(call_api)
    done
    
    echo "$RESPONSE" | jq -r '.content[] | select(.type == "text") | .text'
    #!/bin/bash
    # Ring 5: The Tool Runner SDK abstraction.
    # Source for <CodeSource> in build-a-tool-using-agent.mdx.
    
    # The Tool Runner SDK abstraction is available in the Python, TypeScript,
    # and Ruby SDKs. There is no equivalent for raw curl requests. Switch to
    # the Python or TypeScript tab to see Ring 5, or keep the Ring 4 loop as
    # your shell implementation.