Loading...
    • 構築
    • 管理
    • モデルと価格
    • クライアントSDK
    • APIリファレンス
    Search...
    ⌘K
    最初のステップ
    Claudeの紹介クイックスタート
    Claudeで構築
    機能概要Messages APIの使用Claude 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
    • 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
    • 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
    Claudeで構築

    停止理由の処理

    Claude の Messages API レスポンスの stop_reason フィールドを理解し、異なるレスポンスタイプを適切に処理する方法を学びます。

    Was this page helpful?

    • stop_reason フィールド
    • end_turn
    • max_tokens
    • stop_sequence
    • tool_use
    • pause_turn
    • refusal
    • model_context_window_exceeded
    • 1. 常に stop_reason をチェックする
    • 2. 切り詰められたレスポンスを適切に処理する
    • 3. pause_turn の再試行ロジックを実装する

    Messages API にリクエストを送信すると、Claude のレスポンスには stop_reason フィールドが含まれており、モデルがレスポンス生成を停止した理由を示します。これらの値を理解することは、異なるレスポンスタイプを適切に処理する堅牢なアプリケーションを構築するために重要です。

    API レスポンスの stop_reason の詳細については、Messages API リファレンスを参照してください。

    stop_reason フィールド

    stop_reason フィールドは、すべての成功した Messages API レスポンスに含まれます。リクエスト処理の失敗を示すエラーとは異なり、stop_reason は Claude がレスポンス生成を正常に完了した理由を示します。

    Example response
    {
      "id": "msg_01234",
      "type": "message",
      "role": "assistant",
      "content": [
        {
          "type": "text",
          "text": "Here's the answer to your question..."
        }
      ],
      "stop_reason": "end_turn",
      "stop_sequence": null,
      "usage": {
        "input_tokens": 100,
        "output_tokens": 50
      }
    }

    停止理由の値

    end_turn

    最も一般的な停止理由です。Claude がレスポンスを自然に完了したことを示します。

    Python
    from anthropic import Anthropic
    
    client = Anthropic()
    response = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=1024,
        messages=[{"role": "user", "content": "Hello!"}],
    )
    if response.stop_reason == "end_turn":
        # Process the complete response
        print(response.content[0].text)

    end_turn での空のレスポンス

    時々、Claude は空のレスポンス(コンテンツのない正確に 2~3 トークン)を stop_reason: "end_turn" で返します。これは通常、Claude がアシスタントのターンが完了したと解釈する場合、特にツール結果の後に発生します。

    一般的な原因:

    • ツール結果の直後にテキストブロックを追加する(Claude はツール結果の後に常にユーザーがテキストを挿入することを期待するように学習するため、パターンに従うためにターンを終了します)
    • Claude の完了したレスポンスを何も追加せずに送り返す(Claude は既に完了したと判断しているため、完了したままになります)

    空のレスポンスを防ぐ方法:

    # INCORRECT: Adding text immediately after tool_result
    messages = [
        {"role": "user", "content": "Calculate the sum of 1234 and 5678"},
        {
            "role": "assistant",
            "content": [
                {
                    "type": "tool_use",
                    "id": "toolu_123",
                    "name": "calculator",
                    "input": {"operation": "add", "a": 1234, "b": 5678},
                }
            ],
        },
        {
            "role": "user",
            "content": [
                {"type": "tool_result", "tool_use_id": "toolu_123", "content": "6912"},
                {
                    "type": "text",
                    "text": "Here's the result",  # Don't add text after tool_result
                },
            ],
        },
    ]
    
    # CORRECT: Send tool results directly without additional text
    messages = [
        {"role": "user", "content": "Calculate the sum of 1234 and 5678"},
        {
            "role": "assistant",
            "content": [
                {
                    "type": "tool_use",
                    "id": "toolu_123",
                    "name": "calculator",
                    "input": {"operation": "add", "a": 1234, "b": 5678},
                }
            ],
        },
        {
            "role": "user",
            "content": [
                {"type": "tool_result", "tool_use_id": "toolu_123", "content": "6912"}
            ],
        },  # Just the tool_result, no additional text
    ]
    
    
    # If you still get empty responses after fixing the above:
    def handle_empty_response(client, messages):
        response = client.messages.create(
            model="claude-opus-4-7", max_tokens=1024, messages=messages
        )
    
        # Check if response is empty
        if response.stop_reason == "end_turn" and not response.content:
            # INCORRECT: Don't just retry with the empty response
            # This won't work because Claude already decided it's done
    
            # CORRECT: Add a continuation prompt in a NEW user message
            messages.append({"role": "user", "content": "Please continue"})
    
            response = client.messages.create(
                model="claude-opus-4-7", max_tokens=1024, messages=messages
            )
    
        return response

    ベストプラクティス:

    1. ツール結果の直後にテキストブロックを追加しない - これは Claude にすべてのツール使用後にユーザー入力を期待するように教えます
    2. 修正なしに空のレスポンスを再試行しない - 単に空のレスポンスを送り返すだけでは役に立ちません
    3. 継続プロンプトは最後の手段として使用する - 上記の修正が問題を解決しない場合のみ

    max_tokens

    Claude がリクエストで指定された max_tokens 制限に達したため停止しました。

    Python
    # Request with limited tokens
    response = client.messages.create(
        model="claude-opus-4-7",
        max_tokens=10,
        messages=[{"role": "user", "content": "Explain quantum physics"}],
    )
    
    if response.stop_reason == "max_tokens":
        # Response was truncated
        print("Response was cut off at token limit")
        # Consider making another request to continue

    不完全なツール使用ブロック

    Claude のレスポンスが max_tokens 制限に達したため切り詰められ、切り詰められたレスポンスに不完全なツール使用ブロックが含まれている場合、より高い max_tokens 値でリクエストを再試行して、完全なツール使用を取得する必要があります。

    stop_sequence

    Claude がカスタム停止シーケンスの 1 つに遭遇しました。

    Python
    response = client.messages.create(
        model="claude-opus-4-7",
        max_tokens=1024,
        stop_sequences=["END", "STOP"],
        messages=[{"role": "user", "content": "Generate text until you say END"}],
    )
    
    if response.stop_reason == "stop_sequence":
        print(f"Stopped at sequence: {response.stop_sequence}")

    tool_use

    Claude がツールを呼び出しており、実行することを期待しています。

    ほとんどのツール使用実装では、ツール実行、結果のフォーマット、および会話管理を自動的に処理するツールランナーを使用することをお勧めします。

    Python
    from anthropic import Anthropic
    
    client = Anthropic()
    weather_tool = {
        "name": "get_weather",
        "description": "Get the current weather in a given location",
        "input_schema": {
            "type": "object",
            "properties": {
                "location": {"type": "string", "description": "City and state"},
            },
            "required": ["location"],
        },
    }
    
    
    def execute_tool(name, tool_input):
        """Execute a tool and return the result."""
        return f"Weather in {tool_input.get('location', 'unknown')}: 72°F"
    
    
    response = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=1024,
        tools=[weather_tool],
        messages=[{"role": "user", "content": "What's the weather?"}],
    )
    
    if response.stop_reason == "tool_use":
        # Extract and execute the tool
        for content in response.content:
            if content.type == "tool_use":
                result = execute_tool(content.name, content.input)
                # Return result to Claude for final response

    pause_turn

    Web 検索や Web フェッチなどのサーバーツールを実行中にサーバー側のサンプリングループが反復制限に達したときに返されます。デフォルトの制限はリクエストあたり 10 回の反復です。

    これが発生すると、レスポンスに対応する server_tool_result のない server_tool_use ブロックが含まれる場合があります。Claude が処理を完了できるようにするには、レスポンスをそのまま送り返して会話を続けます。

    Python
    response = client.messages.create(
        model="claude-opus-4-7",
        max_tokens=1024,
        tools=[{"type": "web_search_20250305", "name": "web_search"}],
        messages=[{"role": "user", "content": "Search for latest AI news"}],
    )
    
    if response.stop_reason == "pause_turn":
        # Continue the conversation by sending the response back
        messages = [
            {"role": "user", "content": original_query},
            {"role": "assistant", "content": response.content},
        ]
        continuation = client.messages.create(
            model="claude-opus-4-7",
            messages=messages,
            tools=[{"type": "web_search_20250305", "name": "web_search"}],
        )

    サーバーツールを使用するエージェントループで pause_turn を処理する必要があります。アシスタントのレスポンスをメッセージ配列に追加して、別の API リクエストを実行して Claude に続行させるだけです。

    refusal

    Claude は安全上の懸念からレスポンス生成を拒否しました。

    Python
    response = client.messages.create(
        model="claude-opus-4-7",
        max_tokens=1024,
        messages=[{"role": "user", "content": "[Unsafe request]"}],
    )
    
    if response.stop_reason == "refusal":
        # Claude declined to respond
        print("Claude was unable to process this request")
        # Consider rephrasing or modifying the request

    Claude Sonnet 4.5 または Opus 4.1 を使用中に refusal 停止理由が頻繁に発生する場合は、API 呼び出しを Haiku 4.5(claude-haiku-4-5-20251001)を使用するように更新してみてください。これは異なる使用制限があります。Sonnet 4.5 の API 安全フィルターの理解について詳しく学びます。

    Claude Sonnet 4.5 の API 安全フィルターによってトリガーされた拒否について詳しく知るには、Sonnet 4.5 の API 安全フィルターの理解を参照してください。

    model_context_window_exceeded

    Claude がモデルのコンテキストウィンドウ制限に達したため停止しました。これにより、正確な入力サイズを知らなくても最大限のトークンをリクエストできます。

    Python
    # Request with maximum tokens to get as much as possible
    response = client.messages.create(
        model="claude-opus-4-7",
        max_tokens=64000,  # Practical non-streaming ceiling (Opus 4.7 supports 128K with streaming)
        messages=[
            {"role": "user", "content": "Large input that uses most of context window..."}
        ],
    )
    
    if response.stop_reason == "model_context_window_exceeded":
        # Response hit context window limit before max_tokens
        print("Response reached model's context window limit")
        # The response is still valid but was limited by context window

    この停止理由は Sonnet 4.5 以降のモデルではデフォルトで利用可能です。以前のモデルの場合は、ベータヘッダー model-context-window-exceeded-2025-08-26 を使用してこの動作を有効にします。

    停止理由を処理するためのベストプラクティス

    1. 常に stop_reason をチェックする

    レスポンス処理ロジックで stop_reason をチェックする習慣をつけます:

    def handle_response(response):
        if response.stop_reason == "tool_use":
            return handle_tool_use(response)
        elif response.stop_reason == "max_tokens":
            return handle_truncation(response)
        elif response.stop_reason == "model_context_window_exceeded":
            return handle_context_limit(response)
        elif response.stop_reason == "pause_turn":
            return handle_pause(response)
        elif response.stop_reason == "refusal":
            return handle_refusal(response)
        else:
            # Handle end_turn and other cases
            return response.content[0].text

    2. 切り詰められたレスポンスを適切に処理する

    トークン制限またはコンテキストウィンドウによってレスポンスが切り詰められた場合:

    def handle_truncated_response(response):
        if response.stop_reason in ["max_tokens", "model_context_window_exceeded"]:
            # Option 1: Warn the user about the specific limit
            if response.stop_reason == "max_tokens":
                message = "[Response truncated due to max_tokens limit]"
            else:
                message = "[Response truncated due to context window limit]"
            return f"{response.content[0].text}\n\n{message}"
    
            # Option 2: Continue generation
            messages = [
                {"role": "user", "content": original_prompt},
                {"role": "assistant", "content": response.content[0].text},
            ]
            continuation = client.messages.create(
                model="claude-opus-4-7",
                max_tokens=1024,
                messages=messages + [{"role": "user", "content": "Please continue"}],
            )
            return response.content[0].text + continuation.content[0].text

    3. pause_turn の再試行ロジックを実装する

    サーバーツールを使用する場合、サーバー側のサンプリングループが反復制限に達すると API が pause_turn を返す場合があります(デフォルト 10)。会話を続けることでこれを処理します:

    def handle_server_tool_conversation(client, user_query, tools, max_continuations=5):
        """
        Handle server tool conversations that may require multiple continuations.
    
        The server runs a sampling loop when executing server tools. If the loop
        reaches its iteration limit, the API returns pause_turn. Continue the
        conversation by sending the response back to let Claude finish.
        """
        messages = [{"role": "user", "content": user_query}]
    
        for _ in range(max_continuations):
            response = client.messages.create(
                model="claude-opus-4-7", messages=messages, tools=tools
            )
    
            if response.stop_reason != "pause_turn":
                # Claude finished processing - return the final response
                return response
    
            # pause_turn: replace the full message list to maintain alternating roles
            messages = [
                {"role": "user", "content": user_query},
                {"role": "assistant", "content": response.content},
            ]
    
        # Reached max continuations - return the last response
        return response

    停止理由とエラー

    stop_reason 値と実際のエラーを区別することが重要です:

    停止理由(成功したレスポンス)

    • レスポンス本体の一部
    • 生成が正常に停止した理由を示す
    • レスポンスに有効なコンテンツが含まれる

    エラー(失敗したリクエスト)

    • HTTP ステータスコード 4xx または 5xx
    • リクエスト処理の失敗を示す
    • レスポンスにエラー詳細が含まれる
    Python
    import anthropic
    from anthropic import Anthropic
    
    client = Anthropic()
    
    try:
        response = client.messages.create(
            model="claude-sonnet-4-20250514",
            max_tokens=1024,
            messages=[{"role": "user", "content": "Hello!"}],
        )
    
        # Handle successful response with stop_reason
        if response.stop_reason == "max_tokens":
            print("Response was truncated")
    
    except anthropic.APIError as e:
        # Handle actual errors
        if e.status_code == 429:
            print("Rate limit exceeded")
        elif e.status_code == 500:
            print("Server error")

    ストリーミングに関する考慮事項

    ストリーミングを使用する場合、stop_reason は:

    • 初期の message_start イベントでは null
    • message_delta イベントで提供される
    • その他のイベントでは提供されない
    Python
    from anthropic import Anthropic
    
    client = Anthropic()
    
    with client.messages.stream(
        model="claude-sonnet-4-20250514",
        max_tokens=1024,
        messages=[{"role": "user", "content": "Hello!"}],
    ) as stream:
        for event in stream:
            if event.type == "message_delta":
                stop_reason = event.delta.stop_reason
                if stop_reason:
                    print(f"Stream ended with: {stop_reason}")

    一般的なパターン

    ツール使用ワークフローの処理

    ツールランナーでより簡単に: 以下の例は手動ツール処理を示しています。ほとんどのユースケースでは、ツールランナーがはるかに少ないコードでツール実行を自動的に処理します。

    def complete_tool_workflow(client, user_query, tools):
        messages = [{"role": "user", "content": user_query}]
    
        while True:
            response = client.messages.create(
                model="claude-opus-4-7", messages=messages, tools=tools
            )
    
            if response.stop_reason == "tool_use":
                # Execute tools and continue
                tool_results = execute_tools(response.content)
                messages.append({"role": "assistant", "content": response.content})
                messages.append({"role": "user", "content": tool_results})
            else:
                # Final response
                return response

    完全なレスポンスを確保する

    def get_complete_response(client, prompt, max_attempts=3):
        messages = [{"role": "user", "content": prompt}]
        full_response = ""
    
        for _ in range(max_attempts):
            response = client.messages.create(
                model="claude-opus-4-7", messages=messages, max_tokens=4096
            )
    
            full_response += response.content[0].text
    
            if response.stop_reason != "max_tokens":
                break
    
            # Continue from where it left off
            messages = [
                {"role": "user", "content": prompt},
                {"role": "assistant", "content": full_response},
                {"role": "user", "content": "Please continue from where you left off."},
            ]
    
        return full_response

    入力サイズを知らずに最大トークンを取得する

    model_context_window_exceeded 停止理由を使用すると、入力サイズを計算することなく、モデルのコンテキストウィンドウ内で可能な限り最大のトークンをリクエストできます:

    def get_max_possible_tokens(client, prompt):
        """
        Get as many tokens as possible within the model's context window
        without needing to calculate input token count
        """
        response = client.messages.create(
            model="claude-opus-4-7",
            messages=[{"role": "user", "content": prompt}],
            max_tokens=64000,  # Practical non-streaming ceiling (Opus 4.7 supports 128K with streaming)
        )
    
        if response.stop_reason == "model_context_window_exceeded":
            # Got the maximum possible tokens given input size
            print(
                f"Generated {response.usage.output_tokens} tokens (context limit reached)"
            )
        elif response.stop_reason == "max_tokens":
            # Got exactly the requested tokens
            print(f"Generated {response.usage.output_tokens} tokens (max_tokens reached)")
        else:
            # Natural completion
            print(f"Generated {response.usage.output_tokens} tokens (natural completion)")
    
        return response.content[0].text

    stop_reason 値を適切に処理することで、異なるレスポンスシナリオを適切に処理し、より良いユーザー体験を提供する、より堅牢なアプリケーションを構築できます。

    # Check if response was truncated during tool use
    if response.stop_reason == "max_tokens":
        # Check if the last content block is an incomplete tool_use
        last_block = response.content[-1]
        if last_block.type == "tool_use":
            # Send the request with higher max_tokens
            response = client.messages.create(
                model="claude-opus-4-7",
                max_tokens=4096,  # Increased limit
                messages=messages,
                tools=tools,
            )