Rechazos y fallback
Cómo los modelos Claude Fable y Claude Opus devuelven rechazos del clasificador y cómo reintentar las solicitudes rechazadas en un modelo de fallback.
Claude Fable 5.1, Claude Fable 5 y Claude Opus 5 incluyen clasificadores de seguridad que pueden declinar una solicitud. Cuando eso sucede, recibes una respuesta normal, no un error, con stop_reason: "refusal". Su stop_details.category nombra el área de política (consulta Cómo se ve un rechazo). Por lo general, aún puedes obtener una respuesta enviando la misma solicitud a otro modelo Claude. Esta página te muestra cómo reconocer un "refusal" (rechazo) y cómo configurar ese reintento mediante "fallback" (respaldo).
Lee esta página cuando construyas sobre cualquiera de estos modelos y quieras que las solicitudes declinadas pasen automáticamente a otro modelo. También aplica cuando has visto "refusal" en una respuesta y quieres saber qué hacer a continuación.
Páginas relacionadas:
- Motivos de parada y fallback: la lista completa de valores de
stop_reason. - Crédito de fallback: cómo evitar pagar dos veces el costo de la caché de prompts cuando construyes el reintento tú mismo.
- Middleware del SDK: el asistente del SDK que envuelve todo esto.
- Cookbook de fallback y facturación: un ejemplo completo desarrollado de principio a fin.
La configuración más simple, en beta en la Claude API: establece fallbacks en "default", y la API reintenta una solicitud declinada en el modelo de fallback que Anthropic recomienda para su categoría de rechazo. Para las categorías sin un fallback recomendado, el rechazo se mantiene.
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)Las siguientes secciones cubren qué contiene una respuesta de rechazo, cuándo usar fallback del lado del servidor o del lado del cliente, y cómo se factura cada uno.
Cómo se ve un rechazo
Un rechazo es una respuesta HTTP 200 exitosa con 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
}
}El objeto stop_details explica la declinación:
category: nombra el área de política que activó el clasificador.explanation: una descripción legible para humanos. El texto no es estable, así que muéstralo en lugar de analizarlo.recommended_model: presente solo en solicitudes que establecenfallbacks(fallback del lado del servidor, beta). Nombra un modelo para reintentar directamente cuando la API omitió el intento de fallback (por ejemplo, el modelo de fallback alcanzó su límite de velocidad), y esnullen caso contrario. Es una sugerencia, no una garantía.categoryyexplanationson ambosnullcuando el rechazo no corresponde a una categoría con nombre. Esenulles un valor normal y permanente, no un marcador de posición.stop_detailsen sí esnullpara todos los motivos de parada distintos derefusal.
category | Qué significa |
|---|---|
"cyber" | La solicitud podría facilitar daño cibernético, como el desarrollo de malware o exploits. El trabajo benigno de ciberseguridad también puede activar esta categoría. |
"bio" | La solicitud podría facilitar daño biológico, como métodos de laboratorio peligrosos. El trabajo beneficioso en ciencias de la vida también puede activar esta categoría. |
"frontier_llm" | La solicitud podría ayudar al desarrollo de modelos de IA competidores, lo cual está restringido bajo los términos comerciales de Anthropic. El trabajo benigno de aprendizaje automático también puede activar esta categoría. |
"reasoning_extraction" | La solicitud pide al modelo que reproduzca su razonamiento interno en el texto de la respuesta. Para obtener el razonamiento en una forma estructurada, usa el pensamiento adaptativo. |
"general_harms" | La solicitud cae dentro de un área de la política de uso fuera de las cuatro categorías con nombre. El trabajo benigno también puede activar esta categoría. |
Un rechazo puede llegar antes de cualquier salida, o a mitad del stream después de una salida parcial. En cualquier caso, trata cualquier salida parcial como incompleta y descártala.
Elegir un enfoque de fallback
Hay tres formas de reintentar una solicitud rechazada en otro modelo. La correcta depende de dónde estés ejecutando y cuánto control necesites.
| Tu situación | Usa | Por qué |
|---|---|---|
| Claude API, configuración más simple | Fallback del lado del servidor | Una solicitud, una respuesta. La API maneja el reintento. |
| Cualquier plataforma, usando un SDK de Anthropic | El middleware del SDK | Configúralo una vez en el cliente. Los reintentos ocurren automáticamente. |
| HTTP directo o lógica de reintento personalizada | Un reintento manual con crédito de fallback | Control total. El crédito de fallback mantiene bajo el costo. |
El fallback del lado del servidor y el middleware del SDK aplican el crédito de fallback por ti. Solo necesitas la página de Crédito de fallback cuando construyes el reintento tú mismo.
Fallback del lado del servidor
El fallback del lado del servidor reintenta una solicitud rechazada dentro de una sola llamada a la API. En el modo predeterminado, cuando el modelo principal declina y la categoría de rechazo tiene un fallback recomendado, la API ejecuta la misma solicitud en el modelo que Anthropic recomienda para esa categoría. En su lugar, puedes nombrar hasta tres modelos de fallback propios. De cualquier forma, recibes una sola respuesta que nombra el modelo que respondió, de modo que tu usuario obtiene una respuesta en un solo viaje de ida y vuelta.
Realizar la solicitud
Establece el parámetro fallbacks en la cadena "default" y envía el encabezado beta server-side-fallback-2026-07-01. La API entonces aplica el enrutamiento predeterminado definido por el servidor para el modelo solicitado, que selecciona un modelo de fallback recomendado según la categoría de rechazo que reporta el clasificador, de modo que las solicitudes rechazadas se atienden sin que tengas que mantener una lista de modelos a medida que cambian las recomendaciones.
El enrutamiento predeterminado nunca provoca el rechazo anticipado por imagen sobredimensionada para modelos que no elegiste: un modelo enrutado que redimensionaría una imagen marcada con "oversized_image": "error" se elimina del enrutamiento en su lugar, de modo que una imagen marcada nunca se sirve redimensionada.
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"],
)
# Una entrada fallback_message en usage.iterations indica que se ejecutó un modelo de respaldo;
# combínala con stop_reason para confirmar que el respaldo sirvió la respuesta.
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 establece salvaguardas para cada modelo individualmente y para cada categoría de política, de acuerdo con la capacidad del modelo: dependiendo de la categoría, una solicitud marcada puede recurrir a un modelo menos capaz o ser declinada. El modo "default" codifica por ti estas recomendaciones por modelo y por categoría, de modo que una solicitud rechazada se reintenta en el modelo que Anthropic recomienda para esa categoría. Los fallbacks son visibles de cualquier forma: la respuesta nombra el modelo que la atendió, y el bloque de contenido fallback marca el traspaso.
El enrutamiento se aplica del lado del servidor y no se publica por modelo en la Models API. Para ver qué modelo atendió una solicitud rechazada, revisa el campo model de nivel superior de la respuesta y busca una entrada fallback_message en usage.iterations, como lo hacen los ejemplos de esta página.
Solo una declinación del clasificador de seguridad activa el fallback. Un límite de velocidad, una sobrecarga o un error del servidor en el modelo solicitado se te devuelve tal cual.
Nombrar tus propios modelos de fallback
En lugar del enrutamiento predeterminado, puedes establecer fallbacks en una lista de hasta tres modelos. Cuando el modelo solicitado declina, la API ejecuta el siguiente modelo de la cadena con la misma solicitud. Usa esta forma cuando quieras controlar exactamente qué modelos atienden las solicitudes rechazadas, como fijar un modelo que tu aplicación ha calificado.
Los modelos de fallback nombrados cuentan para la verificación de imagen sobredimensionada: una solicitud cuyo bloque de imagen establece "oversized_image": "error" se verifica de antemano contra el modelo solicitado y cada fallback nombrado, se rechaza si cualquiera de ellos redimensionaría esa imagen, y el objetivo de reescalado reportado en el rechazo se ajusta a todos ellos.
Las líneas resaltadas son la única diferencia con respecto a la solicitud de enrutamiento predeterminado.
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)Algunas reglas aplican a la lista fallbacks:
- Las entradas se prueban en orden. Cada una debe ser distinta de las demás entradas y del modelo solicitado.
- Cada entrada debe ser uno de los destinos permitidos del modelo solicitado. Con el encabezado beta establecido, esa lista se publica como
allowed_fallback_modelsen la entrada del modelo en la Models API. - Cada entrada nombra un
modely puede sobrescribirmax_tokens,thinking,output_configyspeedsolo para ese intento. - La solicitud debe ser válida como solicitud directa a cada modelo nombrado. Si un modelo de fallback no admite una función que la solicitud usa, la API rechaza la solicitud de antemano.
- Al igual que en el modo predeterminado, solo una declinación del clasificador de seguridad activa el fallback. Un límite de velocidad, una sobrecarga o un error del servidor en el modelo solicitado se te devuelve tal cual.
- Si un modelo de fallback alcanzó su límite de velocidad o está sobrecargado, el intento de fallback no se realiza y en su lugar se devuelve el rechazo precedente. El
stop_details.recommended_modeldel rechazo entonces nombra un modelo para reintentar directamente. Dimensiona los límites de velocidad del modelo de fallback para el volumen de rechazos que esperas, o los fallbacks se degradan a rechazos bajo carga.
La respuesta tiene la misma forma en ambos modos: el modelo que atendió el turno aparece en el campo model de nivel superior, un bloque de contenido fallback marca el traspaso, y usage.iterations registra cada intento.
Qué contiene la respuesta
La respuesta se ve como cualquier otro mensaje, con dos adiciones:
- El campo
modelde nivel superior reporta el modelo que produjo el mensaje devuelto, ya sea el modelo solicitado o un fallback. - Un bloque de contenido
fallbackmarca cada punto encontentdonde la salida de un modelo da paso al siguiente:{"type": "fallback", "from": {"model": ...}, "to": {"model": ...}}.from.modelrepite la cadena de modelo que enviaste cuando el salto que declina es el modelo solicitado.to.modeles siempre el ID resuelto del modelo que continúa.
En un rechazo antes de cualquier salida, el bloque fallback es el primer bloque de contenido. Por ejemplo, cuando el enrutamiento predeterminado selecciona Claude Opus 4.8 para la categoría del rechazo:
{
"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
}
]
}
}El arreglo usage.iterations registra cada intento. Un modelo que declinó aparece como una entrada message ordinaria, y el modelo que atendió el turno aparece como una entrada fallback_message. Si todos los modelos de la cadena declinan, la respuesta es el rechazo del último modelo, con una entrada message por cada salto anterior y una entrada fallback_message para el último.
El enrutamiento persistente puede enviar un turno posterior directamente al modelo de fallback. Dicho turno no lleva ningún bloque de contenido fallback, porque ningún modelo declinó ese turno. Identifícalo por la entrada fallback_message en usage.iterations, la ausencia de una entrada message para el modelo solicitado, y el campo model de la respuesta.
Continuar la conversación
En el siguiente turno, envía de vuelta el contenido del asistente tal como lo recibiste. Después de un fallback a mitad de la salida, content puede incluir tipos de bloque que el modelo que declinó produjo antes del traspaso. La siguiente tabla cubre cuáles conservar y cuáles descartar cuando repites el turno.
| Tipo de bloque | En el siguiente turno |
|---|---|
fallback | Consérvalo exactamente donde apareció. La API usa su posición para validar los bloques de pensamiento a su alrededor, por lo que una solicitud que repite bloques de pensamiento de ambos lados del límite se rechaza si el bloque se omite o se mueve. |
text | Conservar. |
Cualquier bloque después del bloque fallback final | Conservar. |
thinking, redacted_thinking o connector_text antes del bloque fallback final | Descartar. |
tool_use del lado del cliente antes del bloque fallback final | Descartar. |
server_tool_use antes del bloque fallback final | Conservar cuando está emparejado con su resultado. Descartar cuando no tiene un resultado correspondiente. |
Streaming
En una solicitud con streaming, el reintento ocurre en el mismo stream, y nada de lo que ya recibiste se invalida. Lo que ves depende de cuándo ocurre la declinación.
Cuando la declinación ocurre antes de cualquier salida:
message_startnombra el modelo de fallback, y el bloquefallbackes el primer bloque de contenido.- Debido a que
message_startespera a que comience el intento de fallback, el tiempo hasta el primer byte incluye el intento declinado.
Cuando la declinación ocurre a mitad de la salida:
- El bloque de contenido abierto se cierra, y el bloque
fallback(un par ordinario decontent_block_startycontent_block_stopsin deltas) marca el límite. - El modelo de fallback continúa desde la salida parcial. Solo los bloques
textde la salida parcial se pasan al modelo de fallback como contexto. Los demás tipos de bloque permanecen encontent. message_startya nombró el modelo solicitado, así que lee el modelo que atiende desde elto.modeldel bloquefallbacky desde la entradafallback_messageen elusage.iterationsdelmessage_deltafinal.
Respuestas sin streaming
En una solicitud sin streaming, una declinación a mitad de la salida se comporta de manera diferente: la respuesta omite la salida parcial del modelo declinado, y el modelo de fallback responde desde cero. El resultado se ve como una declinación antes de cualquier salida, con el bloque fallback primero. El intento declinado y sus tokens de salida aún aparecen en usage.iterations.
Facturación y límites de velocidad
Un intento que declinó antes de producir cualquier salida no se factura: sus tokens se reportan en su entrada de usage.iterations pero no se cobran. Cada intento que produjo salida, incluido uno que declinó a mitad de su respuesta, se factura por separado a las tarifas del modelo que lo ejecutó. El arreglo usage.iterations es el registro por intento de lo que se te factura. Los conteos de usage de nivel superior describen solo el intento que produjo el mensaje devuelto. Los tokens de diferentes modelos nunca se suman en un solo campo.
Cada intento que se ejecuta, incluido uno que declinó, cuenta contra los límites de velocidad de su propio modelo.
Enrutamiento persistente
Después de que una conversación recurre al fallback, la API registra qué modelo la atendió. Las solicitudes posteriores de esa conversación que incluyen fallbacks van directamente a ese modelo de fallback, sin ejecutar el modelo solicitado. Este "sticky routing" (enrutamiento persistente) evita pagar por un intento que previsiblemente sería declinado de nuevo en cada turno.
Algunas propiedades de la decisión de enrutamiento:
- Se conserva durante aproximadamente 1 hora y está limitada a tu organización.
- Se almacena como un hash de contenido del prefijo de la conversación más el modelo que la atendió. El contenido del mensaje en sí no se almacena.
- Es de mejor esfuerzo, por lo que tu código debe manejar que el modelo solicitado se vuelva a probar en cualquier momento.
El enrutamiento persistente aplica tanto a solicitudes con streaming como sin streaming. En una solicitud con streaming, la decisión de enrutamiento se toma antes de que se abra el stream, por lo que el campo model del evento message_start ya lleva el ID del modelo de fallback.
Fallback del lado del cliente con el middleware del SDK
Cada SDK de Anthropic incluye un middleware de fallback ante rechazos. Lo configuras una vez en el cliente con tu lista de modelos de fallback. Las llamadas a través de client.beta.messages entonces reintentan automáticamente las solicitudes rechazadas, en cualquier plataforma. El middleware también envía el encabezado beta fallback-credit-2026-07-01 en cada solicitud que maneja, de modo que los reintentos se reajustan de precio sin configuración por solicitud.
Configurarlo
Pasa el middleware al constructor del cliente, y comparte una instancia de BetaFallbackState entre las solicitudes de una conversación.
from anthropic import Anthropic, BetaFallbackState, BetaRefusalFallbackMiddleware
# Ante un rechazo, el middleware reintenta con el modelo de respaldo indicado y
# envía automáticamente el encabezado beta fallback-credit en cada solicitud que maneja.
client = Anthropic(
middleware=[BetaRefusalFallbackMiddleware([{"model": "claude-opus-4-8"}])],
)
state = BetaFallbackState() # pins follow-ups to the model that accepted
# Streaming: ante un rechazo, el middleware reintenta con el modelo de respaldo y
# empalma sus eventos en el stream abierto.
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}")
# Sin streaming: reutilizar el estado mantiene la conversación fijada.
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}")Cómo se comporta
- Los reintentos recorren tu lista de fallback en orden. Un modelo de fallback que a su vez rechaza pasa la solicitud a la siguiente entrada.
- Cuando todos los modelos de la lista han declinado, el middleware devuelve el rechazo final (la respuesta de rechazo del último modelo) en lugar de lanzar un error.
- Los bloques de pensamiento de Claude Fable 5.1 o Claude Fable 5 pasan sin cambios. Cada reintento reenvía el cuerpo de tu solicitud original, y los únicos bloques que el middleware elimina del historial de la conversación en solicitudes posteriores son los bloques de límite
fallbackque él mismo agregó. El modelo de fallback no puede leer los bloques de Claude Fable 5.1, que se conservan solo para ese modelo o uno más nuevo, por lo que la API los descarta. - Las respuestas atendidas a través del middleware incluyen un bloque de contenido
fallbacken cada límite entre modelos, igual que las respuestas de fallback del lado del servidor. El middleware gestiona esos bloques por ti en solicitudes posteriores. - El modelo que aceptó se registra en
BetaFallbackState, de modo que las solicitudes de seguimiento que comparten el estado permanecen fijadas a él en lugar de volver a preguntar a un modelo que rechazó.
Escribir el reintento tú mismo
Sobre HTTP directo o con lógica de reintento personalizada, implementa el patrón que el middleware envuelve:
Detecta el rechazo
Revisa la respuesta en busca de
stop_reason: "refusal".Reenvía en un modelo de fallback
Envía la misma solicitud con
modelestablecido en un modelo de fallback, como Claude Opus 4.8. Otro modelo normalmente puede atender una solicitud que Claude Fable 5.1 o Claude Fable 5 declina. Cómo manejas el historial de la conversación depende de si canjeas un crédito de fallback:- Sin canjear un crédito: puedes dejar los bloques
thinkingyredacted_thinkinganteriores en su lugar o eliminarlos para ahorrar tokens de entrada. El modelo de fallback no puede usarlos de ninguna forma: ignora los bloques de Claude Fable 5, y los bloques de Claude Fable 5.1 se conservan solo para ese modelo o uno más nuevo, por lo que la API los descarta. - Canjeando un crédito: envía el cuerpo sin cambios, porque el canje requiere una coincidencia exacta. El servidor maneja los bloques de pensamiento del modelo anterior en un canje, así que no los elimines (consulta Campos que deben coincidir con la solicitud rechazada).
- Sin canjear un crédito: puedes dejar los bloques
Permanece en el modelo de fallback
Para conversaciones de varios turnos, sigue usando el modelo de fallback en los turnos subsiguientes en lugar de volver a cambiar.
Un reintento manual escribe la caché de prompts del modelo de fallback desde cero, lo que cuesta más que leer una caché existente. El crédito de fallback reembolsa ese costo; canjéalo en cada reintento que construyas tú mismo.
Rechazos en Message Batches
Una solicitud rechazada en un Message Batch regresa como result.type: "succeeded" con stop_reason: "refusal". Los resultados de lote llevan el mismo objeto stop_details que las respuestas síncronas, por lo que puedes detectar rechazos a través de stop_reason o de stop_details.type. Una diferencia: los rechazos en lote no emiten créditos de fallback, por lo que stop_details en un resultado de lote nunca incluye un fallback_credit_token.
El fallback del lado del servidor no está disponible para lotes (una solicitud de lote que incluye fallbacks produce un resultado con error por elemento). Para reintentar los elementos de lote rechazados:
- Recopila los elementos rechazados de los resultados.
- Elimina los bloques de pensamiento de Claude Fable 5.1 o Claude Fable 5 de cualquier historial de varios turnos.
- Reenvíalos en un modelo de fallback como un nuevo lote o como solicitudes directas.
Errores comunes
- Reintenta en un modelo diferente. Reenviar una solicitud rechazada al mismo modelo generalmente obtiene otro rechazo. Dirige el reintento al modelo de fallback.
- Presupuesta los reintentos por solicitud, no por turno ni por sesión. Un solo turno puede producir varios rechazos, por ejemplo un agente más sus subagentes.
- Configura el fallback en cada ruta de solicitud. Los manejadores de reintento, las ramas de recuperación de errores y los workers en segundo plano lo necesitan. Un manejador que vuelve a emitir una solicitud sin fallback pierde la protección exactamente en las solicitudes que más probablemente la necesiten.
- Da a las llamadas de subagentes su propio fallback. El parámetro
fallbacksno se propaga a las llamadas a modelos realizadas desde dentro de la ejecución de herramientas. - Haz del fallback una propiedad de la solicitud, no del estado ambiental. Una bandera compartida, un valor de configuración en caché o un interruptor global pueden desincronizarse y dejar silenciosamente una solicitud sin protección. Cuando no puedas confirmar que el fallback está activo, configúralo en lugar de asumir que está activado.
- Instrumenta los rechazos como su propia señal. Un rechazo es un HTTP 200, por lo que el monitoreo basado en tasas de error o respuestas 5xx nunca lo ve. Emite un evento por rechazo y uno por respuesta atendida mediante fallback (la entrada
fallback_messageenusage.iterationsmarca esta última), y luego alerta sobre la diferencia entre los dos conteos. - Ramifica según
stop_reasonostop_details.type, no segúncontentni los campos internos destop_details. El objetostop_detailssiempre está presente en un rechazo, pero sus camposcategoryyexplanationpueden sernull. Verifica directamente questop_reasonsea igual a"refusal".
Próximos pasos
Evita pagar dos veces el costo de la caché de prompts cuando construyes el reintento tú mismo.
Cada valor de stop_reason y cómo manejarlo.
Cómo funciona el middleware del SDK, incluido el asistente de fallback ante rechazos.
Migra una aplicación existente a Claude Fable 5.1.
Was this page helpful?