Loading...
  • ビルド
  • 管理
  • モデルと料金
  • クライアントSDK
  • APIリファレンス
Search...
⌘K
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,
        )