Was this page helpful?
Claude Fable 5 enthält Sicherheits-Classifier, die eine Anfrage ablehnen können. Wenn das passiert, erhältst du eine normale Antwort, keinen Fehler, mit stop_reason: "refusal". In der Regel kannst du trotzdem eine Antwort bekommen, indem du dieselbe Anfrage an ein anderes Claude-Modell sendest. Diese Seite zeigt dir, wie du eine Ablehnung erkennst und wie du diesen Retry einrichtest.
Lies diese Seite, wenn du auf Claude Fable 5 aufbaust und möchtest, dass abgelehnte Anfragen automatisch an ein anderes Modell weitergereicht werden. Sie gilt auch, wenn du gerade "refusal" in einer Antwort gesehen hast und wissen möchtest, was als Nächstes zu tun ist.
Die vollständige Liste der stop_reason-Werte findest du unter Stop-Reasons und Fallback. Details dazu, wie abgelehnte Anfragen abgerechnet werden und wie du vermeidest, beim Retry doppelt für Prompt-Caching zu bezahlen, findest du unter Fallback-Credit. Der SDK-Helper, der all das kapselt, ist unter SDK-Middleware beschrieben. Ein durchgängiges Beispiel findest du im Fallback- und Billing-Cookbook.
Das einfachste Setup: Gib ein Fallback-Modell in der Anfrage an, und die API übernimmt den Retry.
await client.beta.messages.create({
model: "claude-fable-5",
max_tokens: 1024,
messages,
betas: ["server-side-fallback-2026-06-01"],
fallbacks: [{ model: "claude-opus-4-8" }]
});Die folgenden Abschnitte behandeln, was eine Ablehnungsantwort enthält, wann du serverseitigen oder clientseitigen Fallback verwenden solltest und wie beides abgerechnet wird.
Eine Ablehnung ist eine erfolgreiche HTTP-200-Antwort mit stop_reason: "refusal":
{
"id": "msg_01XFUDYJgAACzvnptvVoYEL",
"type": "message",
"role": "assistant",
"model": "claude-fable-5",
"content": [],
"stop_reason": "refusal",
"stop_details": {
"type": "refusal",
"category": "cyber",
"explanation": "This request was declined because it could enable cyber harm."
},
"usage": {
"input_tokens": 412,
"output_tokens": 0
}
}Das stop_details-Objekt erklärt die Ablehnung. Das Feld category benennt den Policy-Bereich, der den Classifier ausgelöst hat. Das Feld explanation ist eine menschenlesbare Beschreibung; der Text ist nicht stabil, also zeige ihn an, statt ihn zu parsen. Beide Felder sind null, wenn die Ablehnung keiner benannten Kategorie zugeordnet werden kann, und null ist ein normaler, dauerhafter Wert und kein Platzhalter. stop_details selbst ist null für jeden anderen Stop-Reason als refusal.
category | Bedeutung |
|---|---|
"cyber" | Die Anfrage könnte Cyber-Schaden ermöglichen, etwa Malware- oder Exploit-Entwicklung. Auch harmlose Cybersecurity-Arbeit kann diese Kategorie auslösen. |
"bio" | Die Anfrage könnte biologischen Schaden ermöglichen, etwa gefährliche Labormethoden. Auch nützliche Arbeit in den Biowissenschaften kann diese Kategorie auslösen. |
"reasoning_extraction" | Die Anfrage fordert das Modell auf, sein internes Reasoning im Antworttext wiederzugeben. Um Reasoning stattdessen in strukturierter Form zu erhalten, verwende Adaptive Thinking. |
Eine Ablehnung kann vor jeglicher Ausgabe eintreffen oder mitten im Stream nach teilweiser Ausgabe. In beiden Fällen solltest du jede Teilausgabe als unvollständig behandeln und verwerfen.
Wie Ablehnungen abgerechnet werden: Bei einer Ablehnung vor jeglicher Ausgabe bleibt content leer, und dir wird nichts berechnet (Token-Zahlen erscheinen in usage, werden aber nicht berechnet, und die Anfrage zählt nicht gegen Ratenlimits). Bei einer Ablehnung mitten im Stream werden die Input-Token und die bereits gestreamte Ausgabe zu normalen Preisen abgerechnet.
Es gibt drei Möglichkeiten, eine abgelehnte Anfrage auf einem anderen Modell erneut zu versuchen. Die richtige hängt davon ab, wo du läufst und wie viel Kontrolle du brauchst.
| Deine Situation | Verwende | Warum |
|---|---|---|
| Claude API oder Claude Platform auf AWS, einfachstes Setup | Serverseitiger Fallback | Eine Anfrage, eine Antwort. Die API übernimmt den Retry. |
| Jede Plattform, mit dem TypeScript-, Python-, Go-, Java- oder C#-SDK | Die SDK-Middleware | Einmal auf dem Client konfigurieren. Retries passieren automatisch. |
| Ruby, PHP, rohes HTTP oder eigene Retry-Logik | Manueller Retry mit Fallback-Credit | Volle Kontrolle. Fallback-Credit hält die Kosten niedrig. |
Serverseitiger Fallback und die SDK-Middleware wenden Fallback-Credit für dich an, du brauchst diese Seite also nur, wenn du den Retry selbst baust.
Serverseitiger Fallback wiederholt eine abgelehnte Anfrage innerhalb eines einzigen API-Aufrufs. Du gibst bis zu drei Fallback-Modelle an, und wenn Claude Fable 5 ablehnt, führt die API das nächste Modell in der Kette mit derselben Anfrage aus. Du erhältst eine einzige Antwort zurück, die das Modell nennt, das geantwortet hat, sodass dein Nutzer in einem Roundtrip eine Antwort bekommt.
Serverseitiger Fallback ist in der Beta auf der Claude API und Claude Platform auf AWS. Der fallbacks-Parameter wird von der Message Batches API abgelehnt und ist auf Amazon Bedrock, Vertex AI oder Microsoft Foundry nicht verfügbar. Verwende auf diesen Plattformen stattdessen die SDK-Middleware.
Gib die Fallback-Modelle im fallbacks-Parameter an und sende den Beta-Header server-side-fallback-2026-06-01.
Für die fallbacks-Liste gelten einige Regeln:
allowed_fallback_models im Eintrag des Modells in der Models API veröffentlicht.model und kann max_tokens und thinking nur für diesen Versuch überschreiben.Der Beta-Header muss exakt das Datum 2026-06-01 tragen. Unter jedem anderen server-side-fallback-*-Wert wird der fallbacks-Parameter mit einem 400-Fehler abgelehnt. Wenn du gegen eine frühere Preview dieses Features gebaut hast, aktualisiere den Beta-Header sowie die Request- und Response-Strukturen gemeinsam auf die auf dieser Seite beschriebenen.
Die Antwort sieht aus wie jede andere Nachricht, mit zwei Ergänzungen:
model gibt das Modell an, das die zurückgegebene Nachricht erzeugt hat, egal ob das das angeforderte Modell oder ein Fallback ist.fallback-Content-Block markiert jede Stelle in content, an der die Ausgabe eines Modells in die des nächsten übergeht: {"type": "fallback", "from": {"model": ...}, "to": {"model": ...}}. from.model gibt den Modell-String wieder, den du gesendet hast, wenn der ablehnende Schritt das angeforderte Modell ist. to.model ist immer die aufgelöste ID des Modells, das fortsetzt.Bei einer Ablehnung vor jeglicher Ausgabe ist der fallback-Block der erste Content-Block:
{
"id": "msg_01XFUDYJgAACzvnptvVoYEL",
"type": "message",
"role": "assistant",
"model": "claude-opus-4-8",
"content": [
{
"type": "fallback",
"from": { "model": "claude-fable-5" },
"to": { "model": "claude-opus-4-8" }
},
{ "type": "text", "text": "Hi! How can I help you today?" }
],
"stop_reason": "end_turn",
"stop_details": null,
"usage": {
"input_tokens": 412,
"output_tokens": 264,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 0,
"iterations": [
{
"type": "message",
"model": "claude-fable-5",
"input_tokens": 535,
"output_tokens": 0,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 0
},
{
"type": "fallback_message",
"model": "claude-opus-4-8",
"input_tokens": 412,
"output_tokens": 264,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 0
}
]
}
}Das Array usage.iterations protokolliert jeden Versuch. Ein Modell, das abgelehnt hat, erscheint als gewöhnlicher message-Eintrag, und das Modell, das den Turn bedient hat, erscheint als fallback_message-Eintrag. Wenn jedes Modell in der Kette ablehnt, ist die Antwort die Ablehnung des letzten Modells, mit einem message-Eintrag für jeden früheren Schritt und einem fallback_message-Eintrag für den letzten.
Sende beim nächsten Turn den Assistant-Content so zurück, wie du ihn erhalten hast. Nach einem Fallback mitten in der Ausgabe kann content Block-Typen enthalten, die das ablehnende Modell vor der Übergabe erzeugt hat; die folgende Tabelle zeigt, welche du behalten und welche du verwerfen solltest, wenn du den Turn zurückspiegelst.
| Block-Typ | Beim nächsten Turn |
|---|---|
fallback | Behalte ihn genau dort, wo er erschienen ist. Die API nutzt seine Position, um die Thinking-Blöcke um ihn herum zu validieren, sodass eine Anfrage, die Thinking-Blöcke von beiden Seiten der Grenze zurückspiegelt, abgelehnt wird, wenn der Block weggelassen oder verschoben wird. |
text | Behalten. |
Jeder Block nach dem letzten fallback-Block | Behalten. |
thinking, redacted_thinking oder connector_text vor dem letzten fallback-Block | Verwerfen. |
Clientseitiges tool_use vor dem letzten fallback-Block | Verwerfen. |
| vor dem letzten -Block |
Ein connector_text-Block trägt Erzähltext, den manche Tool-nutzenden Antworten zwischen Tool-Aufrufen enthalten.
Bei einer Streaming-Anfrage passiert der Retry auf demselben Stream, und nichts, was du bereits empfangen hast, wird ungültig. Wenn die Ablehnung vor jeglicher Ausgabe passiert, benennt message_start das Fallback-Modell und der fallback-Block ist der erste Content-Block; da message_start wartet, bis der Fallback-Versuch startet, schließt die Zeit bis zum ersten Byte den abgelehnten Versuch ein. Wenn die Ablehnung mitten in der Ausgabe passiert, wird der offene Content-Block geschlossen, der fallback-Block (ein gewöhnliches content_block_start- und content_block_stop-Paar ohne Deltas) markiert die Grenze, und das Fallback-Modell setzt ab der Teilausgabe fort. Nur die text-Blöcke der Teilausgabe werden dem Fallback-Modell als Kontext übergeben; andere Block-Typen bleiben in content. Im Fall mitten in der Ausgabe hat message_start bereits das angeforderte Modell benannt, also lies das bedienende Modell aus dem to.model des fallback-Blocks und aus dem fallback_message-Eintrag in usage.iterations des finalen message_delta.
Bei einer Nicht-Streaming-Anfrage verhält sich eine Ablehnung mitten in der Ausgabe anders: Die Antwort lässt die Teilausgabe des abgelehnten Modells weg, und das Fallback-Modell antwortet von Grund auf neu. Das Ergebnis sieht aus wie eine Ablehnung vor jeglicher Ausgabe, mit dem fallback-Block zuerst. Der abgelehnte Versuch und seine Output-Token erscheinen trotzdem in usage.iterations.
Wenn eine Ablehnung ausgelöst wird, nachdem Server-Tools (zum Beispiel Websuche oder Code-Ausführung) innerhalb einer Anfrage bereits ausgeführt wurden, gibt die API die Ablehnung zurück, statt zu einem Fallback-Modell weiterzugehen. Wenn der Header fallback-credit-2026-06-01 ebenfalls gesetzt ist, trägt diese Ablehnung ein Credit-Token, das durch Fortsetzen der Teilantwort eingelöst werden kann, sodass die abgeschlossene Tool-Arbeit nicht verloren geht. Das gilt nur für Server-Tools, die innerhalb einer einzelnen Anfrage iterieren; Konversationen, die clientseitige Tools verwenden, fallen normal zurück.
Die TypeScript-, Python-, Go-, Java- und C#-SDKs enthalten eine Refusal-Fallback-Middleware. Du konfigurierst sie einmal auf dem Client mit deiner Liste von Fallback-Modellen. Aufrufe über client.beta.messages wiederholen dann abgelehnte Anfragen automatisch, auf jeder Plattform. Die Middleware sendet außerdem den Beta-Header fallback-credit-2026-06-01 bei jeder Anfrage, die sie verarbeitet, sodass Retries ohne anfrageweise Einrichtung neu bepreist werden.
Der Refusal-Fallback-Middleware-Helper ist in den Ruby- und PHP-SDKs noch nicht verfügbar. Implementiere in diesen SDKs das Detect-and-Retry-Muster direkt.
Übergib die Middleware an den Client-Konstruktor und teile eine BetaFallbackState-Instanz über die Anfragen einer Konversation hinweg.
fallback-Content-Block, genau wie serverseitige Fallback-Antworten. Die Middleware verwaltet diese Blöcke für dich bei späteren Anfragen.BetaFallbackState aufgezeichnet, sodass Folgeanfragen, die den State teilen, daran gepinnt bleiben, statt ein Modell erneut zu fragen, das abgelehnt hat.Die Middleware und der serverseitige fallbacks-Parameter erledigen dieselbe Aufgabe. Konfiguriere das eine oder das andere, nie beides in derselben Anfrage. Um eine serverseitige fallbacks-Anfrage aus einer Anwendung zu senden, die die Middleware installiert, verwende eine separate Client-Instanz ohne sie.
Eine abgelehnte Anfrage in einem Message Batch kommt als result.type: "succeeded" mit stop_reason: "refusal" zurück. Das Feld stop_details kann bei Batch-Ergebnissen null sein, also erkenne Ablehnungen, indem du stop_reason direkt prüfst.
Serverseitiger Fallback ist für Batches nicht verfügbar (eine Batch-Anfrage, die fallbacks enthält, erzeugt ein fehlerhaftes Ergebnis pro Item). Um abgelehnte Batch-Items erneut zu versuchen:
fallbacks-Parameter propagiert nicht in Modellaufrufe, die innerhalb der Tool-Ausführung gemacht werden.fallback_message-Eintrag in markiert Letztere), dann alarmiere auf die Lücke zwischen den beiden Zählern.client = Anthropic()
response = client.beta.messages.create(
model="claude-fable-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello, Claude"}],
fallbacks=[{"model": "claude-opus-4-8"}],
betas=["server-side-fallback-2026-06-01"],
)
# Ein fallback_message-Eintrag in usage.iterations bedeutet, dass ein Fallback-Modell lief;
# kombiniere ihn mit stop_reason, um zu bestätigen, dass der Fallback die Antwort lieferte.
fallback_ran = any(
iteration.type == "fallback_message"
for iteration in response.usage.iterations or []
)
served_by_fallback = fallback_ran and response.stop_reason != "refusal"
print(
json.dumps(
{
"stop_reason": response.stop_reason,
"model": response.model,
"served_by_fallback": served_by_fallback,
}
)
)server_tool_usefallback| Behalten, wenn es mit seinem Ergebnis gepaart ist. Verwerfen, wenn es kein passendes Ergebnis hat. |
# Bei einer Ablehnung wiederholt die Middleware den Versuch mit dem angegebenen Fallback-Modell und
# sendet automatisch den Fallback-Credit-Beta-Header bei jeder Anfrage, die sie verarbeitet.
client = Anthropic(
middleware=[BetaRefusalFallbackMiddleware([{"model": "claude-opus-4-8"}])],
)
state = BetaFallbackState() # pins follow-ups to the model that accepted
# Streaming: Bei einer Ablehnung wiederholt die Middleware den Versuch mit dem Fallback-Modell und
# fügt dessen Events in den offenen Stream ein.
with (
state,
client.beta.messages.stream(
max_tokens=1024,
model="claude-fable-5",
messages=[{"role": "user", "content": "Hello, Claude"}],
) as stream,
):
for event in stream:
if event.type == "text":
print(event.text, end="", flush=True)
final_message = stream.get_final_message()
print(f"\nserved by: {final_message.model}")
# Nicht-Streaming: Die Wiederverwendung des State hält die Konversation fixiert.
with state:
message = client.beta.messages.create(
max_tokens=1024,
model="claude-fable-5",
messages=[{"role": "user", "content": "Hello, Claude"}],
)
print(f"served by: {message.model}")usage.iterationsstop_reason, nicht auf stop_details oder content. stop_details ist informativ und kann bei einer Ablehnung null sein. Prüfe direkt, ob stop_reason gleich "refusal" ist.Wie SDK-Middleware funktioniert, einschließlich des Refusal-Fallback-Helpers.