Claude Fable 5 inclut des classificateurs de sécurité qui peuvent refuser 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 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.
Consultez cette page lorsque vous développez avec Claude Fable 5 et souhaitez que les requêtes refusées soient automatiquement transmises à un autre modèle. Elle s'applique également lorsque vous venez de voir "refusal" dans une réponse et souhaitez savoir quoi faire ensuite.
Pages connexes :
stop_reason.La configuration la plus simple : nommez un modèle de repli dans la requête, et l'API gère la nouvelle tentative.
client = Anthropic()
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"],
)Les sections ci-dessous couvrent le contenu d'une réponse de refus, quand utiliser le repli 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 pas à une 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 | Signification |
|---|---|
"cyber" | La requête pourrait permettre des préjudices cybernétiques, tels que le développement de logiciels malveillants ou d'exploits. Des travaux de cybersécurité bénins peuvent également déclencher cette catégorie. |
"bio" | La requête pourrait permettre des préjudices biologiques, tels que des méthodes de laboratoire dangereuses. Des travaux bénéfiques en sciences de la vie peuvent é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. Des travaux bénins d'apprentissage automatique peuvent é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, utilisez plutôt la réflexion adaptative. |
Un refus peut arriver avant toute sortie, ou en cours de streaming après une sortie partielle. Dans les deux cas, considérez toute sortie partielle comme incomplète et supprimez-la.
Comment les refus sont facturés : Vous n'êtes pas facturé pour un refus qui arrive avant toute sortie. content est vide, les comptages de tokens apparaissent dans usage mais ne sont pas facturés, et la requête ne compte pas dans les limites de débit. Un refus en cours de streaming 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 votre environnement d'exécution et du niveau de contrôle dont vous avez besoin.
| Votre situation | Utilisez | Pourquoi |
|---|---|---|
| API Claude ou Claude Platform sur AWS, configuration la plus simple | Repli côté serveur | Une requête, une réponse. L'API gère la nouvelle tentative. |
| Toute plateforme, avec le SDK TypeScript, Python, Go, Java ou C# | Le middleware SDK | Configurez une fois sur le client. Les nouvelles tentatives se font automatiquement. |
| Ruby, PHP, HTTP brut ou logique de nouvelle tentative personnalisée | Nouvelle tentative manuelle avec crédit de repli | Contrôle total. Le crédit de repli réduit le coût. |
Le repli côté serveur et le middleware SDK appliquent le crédit de repli pour vous. Vous n'avez besoin de la page Crédit de repli que lorsque vous construisez vous-même la nouvelle tentative.
Le repli côté serveur réessaie une requête refusée au sein d'un seul appel API. Vous nommez jusqu'à trois modèles de repli, et lorsque Claude Fable 5 refuse, l'API exécute le modèle suivant de la chaîne sur la même requête. Vous recevez une seule réponse qui nomme le modèle ayant répondu, de sorte que votre utilisateur obtient une réponse en un seul aller-retour.
Le repli côté serveur est en version bêta sur l'API Claude et Claude Platform sur AWS. Le paramètre fallbacks est rejeté sur l'API Message Batches et n'est pas disponible sur Amazon Bedrock, Google Cloud ou Microsoft Foundry. Sur ces plateformes, utilisez plutôt le middleware SDK.
Nommez les modèles de repli dans le paramètre fallbacks et envoyez l'en-tête bêta server-side-fallback-2026-06-01.
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"],
)
# Une entrée fallback_message dans usage.iterations indique qu'un modèle de repli a été exécuté ;
# associez-la à stop_reason pour confirmer que le modèle de 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,
}
)
)Quelques règles s'appliquent à la liste fallbacks :
allowed_fallback_models dans l'entrée du modèle de l'API Models.model et peut remplacer max_tokens et thinking pour cette tentative uniquement.L'en-tête bêta doit porter exactement la date 2026-06-01. Avec toute autre valeur server-side-fallback-*, le paramètre fallbacks est rejeté avec une erreur 400. Si vous avez développé avec une version préliminaire antérieure de cette fonctionnalité, mettez à jour ensemble l'en-tête bêta ainsi que les formats de requête et de réponse vers ceux de cette page.
La réponse ressemble à tout autre message, avec deux ajouts :
model de niveau supérieur indique le modèle qui a produit le message renvoyé, qu'il s'agisse du modèle demandé ou d'un modèle de repli.fallback marque chaque point dans 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 l'étape qui refuse 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 :
{
"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 refusé 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 tous les modèles de la chaîne refusent, la réponse est le refus du dernier modèle, avec une entrée message pour chaque étape précédente et une entrée fallback_message pour la dernière.
Au tour suivant, renvoyez le contenu de l'assistant tel que vous l'avez reçu. Après un repli en cours de sortie, content peut inclure des types de blocs que le modèle ayant refusé a produits avant le transfert ; le tableau ci-dessous 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 limite 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 repli, et le bloc fallback est le premier bloc de contenu.message_start attend que la tentative de repli démarre, le délai avant le premier octet inclut la tentative refusé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 limite.text de la sortie partielle sont transmis au modèle de repli 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 servant à partir du to.model du bloc fallback et de l'entrée fallback_message dans le 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 refusé, et le modèle de repli répond à partir de zéro. Le résultat ressemble à un refus avant toute sortie, avec le bloc fallback en premier. La tentative refusée et ses tokens de sortie apparaissent toujours dans usage.iterations.
Refus après l'exécution d'outils serveur : lorsqu'un refus se déclenche après que des outils serveur (par exemple, la recherche web ou l'exécution de code) ont déjà été exécutés au sein d'une requête, l'API renvoie le refus au lieu de passer à un modèle de repli. Si l'en-tête fallback-credit-2026-06-01 est également défini, ce refus porte un jeton de crédit utilisable en continuant la réponse partielle, de sorte que le travail d'outil terminé n'est pas perdu. Cela s'applique uniquement aux outils serveur itérant au sein d'une seule requête. Les conversations qui utilisent des outils côté client se replient normalement.
Les SDK TypeScript, Python, Go, Java et C# incluent un middleware de repli sur refus. Vous le configurez une fois sur le client avec votre liste de modèles de repli. 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-06-01 sur chaque requête qu'il gère, de sorte que les nouvelles tentatives sont retarifées sans configuration par requête.
L'utilitaire middleware de repli sur refus n'est pas encore disponible dans les SDK Ruby et PHP. Sur ces SDK, implémentez directement le modèle de détection et nouvelle tentative.
Passez le middleware au constructeur du client, et partagez une instance BetaFallbackState entre les requêtes d'une conversation.
# En cas de refus, le middleware réessaie avec le modèle de repli indiqué et
# envoie automatiquement l'en-tête bêta de crédit de repli sur chaque requête traitée.
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 avec 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 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}")
# Sans 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 à chaque limite de modèle, comme les réponses de repli 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 avec result.type: "succeeded" et stop_reason: "refusal". Le champ stop_details peut être null sur les résultats de lot, détectez donc les refus en vérifiant directement stop_reason.
Le repli 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 dans les 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 comptages.stop_reason, pas sur stop_details ou content. stop_details est informatif et peut être null sur un refus. Vérifiez directement que stop_reason est égal à "refusal".Évitez de payer deux fois le coût du cache de prompt lorsque vous construisez vous-même la nouvelle tentative.
Chaque valeur de stop_reason et comment la gérer.
Comment fonctionne le middleware SDK, y compris l'utilitaire de repli sur refus.
Migrez une application existante vers Claude Fable 5.
Was this page helpful?