Como montar fallback entre Fable 5.1 e GPT-6 Astra quando um dos dois falha

Montar um fallback entre Fable 5.1 e GPT-6 Astra é criar uma camada de roteamento que troca de provedor sem o app perceber. Você define um contrato interno único, escreve um adaptador para cada modelo respeitando as regras de cada API (o Fable 5.1 recusa tool_choice any ou tool e thinking desabilitado, o Astra não aceita temperature, top_p nem top_logprobs), deixa o SDK refazer o que é refazível e só troca de modelo em erro persistente, indisponibilidade ou saída que não valida no JSON Schema. No fim, normaliza a resposta e loga qual modelo atendeu
Fala aí, beleza? Depender de um modelo só em produção é combinar de cair junto com ele
Basta um 429, um 529 ou um 503 chegando na hora errada e a sua feature inteira vira tela de erro, mesmo que o outro provedor esteja respondendo lindamente ali do lado
Os dois modelos da vez são novinhos: o Claude Fable 5.1 saiu em 1 de setembro de 2026, junto com o Mythos 5.1, e o GPT-6 Astra começou como preview limitado em 3 de setembro e teve o rollout concluído em 6 de setembro, já disponível na API
A ideia deste post é uma só: desenhar a camada de roteamento que troca de provedor no meio do caminho sem o resto do app descobrir que a troca aconteceu
Bora ver na prática?
O que você precisa antes de montar o fallback
Nada de PC da Nasa aqui, é tudo configuração de projeto mesmo
- Conta e chave de API nos dois provedores, porque fallback com um provedor só é só um retry com nome bonito
- SDK oficial da Anthropic (Python ou TypeScript). Ele já refaz a requisição em 529, 503 e 500 por padrão, com até 2 tentativas, e o número é ajustável via
max_retriesna criação do client - SDK oficial da OpenAI a partir da versão 1.0.0, que refaz automaticamente 429 e 5xx com backoff exponencial e respeita o header
Retry-Afternas tentativas elegíveis - Um JSON Schema único pra resposta, já que os dois modelos suportam structured outputs por JSON Schema. É esse schema que vira o seu contrato
- Log por requisição com modelo usado, código de erro e latência. Sem isso tu nunca vai saber quem atendeu o quê
Por que começar pelo schema e não pelo código? Porque o schema é a única coisa que os dois modelos têm em comum de verdade
O resto (nome do modelo, formato de ferramenta, parâmetros aceitos) muda de um pro outro, e é justamente isso que a sua camada vai esconder
Formação Claude Code
Domine Claude Code do absoluto zero até o avançado
- 114 aulas
- 4 projetos
- 9h 18min
Fable 5.1 x GPT-6 Astra: o que muda na chamada e precisa ser normalizado
Troca cega de modelo quebra por detalhe bobo
Se liga no que muda de um lado pro outro:
| O que muda | Claude Fable 5.1 | GPT-6 Astra |
|---|---|---|
| Identificador do modelo | claude-fable-5-1 na Claude API, Google Cloud, Microsoft Foundry e Claude Platform na AWS, e anthropic.claude-fable-5-1 no Amazon Bedrock |
gpt-6-astra |
| Contexto e saída máxima | 1 milhão de tokens de contexto, até 128 mil tokens de saída por resposta | 1.050.000 tokens de contexto, até 128.000 tokens de completion |
| Tool calling | tool_choice do tipo any ou tool retorna 400 invalid_request_error. A orientação é usar tool_choice auto com ferramentas strict: true |
Tool calling exige a Responses API. Chat Completions atende requisições básicas |
| Thinking | Enviar thinking: {type: "disabled"} retorna erro 400 |
|
| Parâmetros de amostragem | Não suporta temperature, top_p nem top_logprobs. Em Chat Completions, remova logprobs, e em Responses remova message.output_text.logprobs do include |
|
| Structured outputs | JSON Schema em response_format |
JSON Schema informado em json_schema dentro de response_format |
| Preço de entrada e saída | US$ 10,00 por milhão de entrada e US$ 50,00 por milhão de saída | US$ 10,00 por milhão de entrada e US$ 50,00 por milhão de saída no Standard (Batch e Flex custam 50% do Standard, o modo Fast custa 2x) |
| Leitura de cache | US$ 0,25 por milhão (queda de 75% em relação a US$ 1,00 do Fable 5) | US$ 1,00 por milhão de leitura e US$ 12,50 por milhão de escrita |
| Prompt muito longo | Acima de 272 mil tokens de entrada, cobra 2x nas tarifas de entrada e de cache e 1,5x na saída, valendo pra requisição inteira |
Lendo a tabela de trás pra frente: o preço de entrada e saída é idêntico nos dois, então o custo não é o que decide a troca
O que decide é o formato da chamada
A sua camada de roteamento tem que esconder do app quatro coisas: o identificador do modelo, o jeito de pedir ferramenta, os parâmetros que um aceita e o outro recusa, e o caminho até o JSON Schema
Se o app precisar saber qualquer uma dessas quatro, o fallback já nasceu vazando 😅
Passo a passo para montar a camada de roteamento
- Definir o contrato interno
Uma função só, que recebe mensagens e um JSON Schema e devolve um objeto já validado
# contrato.py
def gerar(mensagens: list, schema: dict, ferramentas: list | None = None) -> dict:
"""Devolve sempre o mesmo formato:
{"dados": {...}, "texto": str, "tool_calls": [...], "modelo": str}
O app nao sabe (e nao precisa saber) quem respondeu
"""
O erro comum deste passo: deixar o nome do modelo entrar como argumento vindo do app. Aí não é camada de roteamento, é if espalhado pelo código todo
- Escrever o adaptador do Fable 5.1
Aqui valem duas regras duras: tool_choice auto com ferramentas strict: true, e nunca mandar thinking desabilitado
from anthropic import Anthropic
client_anthropic = Anthropic(max_retries=3)
def chamar_fable(mensagens, schema, ferramentas=None):
kwargs = {
"model": "claude-fable-5-1", # anthropic.claude-fable-5-1 no Bedrock
"max_tokens": 8192,
"messages": mensagens,
"response_format": {"type": "json_schema", "json_schema": schema},
}
if ferramentas:
kwargs["tools"] = ferramentas # cada ferramenta com strict: true
kwargs["tool_choice"] = {"type": "auto"}
return client_anthropic.messages.create(**kwargs)
O erro comum deste passo: copiar um código antigo que forçava ferramenta. tool_choice do tipo any ou tool retorna 400 invalid_request_error no Fable 5.1
O segundo erro comum: mandar thinking: {type: "disabled"} achando que economiza. Retorna 400 e pronto
- Escrever o adaptador do GPT-6 Astra
Se tem ferramenta na jogada, é Responses API. Chat Completions fica pras requisições básicas
from openai import OpenAI
client_openai = OpenAI(max_retries=3)
def chamar_astra(mensagens, schema, ferramentas=None):
kwargs = {
"model": "gpt-6-astra",
"input": mensagens,
"response_format": {"type": "json_schema", "json_schema": schema},
# nada de temperature, top_p ou top_logprobs aqui
}
if ferramentas:
kwargs["tools"] = ferramentas
return client_openai.responses.create(**kwargs)
O erro comum deste passo: arrastar temperature e top_p do preset antigo do time. O Astra não suporta esses parâmetros, nem top_logprobs
E se tu usa Responses com include, lembra de tirar message.output_text.logprobs de lá
- Camada de retry no mesmo modelo, antes de pensar em trocar
Deixa o SDK trabalhar, ele já sabe fazer isso
É o MESMO client dos passos 2 e 3, criado uma vez só, com o número de tentativas escolhido ali na criação
client_anthropic = Anthropic(max_retries=3) # o padrao do SDK sao 2 tentativas
client_openai = OpenAI(max_retries=3)
O SDK da Anthropic já refaz 529, 503 e 500 por padrão, com até 2 tentativas ajustáveis
O SDK da OpenAI, da 1.0.0 em diante, refaz 429 e 5xx com backoff exponencial e respeita o Retry-After
O erro comum deste passo: escrever o seu próprio loop de retry POR CIMA do retry do SDK. Aí tu multiplica tentativa por tentativa e a conta cresce sozinha
- Definir o gatilho de troca
São três, e só três: erro persistente depois das tentativas, indisponibilidade do provedor, e saída que não valida no schema
def gerar(mensagens, schema, ferramentas=None):
ordem = [("claude-fable-5-1", chamar_fable), ("gpt-6-astra", chamar_astra)]
ultimo_erro = None
for nome, chamar in ordem:
try:
bruto = chamar(mensagens, schema, ferramentas)
return normalizar(bruto, nome, schema) # valida contra o schema aqui dentro
except ErroDeCliente: # 400, 401, 403, 404: nao troca, e bug seu
raise
except (ErroDeCapacidade, SaidaInvalida) as e:
ultimo_erro = e
continue
raise ultimo_erro
O erro comum deste passo: cair pro outro modelo em 400. Erro de cliente nunca deve ser refeito, e trocar de provedor só troca a mensagem de erro que tu vai ler no log
- Normalizar a resposta antes de devolver ao app
Mesmo objeto, mesmos campos, texto e tool calls no mesmo formato, sempre
def normalizar(bruto, modelo, schema):
dados = extrair_json(bruto) # cada provedor tem seu caminho ate o conteudo
if not valida(dados, schema):
raise SaidaInvalida(modelo)
return {
"dados": dados,
"texto": extrair_texto(bruto),
"tool_calls": extrair_tool_calls(bruto), # nome + argumentos, no seu formato
"modelo": modelo,
}
O erro comum deste passo: normalizar só o texto e deixar as tool calls no formato cru de cada API. Aí o app funciona no primário e explode no fallback, que é o pior momento possível pra descobrir isso
- Observabilidade e idempotência
Cada requisição precisa carregar uma chave de tarefa, pra que uma troca de modelo no meio não gere trabalho (e cobrança) duplicado
log.info("geracao", extra={
"tarefa_id": tarefa_id,
"modelo": resultado["modelo"],
"tentativas": tentativas,
"codigo_erro": codigo,
"latencia_ms": latencia,
})
Se o fluxo for longo e cheio de ferramenta, dá pra ganhar visibilidade no lado do Claude usando os progress updates em beta e acompanhar o que acontece entre as tool calls
O erro comum deste passo: logar só o erro final. Sem registrar QUAL modelo atendeu cada requisição, tu não consegue nem explicar a variação de custo no fim do mês
Qual erro deve refazer, qual deve trocar de modelo
Aqui é onde a maioria dos fallbacks erra: trata todo erro igual
429 na Claude API
- Sintoma: a requisição volta com
rate_limit_error - Causa: a organização bateu um limite de taxa, o teto mensal de gasto do tier ou um limite de gasto do workspace. Os limites são medidos por requisições por minuto (RPM), tokens de entrada por minuto (ITPM) e tokens de saída por minuto (OTPM)
- Solução: ler o header
retry-after, que vem em segundos, e esperar o tempo indicado antes de tentar de novo - Como prevenir: distribuir a carga no minuto e olhar as três métricas separadas, porque estourar OTPM com resposta longa é diferente de estourar RPM com muita chamada curta
529 na Claude API
- Sintoma:
overloaded_error - Causa: a API está temporariamente sobrecarregada do lado da Anthropic, não é problema do seu uso
- Solução: esse é o candidato mais claro a troca de provedor, porque não existe valor de
retry-afterconfiável pra seguir aqui - Como prevenir: não dá pra prevenir do seu lado, e é exatamente por isso que o fallback existe
429 na API da OpenAI
- Sintoma: 429 com type
rate_limit_errore codeslow_down - Causa: ritmo de requisições acima do que o serviço aceita, e pode ser também saldo pré-pago esgotado ou limite de gasto atingido
- Solução: backoff mais longo. Se vier header
Retry-After, esperar pelo menos o tempo indicado - Como prevenir: monitorar saldo e limite de gasto junto com o ritmo. Já me ferrei com isso: parece rate limit, e no fim era saldo
503 na API da OpenAI
- Sintoma: 503 com type
service_unavailable_errore codeserver_is_overloaded - Causa: o modelo pedido está sem capacidade no momento
- Solução: backoff mais longo e, se persistir, cair pro outro provedor
- Como prevenir: mesma coisa do 529, é capacidade do outro lado
A regra geral de o que refazer
A classificação da OpenAI é bem direta e serve de guia pro seu roteador inteiro:
- erros de cliente (400, 401, 403, 404) nunca devem ser refeitos
- erros de servidor (500, 502) devem ser refeitos com backoff
- erros de capacidade (429, 503) pedem backoff mais longo
E a saída fora do formato esperado?
Essa não tem código HTTP nenhum: chega 200, chega bonita, e vem quebrada pro seu app
Por isso a validação contra o JSON Schema entra dentro da camada, antes de devolver qualquer coisa
Se não validou, trata como falha e segue pro próximo adaptador, igual erro de capacidade
Quando vale acionar o outro modelo (e quando não vale)
Escolher o primário não é torcida, é perfil de carga
Carga com muita releitura de contexto: o Fable 5.1 leva vantagem pela leitura de cache a US$ 0,25 por milhão, contra US$ 1,00 por milhão no Astra. Entrada e saída custam igual nos dois, então o cache é onde a diferença aparece de verdade
Prompt muito longo: presta atenção no corte de 272 mil tokens de entrada do Astra. Acima disso, a cobrança vira 2x nas tarifas de entrada e de cache e 1,5x na saída, valendo pra requisição inteira. Um fallback que joga um prompt gigante pro Astra sem avisar ninguém consegue ser caro e silencioso ao mesmo tempo
Fluxo que dependia de uso obrigatório de ferramenta: esse precisa ser repensado antes de virar fallback, porque o Fable 5.1 removeu o uso forçado. Com tool_choice auto e ferramentas strict: true, o desenho do prompt passa a ter mais peso
E tem o outro lado da moeda, que é saber quando NÃO acionar
Erro de cliente (400, 401, 403, 404) é bug seu: schema errado, chave errada, parâmetro que o modelo não aceita. Trocar de provedor aí só esconde o problema, e ele volta em dobro depois
Vale também o exercício de custo antes de escolher o primário, porque existem tarefas em que o Astra é exagero e um modelo mais barato entrega igual
Vídeo: comparativo de modelos no canal
Pra começar do zero na comparação entre modelos de topo, este vídeo do canal traz um panorama do assunto, colocando modelos frente a frente em teste
Conclusão
Fallback bom é aquele que ninguém percebe
O app manda mensagens e um schema, recebe um objeto validado de volta, e nunca fica sabendo se quem respondeu foi o claude-fable-5-1 ou o gpt-6-astra
O próximo passo é bem concreto: implementa o adaptador de UM dos dois primeiro, valida a saída contra o JSON Schema em ambiente de teste, confere se as tool calls saem no seu formato normalizado e só depois disso liga a troca automática
E liga o log de qual modelo atendeu cada requisição desde o primeiro dia, porque no dia do 529 tu vai querer olhar esse gráfico 😀
até o próximo post!
Perguntas frequentes
Qual a diferença entre erro 429 e 529 na Claude API na hora de montar o fallback?
O 429 rate_limit_error indica que a organização bateu um limite de taxa, o teto mensal de gasto do tier ou um limite de gasto do workspace, e vem com o header retry-after em segundos. Já o 529 overloaded_error é sobrecarga temporária do lado da Anthropic, sem relação com o seu uso, e não traz um retry-after confiável para seguir. Por isso o roteamento não pode tratar os dois do mesmo jeito.
O código slow_down no erro 429 da OpenAI sempre é limite de requisições?
Não necessariamente. O 429 com type rate_limit_error e code slow_down indica ritmo de requisições acima do que o serviço aceita, mas também pode significar saldo pré-pago esgotado ou limite de gasto atingido. Vale sempre checar o header Retry-After quando ele vier na resposta.
O SDK oficial já resolve sozinho o fallback entre Fable 5.1 e GPT-6 Astra?
Não, cada SDK só refaz a própria chamada dentro do próprio provedor. O SDK da Anthropic já refaz 529, 503 e 500 com até 2 tentativas por padrão, ajustável via max_retries, e o da OpenAI, a partir da versão 1.0.0, refaz 429 e 5xx com backoff exponencial respeitando o Retry-After. Trocar de provedor no meio do caminho é a parte que fica por conta da sua camada de roteamento.
Dá pra usar o mesmo JSON Schema no Fable 5.1 e no GPT-6 Astra sem adaptar nada?
O schema em si pode ser o mesmo, mas o campo onde ele entra muda: no Fable 5.1 ele vai direto em response_format, e no GPT-6 Astra vai em json_schema dentro de response_format. Os dois suportam structured outputs via JSON Schema, então é diferença de encaixe, não de conteúdo.
Faz diferença de custo escolher Fable 5.1 ou GPT-6 Astra no fallback?
No preço padrão de entrada e saída, não: os dois cobram US$ 10,00 por milhão de tokens de entrada e US$ 50,00 por milhão de saída. A diferença aparece na leitura de cache, US$ 0,25 por milhão no Fable 5.1 contra US$ 1,00 por milhão no GPT-6 Astra, e no GPT-6 Astra acima de 272 mil tokens de entrada, faixa em que a tarifa sobe pra 2x na entrada e no cache e 1,5x na saída.
Preciso usar a Responses API para chamar ferramentas no GPT-6 Astra?
Sim, a orientação atual da OpenAI é que tool calling no GPT-6 Astra exige a Responses API. A Chat Completions atende só requisições básicas ao modelo, sem cobrir o uso de ferramentas.
Formações
Formação Vibe Coding
Do Prompt ao Produto: Crie Software Real com IA
- 474 aulas
- 20 projetos
- 39h 27min
Blog | Mais populares
O que significa “ChatGPT network error” e como resolver
O “ChatGPT Network Error” é uma ocorrência frequente na rotina de muitos usuários do ChatGPT. Porém, poucos compreendem seu significado, quando esse erro surge, etc. […]
Checklist de segurança n8n VPS pública: guia essencial para proteger sua instalação
Checklist de segurança n8n VPS pública: guia essencial para proteger sua instalação A popularidade da automação de processos com o n8n está em alta, principalmente […]
