Claude Fable 5 et Claude Opus 5 incluent des classificateurs de sécurité qui peuvent décliner une requête. Lorsque cela se produit, vous recevez une réponse normale, et non une erreur, avec stop_reason: "refusal". Vous pouvez généralement toujours obtenir une réponse en envoyant la même requête à un autre modèle Claude. Cette page vous montre comment reconnaître un refus et comment configurer cette nouvelle tentative.
Lisez cette page lorsque vous développez sur Claude Fable 5 ou Claude Opus 5 et que vous souhaitez que les requêtes déclinées basculent automatiquement vers un autre modèle. Elle s'applique également lorsque vous venez de voir "refusal" dans une réponse et que vous voulez savoir quoi faire ensuite.
Pages connexes :
stop_reason.La configuration la plus simple, en version bêta sur l'API Claude : définissez fallbacks sur "default", et l'API réessaie une requête déclinée sur le modèle de « fallback » (repli) qu'Anthropic recommande pour sa catégorie de refus. Pour les catégories sans fallback recommandé, le refus est maintenu.
client = Anthropic()
response = client.beta.messages.create(
model="claude-fable-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello, Claude"}],
fallbacks="default",
betas=["server-side-fallback-2026-07-01"],
)
print(response.model)Les sections suivantes couvrent ce que contient une réponse de refus, quand utiliser le fallback côté serveur ou côté client, et comment chacun est facturé.
Un refus est une réponse HTTP 200 réussie avec 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
}
}L'objet stop_details explique le refus :
category : nomme le domaine de politique qui a déclenché le classificateur.explanation : une description lisible par un humain. Le texte n'est pas stable, affichez-le donc plutôt que de l'analyser.null lorsque le refus ne correspond à aucune catégorie nommée. Ce null est une valeur normale et permanente, pas un espace réservé.stop_details lui-même est null pour toute raison d'arrêt autre que refusal.category | Ce que cela signifie |
|---|---|
"cyber" | La requête pourrait permettre des dommages cyber, tels que le développement de logiciels malveillants ou d'exploits. Un travail de cybersécurité bénin peut également déclencher cette catégorie. |
"bio" | La requête pourrait permettre des dommages biologiques, tels que des méthodes de laboratoire dangereuses. Un travail bénéfique en sciences de la vie peut également déclencher cette catégorie. |
"frontier_llm" | La requête pourrait aider au développement de modèles d'IA concurrents, ce qui est restreint par les conditions commerciales d'Anthropic. Un travail bénin d'apprentissage automatique peut également déclencher cette catégorie. |
"reasoning_extraction" | La requête demande au modèle de reproduire son raisonnement interne dans le texte de la réponse. Pour obtenir le raisonnement sous une forme structurée à la place, utilisez la réflexion adaptative. |
"general_harms" | La requête pourrait être liée à un domaine déterminé comme nuisible. Un travail bénin peut parfois déclencher cette catégorie. |
Un refus peut survenir avant toute sortie, ou en cours de flux après une sortie partielle. Dans les deux cas, traitez toute sortie partielle comme incomplète et supprimez-la.
Comment les refus sont facturés : vous n'êtes pas facturé pour un refus qui survient avant toute sortie. content est vide, et les décomptes de tokens apparaissent dans usage mais ne sont pas facturés. La requête compte tout de même dans vos limites de débit. Un refus en cours de flux facture les tokens d'entrée et la sortie déjà diffusée aux tarifs normaux.
Il existe trois façons de réessayer une requête refusée sur un autre modèle. La bonne approche dépend de l'endroit où vous exécutez votre application et du niveau de contrôle dont vous avez besoin.
| Votre situation | Utilisez | Pourquoi |
|---|---|---|
| API Claude, configuration la plus simple | Fallback côté serveur | Une requête, une réponse. L'API gère la nouvelle tentative. |
| Toute plateforme, avec un SDK Anthropic | Le middleware du SDK | Configurez une fois sur le client. Les nouvelles tentatives se font automatiquement. |
| HTTP brut ou logique de nouvelle tentative personnalisée | Nouvelle tentative manuelle avec le crédit de fallback | Contrôle total. Le crédit de fallback réduit le coût. |
Le fallback côté serveur et le middleware du SDK appliquent le crédit de fallback pour vous. Vous n'avez besoin de la page Crédit de fallback que lorsque vous construisez la nouvelle tentative vous-même.
Le fallback côté serveur réessaie une requête refusée au sein d'un seul appel API. Dans le mode par défaut, lorsque le modèle principal décline et que la catégorie de refus a un fallback recommandé, l'API exécute la même requête sur le modèle qu'Anthropic recommande pour cette catégorie. Vous pouvez à la place nommer jusqu'à trois modèles de fallback de votre choix (ci-dessous). Dans les deux cas, vous recevez une seule réponse qui nomme le modèle qui a répondu, de sorte que votre utilisateur obtient une réponse en un seul aller-retour.
Le fallback côté serveur est en version bêta sur l'API Claude. Le paramètre fallbacks n'est pas pris en charge sur l'API Message Batches (un élément de lot qui l'inclut revient comme un résultat en erreur) et n'est pas disponible sur Amazon Bedrock, Google Cloud ou Microsoft Foundry. Sur ces plateformes, utilisez plutôt le fallback côté client avec le middleware du SDK.
Définissez le paramètre fallbacks sur la chaîne "default" et envoyez l'en-tête bêta server-side-fallback-2026-07-01. L'API applique alors le routage par défaut défini côté serveur pour le modèle demandé, qui sélectionne un modèle de fallback recommandé en fonction de la catégorie de refus signalée par le classificateur, de sorte que les requêtes refusées sont servies sans que vous ayez à maintenir une liste de modèles à mesure que les recommandations évoluent.
client = Anthropic()
response = client.beta.messages.create(
model="claude-fable-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello, Claude"}],
fallbacks="default",
betas=["server-side-fallback-2026-07-01"],
)
# Une entrée fallback_message dans usage.iterations signifie qu'un modèle de repli a été exécuté ;
# associez-la à stop_reason pour confirmer que le repli a servi la réponse.
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,
}
)
)Anthropic définit des garde-fous pour chaque modèle individuellement et pour chaque catégorie de politique, en fonction des capacités du modèle : selon la catégorie, une requête signalée peut basculer vers un modèle moins capable ou être déclinée. Le mode "default" encode ces recommandations par modèle et par catégorie pour vous, de sorte qu'une requête refusée est réessayée sur le modèle qu'Anthropic recommande pour cette catégorie. Les fallbacks sont visibles dans tous les cas : la réponse nomme le modèle qui l'a servie, et le bloc de contenu fallback marque le transfert.
Le routage est appliqué côté serveur et n'est pas publié par modèle sur l'API Models. Pour voir quel modèle a servi une requête refusée, vérifiez le champ model de premier niveau de la réponse et recherchez une entrée fallback_message dans usage.iterations, comme le font les exemples de cette page.
Seul un refus du classificateur de sécurité déclenche le fallback. Une limite de débit, une surcharge ou une erreur serveur sur le modèle demandé vous est renvoyée telle quelle.
L'en-tête bêta doit porter exactement la date 2026-07-01, qui prend en charge à la fois "default" et la forme de liste explicite ci-dessous, ou 2026-06-01, qui n'accepte que la forme de liste explicite. Avec toute autre valeur server-side-fallback-*, le paramètre fallbacks est rejeté avec une erreur 400. Si vous avez développé sur une version préliminaire antérieure de cette fonctionnalité, mettez à jour ensemble l'en-tête bêta ainsi que les formes de requête et de réponse vers celles de cette page.
Au lieu du routage par défaut, vous pouvez définir fallbacks sur une liste d'au maximum trois modèles. Lorsque le modèle demandé décline, l'API exécute le modèle suivant de la chaîne sur la même requête. Utilisez cette forme lorsque vous voulez contrôler exactement quels modèles servent les requêtes refusées, par exemple pour épingler un modèle que votre application a qualifié.
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-07-01"],
)
print(response.model)Quelques règles s'appliquent à la liste fallbacks :
allowed_fallback_models dans l'entrée du modèle sur l'API Models.model et peut remplacer max_tokens, thinking, output_config et speed pour cette tentative uniquement.La forme de liste explicite fonctionne également avec l'en-tête bêta server-side-fallback-2026-06-01 ; le mode "default" non.
La réponse a la même forme dans les deux modes : le modèle qui a servi le tour apparaît dans le champ model de premier niveau, un bloc de contenu fallback marque le transfert, et usage.iterations enregistre chaque tentative.
La réponse ressemble à n'importe quel autre message, avec deux ajouts :
model de premier niveau indique le modèle qui a produit le message renvoyé, qu'il s'agisse du modèle demandé ou d'un fallback.fallback marque chaque point de content où la sortie d'un modèle cède la place au suivant : {"type": "fallback", "from": {"model": ...}, "to": {"model": ...}}.
from.model reprend la chaîne de modèle que vous avez envoyée lorsque le saut qui décline est le modèle demandé.to.model est toujours l'ID résolu du modèle qui continue.Lors d'un refus avant toute sortie, le bloc fallback est le premier bloc de contenu. Par exemple, lorsque le routage par défaut sélectionne Claude Opus 4.8 pour la catégorie du refus :
{
"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
}
]
}
}Le tableau usage.iterations enregistre chaque tentative. Un modèle qui a décliné apparaît comme une entrée message ordinaire, et le modèle qui a servi le tour apparaît comme une entrée fallback_message. Si chaque modèle de la chaîne décline, la réponse est le refus du dernier modèle, avec une entrée message pour chaque saut précédent et une entrée fallback_message pour le dernier.
Au tour suivant, renvoyez le contenu de l'assistant tel que vous l'avez reçu. Après un fallback en cours de sortie, content peut inclure des types de blocs que le modèle qui a décliné a produits avant le transfert ; le tableau suivant indique lesquels conserver et lesquels supprimer lorsque vous renvoyez le tour.
| Type de bloc | Au tour suivant |
|---|---|
fallback | Conservez-le exactement là où il est apparu. L'API utilise sa position pour valider les blocs de réflexion qui l'entourent, donc une requête qui renvoie des blocs de réflexion des deux côtés de la frontière est rejetée si le bloc est omis ou déplacé. |
text | Conservez. |
Tout bloc après le dernier bloc fallback | Conservez. |
thinking, redacted_thinking ou connector_text avant le dernier bloc fallback | Supprimez. |
tool_use côté client avant le dernier bloc fallback | Supprimez. |
server_tool_use avant le dernier bloc fallback | Conservez lorsqu'il est associé à son résultat. Supprimez lorsqu'il n'a pas de résultat correspondant. |
Un bloc connector_text contient du texte de narration que certaines réponses utilisant des outils incluent entre les appels d'outils.
Sur une requête en streaming, la nouvelle tentative se produit sur le même flux, et rien de ce que vous avez déjà reçu n'est invalidé. Ce que vous voyez dépend du moment où le refus se produit.
Lorsque le refus se produit avant toute sortie :
message_start nomme le modèle de fallback, et le bloc fallback est le premier bloc de contenu.message_start attend le démarrage de la tentative de fallback, le temps jusqu'au premier octet inclut la tentative déclinée.Lorsque le refus se produit en cours de sortie :
fallback (une paire ordinaire content_block_start et content_block_stop sans deltas) marque la frontière.text de la sortie partielle sont transmis au modèle de fallback comme contexte ; les autres types de blocs restent dans content.message_start a déjà nommé le modèle demandé, lisez donc le modèle qui sert la requête à partir du to.model du bloc fallback et de l'entrée fallback_message dans usage.iterations du message_delta final.Sur une requête sans streaming, un refus en cours de sortie se comporte différemment : la réponse omet la sortie partielle du modèle qui a décliné, et le modèle de fallback répond depuis le début. Le résultat ressemble à un refus avant toute sortie, avec le bloc fallback en premier. La tentative déclinée et ses tokens de sortie apparaissent tout de même dans usage.iterations.
Refus pendant l'utilisation d'outils : le travail d'outil terminé ne bloque pas le fallback. Lorsqu'un refus se déclenche après que des outils serveur (par exemple, la recherche web ou l'exécution de code) ont fini de s'exécuter au sein d'une requête, la tentative de fallback se poursuit : les résultats d'outils terminés sont reportés, et le modèle de fallback peut continuer à invoquer des outils serveur. Le seul cas qui ne fait pas l'objet d'une nouvelle tentative est un refus en streaming qui se déclenche alors qu'un bloc d'utilisation d'outils de tout type (un outil client, un outil serveur ou un appel d'outil MCP) est encore ouvert sur le flux : ce refus est renvoyé directement, et si l'en-tête fallback-credit-2026-07-01 est défini, il porte tout de même un jeton de crédit échangeable en poursuivant la réponse partielle. Les requêtes sans streaming ne sont pas affectées ; l'API efface le travail partiel et réessaie avant de répondre.
Chaque SDK Anthropic inclut un middleware de fallback sur refus. Vous le configurez une fois sur le client avec votre liste de modèles de fallback. Les appels via client.beta.messages réessaient alors automatiquement les requêtes refusées, sur n'importe quelle plateforme. Le middleware envoie également l'en-tête bêta fallback-credit-2026-07-01 sur chaque requête qu'il gère, de sorte que les nouvelles tentatives sont retarifées sans configuration par requête.
Passez le middleware au constructeur du client, et partagez une seule instance BetaFallbackState entre les requêtes d'une conversation.
from anthropic import Anthropic, BetaFallbackState, BetaRefusalFallbackMiddleware
# En cas de refus, le middleware réessaie sur le modèle de repli indiqué et
# envoie automatiquement l'en-tête bêta fallback-credit sur chaque requête qu'il traite.
client = Anthropic(
middleware=[BetaRefusalFallbackMiddleware([{"model": "claude-opus-4-8"}])],
)
state = BetaFallbackState() # pins follow-ups to the model that accepted
# Streaming : en cas de refus, le middleware réessaie sur le modèle de repli et
# insère ses événements dans le flux ouvert.
with (
state,
client.beta.messages.stream(
max_tokens=1024,
model="claude-fable-5",
messages=[{"role": "user", "content": "Hello, Claude"}],
) as stream,
):
for text in stream.text_stream:
print(text, end="", flush=True)
final_message = stream.get_final_message()
print(f"\nserved by: {final_message.model}")
# Non-streaming : réutiliser l'état maintient la conversation épinglée.
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}")fallback qu'il a lui-même ajoutés.fallback à chaque frontière de modèle, comme les réponses de fallback côté serveur. Le middleware gère ces blocs pour vous lors des requêtes ultérieures.BetaFallbackState, de sorte que les requêtes de suivi qui partagent l'état restent épinglées à celui-ci plutôt que de redemander à un modèle qui a refusé.Le middleware et le paramètre fallbacks côté serveur font le même travail. Configurez l'un ou l'autre, jamais les deux sur la même requête. Pour envoyer une requête fallbacks côté serveur depuis une application qui installe le middleware, utilisez une instance de client distincte sans celui-ci.
Une requête refusée dans un Message Batch revient comme result.type: "succeeded" avec stop_reason: "refusal". Les résultats de lot portent le même objet stop_details que les réponses synchrones, vous pouvez donc détecter les refus via stop_reason ou stop_details.type. Une différence : les refus de lot n'émettent pas de crédits de fallback, donc stop_details sur un résultat de lot n'inclut jamais de fallback_credit_token.
Le fallback côté serveur n'est pas disponible pour les lots (une requête de lot qui inclut fallbacks produit un résultat en erreur par élément). Pour réessayer les éléments de lot refusés :
fallbacks ne se propage pas aux appels de modèle effectués depuis l'intérieur de l'exécution d'outils.fallback_message dans usage.iterations marque cette dernière), puis alertez sur l'écart entre les deux décomptes.stop_reason ou stop_details.type, pas sur content ni sur les champs internes de stop_details. L'objet stop_details est toujours présent lors d'un refus, mais ses champs category et explanation peuvent être null. Vérifiez directement que stop_reason est égal à "refusal".Évitez de payer deux fois le coût du cache de prompt lorsque vous construisez la nouvelle tentative vous-même.
Chaque valeur de stop_reason et comment la gérer.
Comment fonctionne le middleware du SDK, y compris l'assistant de fallback sur refus.
Migrez une application existante vers Claude Fable 5.
Was this page helpful?