Was this page helpful?
すべてのMessages APIレスポンスには、Claudeが生成を停止した理由を示すstop_reasonフィールドが含まれています。このフィールドを確認して、レスポンスをそのまま使用するか、会話を続けるか、再試行するか、別のモデルにフォールバックするかを判断してください。
完全なレスポンススキーマについては、Messages APIリファレンスを参照してください。
| 値 | 発生するタイミング | 対処方法 |
|---|---|---|
end_turn | Claudeがレスポンスを自然に完了した。 | レスポンスを使用します。 |
max_tokens | レスポンスがmax_tokensの制限に達した。 | max_tokensを増やすか、レスポンスを継続します。 |
stop_sequence | Claudeが指定したstop_sequencesのいずれかを出力した。 | stop_sequenceを読み取り、どれがトリガーされたかを確認します。 |
tool_use | Claudeがツールを呼び出している。 | ツールを実行し、結果を返します。 |
pause_turn | サーバーツールのループが反復制限に達した。 | アシスタントのコンテンツを送り返して続行します。 |
refusal | Claudeが応答を拒否した。 | stop_detailsを読み取り、フォールバックモデルで再試行します。 |
model_context_window_exceeded | レスポンスがモデルのコンテキストウィンドウを埋め尽くした。 | レスポンスを切り捨てられたものとして扱います。 |
stop_reasonフィールドは、すべての成功したMessages APIレスポンスの一部です。リクエスト処理の失敗を示すエラーとは異なり、stop_reasonはClaudeがレスポンス生成を完了した理由を示します。
{
"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,
"stop_details": null,
"usage": {
"input_tokens": 100,
"output_tokens": 50
}
}最も一般的な停止理由です。Claudeがレスポンスを自然に完了したことを示します。
Claudeがリクエストで指定されたmax_tokensの制限に達したため停止しました。
Claudeがカスタム停止シーケンスのいずれかに遭遇しました。
Claudeがツールを呼び出しており、実行することを期待しています。
ほとんどのツール使用の実装では、ツールの実行、結果のフォーマット、会話管理を自動的に処理するツールランナーを使用してください。
ウェブ検索やウェブフェッチなどのサーバーツールを実行中に、サーバー側のサンプリングループが反復制限に達した場合に返されます。デフォルトの制限はリクエストごとに10回の反復です。
これが発生した場合、レスポンスには対応するserver_tool_resultのないserver_tool_useブロックが含まれることがあります。Claudeに処理を完了させるには、レスポンスをそのまま送り返して会話を続けてください。
サーバーツールを使用するエージェントループでは、アプリケーションがpause_turnを処理する必要があります。アシスタントのレスポンスをメッセージ配列に追加し、別のAPIリクエストを行ってClaudeに続行させてください。
Claudeがレスポンスの生成を拒否しました。Claude Fable 5では、安全性分類器はこの停止理由をエラーではなく通常のHTTP 200レスポンスとして返します。
Claude Sonnet 4.5またはOpus 4.1(非推奨)の使用中にrefusal停止理由が頻繁に発生する場合は、異なる使用制限を持つHaiku 4.5(claude-haiku-4-5-20251001)を使用するようにAPI呼び出しを更新してみてください。Sonnet 4.5のAPI安全フィルターについての詳細をご覧ください。
拒否が発生した場合、stop_detailsオブジェクトがそれをトリガーしたポリシーカテゴリを識別します。カテゴリと完全な拒否レスポンスの形式については、拒否とフォールバックで説明しています。stop_detailsは、refusal以外のすべての停止理由ではnullです。
Claude Fable 5で拒否されたリクエストは、通常、別のClaudeモデルで再試行することで処理できます。拒否とフォールバックでは、サーバー側またはクライアントでその再試行を設定する方法を示しています。フォールバッククレジットでは、再試行を自分で構築する際にプロンプトキャッシュのコストを二重に支払わないようにする方法について説明しています。
Claudeがモデルのコンテキストウィンドウの制限に達したため停止しました。これにより、正確な入力サイズを知らなくても、可能な限り最大のトークンをリクエストできます。
この停止理由は現在、SDKのbeta名前空間でのみ型付けされているため、以下の例ではclient.beta.messagesを呼び出し、Betaプレフィックス付きの型を使用しています。Sonnet 4.5以降のモデルでは、APIはベータヘッダーなしでこの値を返します。それ以前のモデルでは、model-context-window-exceeded-2025-08-26ベータヘッダーを追加して有効にしてください。
レスポンス処理ロジックでstop_reasonを確認することを習慣にしてください:
トークン制限またはコンテキストウィンドウが原因でレスポンスが切り捨てられた場合は、出力が不完全であることを読者に知らせる通知を追加してください。代わりにレスポンスが途切れた箇所から生成を続ける方法については、完全なレスポンスの確保を参照してください。
サーバーツールを使用する場合、サーバー側のサンプリングループが反復制限(デフォルト10)に達すると、APIはpause_turnを返すことがあります。会話を続けることでこれを処理してください:
stop_reason値と実際のエラーを区別することが重要です:
ストリーミングを使用する場合、stop_reasonは:
message_startイベントではnullmessage_deltaイベントで提供されるツールランナーでよりシンプルに: 以下の例は手動でのツール処理を示しています。ほとんどのユースケースでは、ツールランナーがはるかに少ないコードでツール実行を自動的に処理します。
model_context_window_exceeded停止理由により、入力サイズを計算せずに可能な限り最大のトークンをリクエストできます:
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello!"}],
)
if response.stop_reason == "end_turn":
# 完全なレスポンスを処理する
print(response.content[0].text)client = anthropic.Anthropic()
# トークン数を制限したリクエスト
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=10,
messages=[{"role": "user", "content": "Explain quantum physics"}],
)
if response.stop_reason == "max_tokens":
# レスポンスが切り詰められました
print("Response was cut off at token limit")
# 続きを取得するには別のリクエストの送信を検討してくださいclient = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-8",
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}")client = anthropic.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-opus-4-8",
max_tokens=1024,
tools=[weather_tool],
messages=[{"role": "user", "content": "What is the weather in San Francisco?"}],
)
if response.stop_reason == "tool_use":
# ツールを抽出して実行
for block in response.content:
if block.type == "tool_use":
result = execute_tool(block.name, block.input)
# 最終レスポンスのために結果をClaudeに返すresponse = client.messages.create(
model="claude-opus-4-8",
max_tokens=4096,
tools=[{"type": "web_search_20250305", "name": "web_search"}],
messages=[{"role": "user", "content": "Search for latest AI news"}],
)
if response.stop_reason == "pause_turn":
# レスポンスを送り返して会話を続けます
messages = [
{"role": "user", "content": "Search for latest AI news"},
{"role": "assistant", "content": response.content},
]
continuation = client.messages.create(
model="claude-opus-4-8",
max_tokens=4096,
messages=messages,
tools=[{"type": "web_search_20250305", "name": "web_search"}],
)client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
messages=[{"role": "user", "content": "[Unsafe request]"}],
)
if response.stop_reason == "refusal":
# Claudeが応答を拒否しました
print("Claude was unable to process this request")
# リクエストの言い換えや修正を検討してください# できるだけ多く取得するために最大トークン数でリクエスト
response = client.beta.messages.create(
model="claude-opus-4-8",
max_tokens=20000, # Python SDK requires streaming for max_tokens above ~21k (Opus 4.8 supports 128k with streaming)
messages=[
{"role": "user", "content": "Large input that uses most of context window..."}
],
)
if response.stop_reason == "model_context_window_exceeded":
# レスポンスが max_tokens より先にコンテキストウィンドウの上限に達しました
print("Response reached model's context window limit")
# レスポンスは有効ですが、コンテキストウィンドウによって制限されました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:
# end_turnやその他のケースを処理
return response.content[0].textdef handle_truncated_response(response):
if response.stop_reason in ["max_tokens", "model_context_window_exceeded"]:
if response.stop_reason == "max_tokens":
note = "[Response truncated due to max_tokens limit]"
else:
note = "[Response truncated due to context window limit]"
return f"{response.content[0].text}\n\n{note}"
return response.content[0].textdef 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-8", max_tokens=4096, messages=messages, tools=tools
)
if response.stop_reason != "pause_turn":
# Claudeが処理を完了 - 最終レスポンスを返す
return response
# pause_turn: ロールの交互性を維持するためメッセージリスト全体を置き換える
messages = [
{"role": "user", "content": user_query},
{"role": "assistant", "content": response.content},
]
# 最大継続回数に到達 - 最後のレスポンスを返す
return responseclient = anthropic.Anthropic()
try:
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello!"}],
)
# stop_reasonを含む成功レスポンスを処理
if response.stop_reason == "max_tokens":
print("Response was truncated")
except anthropic.APIStatusError as e:
# 実際のエラーを処理
if e.status_code == 429:
print("Rate limit exceeded")
elif e.status_code == 500:
print("Server error")client = anthropic.Anthropic()
with client.messages.stream(
model="claude-opus-4-8",
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-8", max_tokens=1024, messages=messages, tools=tools
)
if response.stop_reason == "tool_use":
# ツールを実行して続行
tool_results = execute_tools(response.content)
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
else:
# 最終レスポンス
return responsedef 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-8", messages=messages, max_tokens=4096
)
full_response += response.content[0].text
if response.stop_reason != "max_tokens":
break
# 中断した箇所から続行
messages = [
{"role": "user", "content": prompt},
{"role": "assistant", "content": full_response},
{"role": "user", "content": "Please continue from where you left off."},
]
return full_responsedef 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.beta.messages.create(
model="claude-opus-4-8",
messages=[{"role": "user", "content": prompt}],
max_tokens=20000, # Python SDK requires streaming for max_tokens above ~21k
)
if response.stop_reason == "model_context_window_exceeded":
# 入力サイズに対して可能な最大トークン数に達しました
print(
f"Generated {response.usage.output_tokens} tokens (context limit reached)"
)
elif response.stop_reason == "max_tokens":
# リクエストされたトークン数に正確に達しました
print(f"Generated {response.usage.output_tokens} tokens (max_tokens reached)")
else:
# 自然な完了
print(f"Generated {response.usage.output_tokens} tokens (natural completion)")
return response.content[0].text