Wenn Sie eine Anfrage an die Messages API stellen, enthält Claudes Antwort ein stop_reason-Feld, das angibt, warum das Modell die Generierung seiner Antwort gestoppt hat. Das Verständnis dieser Werte ist entscheidend für die Erstellung robuster Anwendungen, die verschiedene Antworttypen angemessen handhaben.
Für Details über stop_reason in der API-Antwort siehe die Messages API-Referenz.
Was ist stop_reason?
Das stop_reason-Feld ist Teil jeder erfolgreichen Messages API-Antwort. Im Gegensatz zu Fehlern, die Ausfälle bei der Verarbeitung Ihrer Anfrage anzeigen, teilt Ihnen stop_reason mit, warum Claude seine Antwortgenerierung erfolgreich abgeschlossen hat.
{
"id": "msg_01234",
"type": "message",
"role": "assistant",
"content": [
{
"type": "text",
"text": "Hier ist die Antwort auf Ihre Frage..."
}
],
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 100,
"output_tokens": 50
}
}
Stop-Reason-Werte
end_turn
Der häufigste Stop-Grund. Zeigt an, dass Claude seine Antwort natürlich beendet hat.
if response.stop_reason == "end_turn":
# Verarbeite die vollständige Antwort
print(response.content[0].text)
Leere Antworten mit end_turn
Manchmal gibt Claude eine leere Antwort zurück (genau 2-3 Token ohne Inhalt) mit stop_reason: "end_turn". Dies passiert typischerweise, wenn Claude interpretiert, dass der Assistenten-Turn abgeschlossen ist, insbesondere nach Tool-Ergebnissen.
Häufige Ursachen:
- Hinzufügen von Textblöcken unmittelbar nach Tool-Ergebnissen (Claude lernt zu erwarten, dass der Benutzer immer Text nach Tool-Ergebnissen einfügt, also beendet es seinen Turn, um dem Muster zu folgen)
- Zurücksenden von Claudes abgeschlossener Antwort ohne etwas hinzuzufügen (Claude hat bereits entschieden, dass es fertig ist, also wird es fertig bleiben)
Wie man leere Antworten verhindert:
# FALSCH: Text unmittelbar nach tool_result hinzufügen
messages = [
{"role": "user", "content": "Berechne die Summe von 1234 und 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": "Hier ist das Ergebnis" # Fügen Sie keinen Text nach tool_result hinzu
}
]}
]
# RICHTIG: Tool-Ergebnisse direkt ohne zusätzlichen Text senden
messages = [
{"role": "user", "content": "Berechne die Summe von 1234 und 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"
}
]} # Nur das tool_result, kein zusätzlicher Text
]
# Wenn Sie nach der Behebung des oben genannten Problems immer noch leere Antworten erhalten:
def handle_empty_response(client, messages):
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=messages
)
# Prüfen, ob die Antwort leer ist
if (response.stop_reason == "end_turn" and
not response.content):
# FALSCH: Nicht einfach mit der leeren Antwort wiederholen
# Das funktioniert nicht, weil Claude bereits entschieden hat, dass es fertig ist
# RICHTIG: Eine Fortsetzungsaufforderung in einer NEUEN Benutzernachricht hinzufügen
messages.append({"role": "user", "content": "Bitte fortfahren"})
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=messages
)
return response
Best Practices:
- Niemals Textblöcke unmittelbar nach Tool-Ergebnissen hinzufügen - Dies lehrt Claude zu erwarten, dass Benutzereingaben nach jeder Tool-Verwendung kommen
- Leere Antworten nicht ohne Änderung wiederholen - Das einfache Zurücksenden der leeren Antwort wird nicht helfen
- Fortsetzungsaufforderungen nur als letzten Ausweg verwenden - Nur wenn die oben genannten Korrekturen das Problem nicht lösen
max_tokens
Claude stoppte, weil es das in Ihrer Anfrage angegebene max_tokens-Limit erreicht hat.
# Anfrage mit begrenzten Token
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=10,
messages=[{"role": "user", "content": "Erkläre Quantenphysik"}]
)
if response.stop_reason == "max_tokens":
# Antwort wurde abgeschnitten
print("Antwort wurde am Token-Limit abgeschnitten")
# Erwägen Sie eine weitere Anfrage zum Fortfahren
stop_sequence
Claude stieß auf eine Ihrer benutzerdefinierten Stop-Sequenzen.
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
stop_sequences=["ENDE", "STOPP"],
messages=[{"role": "user", "content": "Generiere Text bis du ENDE sagst"}]
)
if response.stop_reason == "stop_sequence":
print(f"Gestoppt bei Sequenz: {response.stop_sequence}")
Claude ruft ein Tool auf und erwartet, dass Sie es ausführen.
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=[weather_tool],
messages=[{"role": "user", "content": "Wie ist das Wetter?"}]
)
if response.stop_reason == "tool_use":
# Tool extrahieren und ausführen
for content in response.content:
if content.type == "tool_use":
result = execute_tool(content.name, content.input)
# Ergebnis an Claude für finale Antwort zurückgeben
pause_turn
Wird mit Server-Tools wie Websuche verwendet, wenn Claude eine langwierige Operation pausieren muss.
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=[{"type": "web_search_20250305", "name": "web_search"}],
messages=[{"role": "user", "content": "Suche nach den neuesten KI-Nachrichten"}]
)
if response.stop_reason == "pause_turn":
# Unterhaltung fortsetzen
messages = [
{"role": "user", "content": original_query},
{"role": "assistant", "content": response.content}
]
continuation = client.messages.create(
model="claude-sonnet-4-5",
messages=messages,
tools=[{"type": "web_search_20250305", "name": "web_search"}]
)
refusal
Claude weigerte sich, eine Antwort aufgrund von Sicherheitsbedenken zu generieren.
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
messages=[{"role": "user", "content": "[Unsichere Anfrage]"}]
)
if response.stop_reason == "refusal":
# Claude lehnte eine Antwort ab
print("Claude konnte diese Anfrage nicht verarbeiten")
# Erwägen Sie eine Umformulierung oder Änderung der Anfrage
Wenn Sie häufig refusal Stop-Gründe bei der Verwendung von Claude Sonnet 4.5 oder Opus 4.1 antreffen, können Sie versuchen, Ihre API-Aufrufe zu aktualisieren, um Sonnet 4 (claude-sonnet-4-20250514) zu verwenden, das andere Nutzungsbeschränkungen hat.
model_context_window_exceeded
Claude stoppte, weil es das Kontextfenster-Limit des Modells erreicht hat. Dies ermöglicht es Ihnen, die maximal möglichen Token anzufordern, ohne die genaue Eingabegröße zu kennen.
# Anfrage mit maximalen Token, um so viel wie möglich zu erhalten
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=64000, # Maximale Ausgabe-Token des Modells
messages=[{"role": "user", "content": "Große Eingabe, die den größten Teil des Kontextfensters nutzt..."}]
)
if response.stop_reason == "model_context_window_exceeded":
# Antwort erreichte Kontextfenster-Limit vor max_tokens
print("Antwort erreichte das Kontextfenster-Limit des Modells")
# Die Antwort ist immer noch gültig, wurde aber durch das Kontextfenster begrenzt
Dieser Stop-Grund ist standardmäßig in Sonnet 4.5 und neueren Modellen verfügbar. Für frühere Modelle verwenden Sie den Beta-Header model-context-window-exceeded-2025-08-26, um dieses Verhalten zu aktivieren.
Best Practices für den Umgang mit Stop-Gründen
1. Immer stop_reason prüfen
Machen Sie es sich zur Gewohnheit, den stop_reason in Ihrer Antwortbehandlungslogik zu prüfen:
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 und andere Fälle behandeln
return response.content[0].text
2. Abgeschnittene Antworten elegant behandeln
Wenn eine Antwort aufgrund von Token-Limits oder Kontextfenster abgeschnitten wird:
def handle_truncated_response(response):
if response.stop_reason in ["max_tokens", "model_context_window_exceeded"]:
# Option 1: Benutzer über das spezifische Limit warnen
if response.stop_reason == "max_tokens":
message = "[Antwort aufgrund von max_tokens-Limit abgeschnitten]"
else:
message = "[Antwort aufgrund von Kontextfenster-Limit abgeschnitten]"
return f"{response.content[0].text}\n\n{message}"
# Option 2: Generierung fortsetzen
messages = [
{"role": "user", "content": original_prompt},
{"role": "assistant", "content": response.content[0].text}
]
continuation = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
messages=messages + [{"role": "user", "content": "Bitte fortfahren"}]
)
return response.content[0].text + continuation.content[0].text
3. Wiederholungslogik für pause_turn implementieren
Für Server-Tools, die pausieren können:
def handle_paused_conversation(initial_response, max_retries=3):
response = initial_response
messages = [{"role": "user", "content": original_query}]
for attempt in range(max_retries):
if response.stop_reason != "pause_turn":
break
messages.append({"role": "assistant", "content": response.content})
response = client.messages.create(
model="claude-sonnet-4-5",
messages=messages,
tools=original_tools
)
return response
Stop-Gründe vs. Fehler
Es ist wichtig, zwischen stop_reason-Werten und tatsächlichen Fehlern zu unterscheiden:
Stop-Gründe (erfolgreiche Antworten)
- Teil des Antwortkörpers
- Zeigen an, warum die Generierung normal gestoppt wurde
- Antwort enthält gültigen Inhalt
Fehler (fehlgeschlagene Anfragen)
- HTTP-Statuscodes 4xx oder 5xx
- Zeigen Ausfälle bei der Anfrageverarbeitung an
- Antwort enthält Fehlerdetails
try:
response = client.messages.create(...)
# Erfolgreiche Antwort mit stop_reason behandeln
if response.stop_reason == "max_tokens":
print("Antwort wurde abgeschnitten")
except anthropic.APIError as e:
# Tatsächliche Fehler behandeln
if e.status_code == 429:
print("Rate-Limit überschritten")
elif e.status_code == 500:
print("Server-Fehler")
Streaming-Überlegungen
Bei der Verwendung von Streaming ist stop_reason:
null im anfänglichen message_start-Event
- Bereitgestellt im
message_delta-Event
- Nicht in anderen Events bereitgestellt
with client.messages.stream(...) as stream:
for event in stream:
if event.type == "message_delta":
stop_reason = event.delta.stop_reason
if stop_reason:
print(f"Stream endete mit: {stop_reason}")
Häufige Muster
def complete_tool_workflow(client, user_query, tools):
messages = [{"role": "user", "content": user_query}]
while True:
response = client.messages.create(
model="claude-sonnet-4-5",
messages=messages,
tools=tools
)
if response.stop_reason == "tool_use":
# Tools ausführen und fortfahren
tool_results = execute_tools(response.content)
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
else:
# Finale Antwort
return response
Vollständige Antworten sicherstellen
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-sonnet-4-5",
messages=messages,
max_tokens=4096
)
full_response += response.content[0].text
if response.stop_reason != "max_tokens":
break
# Von dort fortfahren, wo aufgehört wurde
messages = [
{"role": "user", "content": prompt},
{"role": "assistant", "content": full_response},
{"role": "user", "content": "Bitte fahren Sie dort fort, wo Sie aufgehört haben."}
]
return full_response
Maximale Token erhalten ohne Eingabegröße zu kennen
Mit dem model_context_window_exceeded Stop-Grund können Sie die maximal möglichen Token anfordern, ohne die Eingabegröße zu berechnen:
def get_max_possible_tokens(client, prompt):
"""
So viele Token wie möglich innerhalb des Kontextfensters des Modells erhalten
ohne die Eingabe-Token-Anzahl berechnen zu müssen
"""
response = client.messages.create(
model="claude-sonnet-4-5",
messages=[{"role": "user", "content": prompt}],
max_tokens=64000 # Auf maximale Ausgabe-Token des Modells setzen
)
if response.stop_reason == "model_context_window_exceeded":
# Maximale mögliche Token bei gegebener Eingabegröße erhalten
print(f"{response.usage.output_tokens} Token generiert (Kontextlimit erreicht)")
elif response.stop_reason == "max_tokens":
# Genau die angeforderten Token erhalten
print(f"{response.usage.output_tokens} Token generiert (max_tokens erreicht)")
else:
# Natürliche Vervollständigung
print(f"{response.usage.output_tokens} Token generiert (natürliche Vervollständigung)")
return response.content[0].text
Durch die ordnungsgemäße Behandlung von stop_reason-Werten können Sie robustere Anwendungen erstellen, die verschiedene Antwortszenarien elegant handhaben und bessere Benutzererfahrungen bieten.