Claude Fable 5 incluye clasificadores de seguridad que pueden rechazar una solicitud. Cuando eso sucede, recibes una respuesta normal, no un error, con stop_reason: "refusal". Por lo general, aún puedes obtener una respuesta enviando la misma solicitud a otro modelo de Claude. Esta página te muestra cómo reconocer un rechazo y cómo configurar ese reintento.
Lee esta página cuando desarrolles con Claude Fable 5 y quieras que las solicitudes rechazadas pasen automáticamente a otro modelo. También aplica cuando acabas de ver "refusal" en una respuesta y quieres saber qué hacer a continuación.
La lista completa de valores de stop_reason está en Stop reasons y fallback. Los detalles sobre cómo se facturan las solicitudes rechazadas, y cómo evitar pagar dos veces por el almacenamiento en caché de prompts en un reintento, están en Crédito de fallback. El helper del SDK que encapsula todo esto está en Middleware del SDK. Para ver un ejemplo completo de principio a fin, consulta el cookbook de fallback y facturación.
La configuración más simple: nombra un modelo de fallback en la solicitud, y la API se encarga del reintento.
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" }]
});Las secciones siguientes 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.
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 el rechazo. Su campo category nombra el área de política que activó el clasificador. Su campo explanation es una descripción legible para humanos; el texto no es estable, así que muéstralo en lugar de analizarlo. Ambos campos son null cuando el rechazo no corresponde a una categoría con nombre, y null es un valor normal y permanente en lugar de un marcador de posición. stop_details en sí es null para todos los stop reasons distintos de refusal.
category | Qué significa |
|---|---|
"cyber" | La solicitud podría facilitar daño cibernético, como 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. |
"reasoning_extraction" | La solicitud pide al modelo que reproduzca su razonamiento interno en el texto de la respuesta. Para obtener el razonamiento en forma estructurada, usa adaptive thinking. |
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.
Cómo se facturan los rechazos: Un rechazo antes de cualquier salida deja content vacío, y no se te factura (los conteos de tokens aparecen en usage pero no se cobran, y la solicitud no cuenta contra los límites de velocidad). Un rechazo a mitad del stream factura los tokens de entrada y la salida ya transmitida a las tarifas normales.
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 o Claude Platform en AWS, configuración más simple | Fallback del lado del servidor | Una solicitud, una respuesta. La API se encarga del reintento. |
| Cualquier plataforma, con el SDK de TypeScript, Python, Go, Java o C# | El middleware del SDK | Configura una vez en el cliente. Los reintentos ocurren automáticamente. |
| Ruby, PHP, HTTP sin procesar o lógica de reintento personalizada | Reintento manual con crédito de fallback | Control total. El crédito de fallback mantiene el costo bajo. |
El fallback del lado del servidor y el middleware del SDK aplican el crédito de fallback por ti, así que solo necesitas esa página cuando construyas el reintento tú mismo.
El fallback del lado del servidor reintenta una solicitud rechazada dentro de una sola llamada a la API. Nombras hasta tres modelos de fallback, y cuando Claude Fable 5 rechaza, la API ejecuta el siguiente modelo de la cadena con la misma solicitud. 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.
El fallback del lado del servidor está en beta en la Claude API y Claude Platform en AWS. El parámetro fallbacks se rechaza en la Message Batches API y no está disponible en Amazon Bedrock, Vertex AI ni Microsoft Foundry. En esas plataformas, usa el middleware del SDK en su lugar.
Nombra los modelos de fallback en el parámetro fallbacks y envía el encabezado beta 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"],
)
# 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 generó 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,
}
)
)Algunas reglas aplican a la lista fallbacks:
allowed_fallback_models en la entrada del modelo en la Models API.model y puede sobrescribir max_tokens y thinking solo para ese intento.El encabezado beta debe llevar exactamente la fecha 2026-06-01. Con cualquier otro valor server-side-fallback-*, el parámetro fallbacks se rechaza con un error 400. Si desarrollaste contra una vista previa anterior de esta función, actualiza el encabezado beta y las formas de solicitud y respuesta juntas a las de esta página.
La respuesta se ve como cualquier otro mensaje, con dos adiciones:
model de nivel superior reporta el modelo que produjo el mensaje devuelto, ya sea el modelo solicitado o un fallback.fallback marca cada punto en content donde la salida de un modelo da paso a la del siguiente: {"type": "fallback", "from": {"model": ...}, "to": {"model": ...}}. from.model repite la cadena de modelo que enviaste cuando el salto que rechaza es el modelo solicitado. to.model es 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:
{
"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 array usage.iterations registra cada intento. Un modelo que rechazó 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 rechazan, la respuesta es el rechazo del último modelo, con una entrada message para cada salto anterior y una entrada fallback_message para el último.
En el siguiente turno, envía el contenido del asistente de vuelta tal como lo recibiste. Después de un fallback a mitad de la salida, content puede incluir tipos de bloque que el modelo que rechazó produjo antes del traspaso; la tabla siguiente cubre cuáles conservar y cuáles descartar cuando repitas 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 thinking a su alrededor, así que una solicitud que repite bloques de thinking 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 resultado correspondiente. |
Un bloque connector_text lleva texto de narración que algunas respuestas que usan herramientas incluyen entre llamadas a herramientas.
En una solicitud con streaming, el reintento ocurre en el mismo stream, y nada de lo que ya has recibido se invalida. Cuando el rechazo ocurre antes de cualquier salida, message_start nombra el modelo de fallback y el bloque fallback es el primer bloque de contenido; como message_start espera a que el intento de fallback comience, el tiempo hasta el primer byte incluye el intento rechazado. Cuando el rechazo ocurre a mitad de la salida, el bloque de contenido abierto se cierra, el bloque fallback (un par ordinario de content_block_start y content_block_stop sin deltas) marca el límite, y el modelo de fallback continúa desde la salida parcial. Solo los bloques text de la salida parcial se pasan al modelo de fallback como contexto; los otros tipos de bloque permanecen en content. En el caso de mitad de salida, message_start ya nombró el modelo solicitado, así que lee el modelo que atiende desde el to.model del bloque fallback y desde la entrada fallback_message en el usage.iterations del message_delta final.
En una solicitud sin streaming, un rechazo a mitad de la salida se comporta de manera diferente: la respuesta omite la salida parcial del modelo rechazado, y el modelo de fallback responde desde cero. El resultado se ve como un rechazo antes de cualquier salida, con el bloque fallback primero. El intento rechazado y sus tokens de salida aún aparecen en usage.iterations.
Cuando un rechazo se activa después de que las herramientas del servidor (por ejemplo, búsqueda web o ejecución de código) ya se han ejecutado dentro de una solicitud, la API devuelve el rechazo en lugar de avanzar a un modelo de fallback. Si el encabezado fallback-credit-2026-06-01 también está configurado, ese rechazo lleva un token de crédito canjeable al continuar la respuesta parcial, de modo que el trabajo de herramientas completado no se pierde. Esto aplica solo a herramientas del servidor que iteran dentro de una sola solicitud; las conversaciones que usan herramientas del lado del cliente hacen fallback normalmente.
Los SDKs de TypeScript, Python, Go, Java y C# incluyen un middleware de fallback por rechazo. 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 solicitudes rechazadas automáticamente, en cualquier plataforma. El middleware también envía el encabezado beta fallback-credit-2026-06-01 en cada solicitud que maneja, así que los reintentos se retarifican sin configuración por solicitud.
El helper de middleware de fallback por rechazo aún no está disponible en los SDKs de Ruby y PHP. En esos SDKs, implementa el patrón de detectar y reintentar directamente.
Pasa el middleware al constructor del cliente, y comparte una instancia de BetaFallbackState entre las solicitudes de una conversación.
# Ante un rechazo, el middleware reintenta con el modelo de respaldo indicado y
# envía automáticamente el encabezado beta de crédito de respaldo en cada solicitud que gestiona.
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 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}")
# 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}")fallback en cada límite de modelo, igual que las respuestas de fallback del lado del servidor. El middleware gestiona esos bloques por ti en solicitudes posteriores.BetaFallbackState, así que las solicitudes de seguimiento que comparten el estado permanecen fijadas a él en lugar de volver a preguntar a un modelo que rechazó.El middleware y el parámetro fallbacks del lado del servidor hacen el mismo trabajo. Configura uno u otro, nunca ambos en la misma solicitud. Para enviar una solicitud con fallbacks del lado del servidor desde una aplicación que instala el middleware, usa una instancia de cliente separada sin él.
Una solicitud rechazada en un Message Batch regresa como result.type: "succeeded" con stop_reason: "refusal". El campo stop_details puede ser null en los resultados de batch, así que detecta rechazos verificando stop_reason directamente.
El fallback del lado del servidor no está disponible para batches (una solicitud de batch que incluye fallbacks produce un resultado con error por elemento). Para reintentar elementos de batch rechazados:
fallbacks no se propaga a las llamadas de modelo hechas desde dentro de la ejecución de herramientas.fallback_message en usage.iterations marca esta última), luego alerta sobre la brecha entre los dos conteos.stop_reason, no según stop_details ni content. stop_details es informativo y puede ser null en un rechazo. Verifica que stop_reason sea igual a "refusal" directamente.Evita pagar el costo de caché de prompts dos veces cuando construyas el reintento tú mismo.
Todos los valores de stop_reason y cómo manejarlos.
Cómo funciona el middleware del SDK, incluido el helper de fallback por rechazo.
Migra una aplicación existente a Claude Fable 5.
Was this page helpful?