Trocar Fable 5.1 por GPT-6 Astra: o que realmente muda no seu código?

Comparação de código ao trocar Fable 5.1 por GPT-6 Astra
Resposta rápida

Trocar Fable 5.1 por GPT-6 Astra raramente é só editar o model ID: os dois cobram US$ 10 por milhão de tokens de entrada e US$ 50 de saída, entregam até 128k de saída e aceitam os mesmos cinco níveis de esforço (low, medium, high, xhigh e max), mas o formato de ferramenta muda (tool_use e tool_result com tool_use_id contra function_call e function_call_output com call_id), o estado de raciocínio muda (thinking blocks contra reasoning items com encrypted_content) e o cache read custa US$ 0,25 de um lado e US$ 1 do outro. A saída é isolar a chamada numa única fronteira.

Fala aí, beleza? Trocar de modelo quase nunca é "troca o model ID e segue a vida"

O Claude Fable 5.1 saiu em 2026-09-01, lançado pela Anthropic junto com o Mythos 5.1

O GPT-6 Astra saiu dois dias depois, em 2026-09-03, pela OpenAI, inicialmente para um conjunto limitado de organizações e com disponibilidade ampliada nos dias seguintes

Os dois têm janela gigante e teto de 128k tokens de saída, então no papel parece que dá pra pingar de um pro outro sem dor

Aí você abre o código que já está rodando e a conta é outra: a integração encosta em formato de mensagem, em parâmetro de raciocínio e em tratamento de ferramentas

Esse post é sobre onde a troca REALMENTE dói, e sobre como isolar a chamada do modelo pra ela não vazar pelo app inteiro 🙂

Mapa de equivalências: o que tem par dos dois lados e o que não tem

Antes de mexer em qualquer linha, vale olhar o que tem par e o que simplesmente não existe do outro lado

Item Claude Fable 5.1 GPT-6 Astra Tem equivalente direto?
Model ID claude-fable-5-1 na Claude API, Google Cloud, Microsoft Foundry e Claude Platform na AWS; anthropic.claude-fable-5-1 no Amazon Bedrock gpt-6-astra na API da OpenAI, que é onde o identificador está documentado; o modelo também está disponível no Microsoft Azure e no AWS Bedrock Sim, só muda a string (e o prefixo no Bedrock, do lado do Claude)
Janela de contexto 1M de tokens por padrão 1.050.000 tokens Sim, na prática o mesmo porte
Saída máxima 128k tokens 128.000 tokens Sim
Entrada (API) US$ 10 por milhão US$ 10 por milhão Sim, mesmo preço
Saída (API) US$ 50 por milhão US$ 50 por milhão Sim, mesmo preço
Cache read US$ 0,25 por milhão US$ 1 por milhão Existe dos dois lados, mas o preço não bate
Níveis de esforço low, medium, high, xhigh, max, com padrão high na API low, medium, high, xhigh, max, e o Astra não aceita none Mesmos cinco níveis, nome do parâmetro diferente
Nome do parâmetro effort reasoning.effort na Responses API e reasoning_effort na Chat Completions Sim, com tradução
Formato de ferramenta bloco tool_use na resposta e tool_result numa mensagem com role user, ligados por tool_use_id Items function_call e function_call_output, correlacionados por call_id Conceito igual, formato diferente
Estado de raciocínio thinking blocks reasoning items com encrypted_content, repassados por previous_response_id ou reenviando os output items Cada um tem o seu jeito, não é 1 pra 1
Gestão de contexto cheio compaction (resume o contexto antigo perto do limite) e context editing (remove tool_result antigos) endpoint /responses/compact, que devolve a janela compactada com um item de compactação criptografado Existe dos dois lados, com mecânica diferente
Orquestração programática sem recurso equivalente documentado Programmatic Tool Calling na Responses API, com allowed_callers aceitando direct e/ou programmatic Não, isso é só de um lado
Modo de thinking só o modo adaptive, com a profundidade controlada pelo effort controle via reasoning.effort Parecido no efeito, não no desenho
Extras do Fable 5.1 effort por mensagem (beta), system messages com escopo de turno (beta), updates legíveis entre chamadas de ferramenta com display: updates (beta) e content provenance recursos suportados: reasoning tokens, streaming, function calling, structured outputs e entrada de imagem Não, cada lado tem o seu conjunto

Repara numa coisa: o preço de entrada e de saída é o MESMO nos dois

Então a briga de custo não se decide na tabela de preço padrão, ela se decide no cache e no formato do seu tráfego

Formação Claude Code
Formação Recomendada

Formação Claude Code

Domine Claude Code do absoluto zero até o avançado

  • 120 aulas
  • 4 projetos
  • 9h 45min

Antes de migrar: o que você precisa ter em mãos

Antes do primeiro commit, junta isso aqui:

  • Chave e SDK do provedor de destino, óbvio, mas é o que mais trava a primeira execução
  • Saber em qual plataforma o modelo roda. O Fable 5.1 aparece como claude-fable-5-1 na Claude API, no Google Cloud, no Microsoft Foundry e na Claude Platform na AWS, e como anthropic.claude-fable-5-1 no Amazon Bedrock. O GPT-6 Astra está disponível na API da OpenAI, no Microsoft Azure e no AWS Bedrock, e o identificador documentado é o gpt-6-astra da API da OpenAI, então confirme na sua plataforma como o modelo é referenciado antes de sair trocando string
  • Saber qual API da OpenAI você usa. Responses ou Chat Completions? Isso muda o nome do parâmetro de esforço (reasoning.effort contra reasoning_effort) e muda o desenho da conversa, porque a Responses trabalha com Items
  • Um inventário do que seu app usa hoje. Lista todo ponto que toca tool_choice, thinking blocks, streaming, structured outputs e entrada de imagem. É esse inventário que vira a sua camada isolada

E a camada de compatibilidade com o SDK da OpenAI?

Ela existe: dá pra configurar o cliente OpenAI com a chave da Claude API e a base URL https://api.anthropic.com/v1/, chamando chat.completions.create com nomes de modelo Claude

Parece o atalho dos sonhos, né? 😀

Só que a própria documentação posiciona isso como caminho de teste e comparação, não como solução de produção, e o parâmetro strict de function calling é ignorado nessa camada

Use pra medir, não pra virar a chave do seu app em produção

Passo a passo: isolar a chamada do modelo e fazer a troca sem vazar pelo app

A ideia central é simples: se o formato do provedor só existe em UM arquivo, trocar de modelo é barato

Se ele está espalhado em controller, service, worker e teste, cada troca vira uma refatoração

  1. Crie uma fronteira única. Uma função (ou classe) que recebe mensagens, ferramentas, nível de esforço e teto de saída, e devolve texto, chamadas de ferramenta e uso. O resto do app não conhece mais nada além disso
   # unico ponto do app que sabe qual provedor esta em uso
   def chamar_modelo(mensagens, ferramentas, esforco, max_saida):
       if PROVEDOR == "claude":
           return _via_claude(mensagens, ferramentas, esforco, max_saida)
       return _via_openai(mensagens, ferramentas, esforco, max_saida)

   # formato normalizado que TODO o resto do app consome
   RESPOSTA = {
       "texto": "",
       "chamadas": [{"id": "", "nome": "", "args": {}}],
       "uso": {"entrada": 0, "saida": 0},
   }

O erro comum deste passo: deixar o formato do provedor vazar. No dia em que alguém der um if bloco["type"] == "tool_use" dentro de um handler de rota, a fronteira morreu

  1. Normalize o formato de mensagem. Na Messages API do Claude, system é um parâmetro de topo, separado das mensagens, e max_tokens é obrigatório na criação da mensagem. Na Responses API da OpenAI a conversa é uma lista de Items, não um array de mensagens com o system dentro
   # Claude: system fora das mensagens, max_tokens obrigatorio
   payload_claude = {
       "model": "claude-fable-5-1",
       "system": instrucao_do_sistema,
       "max_tokens": max_saida,   # sem isso, a criacao da mensagem nao passa
       "messages": mensagens,
   }

   # OpenAI Responses: a conversa e uma lista de Items
   # function_call e function_call_output sao Items DISTINTOS, ligados pelo call_id
   itens = montar_items(mensagens)

O erro comum deste passo: esquecer o max_tokens do lado do Claude, ou empurrar o system como primeira mensagem porque "sempre foi assim no outro provedor"

  1. Traduza o esforço. Os cinco níveis são os mesmos (low, medium, high, xhigh e max), o nome do parâmetro é que muda. E vale lembrar: no Claude o effort é um sinal comportamental, não um orçamento estrito de tokens, ou seja, em níveis baixos ele ainda pensa em problemas difíceis, só pensa menos
   NIVEIS = ("low", "medium", "high", "xhigh", "max")

   def traduzir_esforco(nivel, destino):
       if nivel not in NIVEIS:
           raise ValueError(f"nivel invalido: {nivel}")
       if destino == "claude":
           return {"effort": nivel}            # padrao da API e high
       if destino == "openai_responses":
           return {"reasoning": {"effort": nivel}}
       return {"reasoning_effort": nivel}      # Chat Completions

O erro comum deste passo: carregar um none herdado de outro modelo. O GPT-6 Astra não suporta o valor none

  1. Traduza as ferramentas. No Claude, a resposta traz um bloco tool_use com nome e argumentos JSON, e o resultado volta num bloco tool_result dentro de uma mensagem com role user, carregando o tool_use_id. E tem uma regra que pega muita gente: os blocos tool_result devem vir IMEDIATAMENTE depois dos tool_use correspondentes
   # Claude: resultado da ferramenta volta numa mensagem role user
   mensagem_resultado = {
       "role": "user",
       "content": [{
           "type": "tool_result",
           "tool_use_id": chamada["id"],   # o mesmo id que veio no tool_use
           "content": resultado_serializado,
       }],
   }

   # OpenAI Responses: dois Items separados, correlacionados pelo call_id
   item_saida = {
       "type": "function_call_output",
       "call_id": chamada["id"],
       "output": resultado_serializado,
   }

O erro comum deste passo: guardar o id da chamada num campo genérico e perder a correlação na volta. Guarde o id na sua estrutura normalizada e reidrate ele no formato certo de cada lado

  1. Decida o que fazer com o estado de raciocínio. Aqui não existe tradução limpa. Os thinking blocks do Fable 5.1 não são legíveis por modelos anteriores, e editar turnos anteriores invalida esses blocos. Do lado da OpenAI, os reasoning items trazem a propriedade encrypted_content com os tokens de raciocínio criptografados, que voltam via previous_response_id ou reenviando manualmente os output items da resposta anterior
   # trate o estado de raciocinio como BLOB OPACO do provedor
   # o app so guarda e devolve, nunca tenta ler ou reescrever
   estado = {
       "provedor": PROVEDOR,
       "blob": blob_do_provedor,   # thinking blocks ou reasoning items
   }

   if estado["provedor"] != PROVEDOR:
       estado = None   # trocou de lado? comeca a linha de raciocinio do zero

O erro comum deste passo: reaproveitar histórico entre provedores. Estado de raciocínio de um não é estado de raciocínio do outro, e no Claude ainda tem o detalhe de que mexer em turno passado invalida os blocks

  1. Escolha a estratégia de contexto cheio de cada lado. No Claude você tem compaction, que resume automaticamente o contexto antigo ao se aproximar do limite da janela, e context editing, que remove blocos tool_result antigos do histórico sem reiniciar a conversa. Na OpenAI você chama /responses/compact enviando a janela de contexto completa e recebe uma janela compactada, com um item de compactação criptografado que carrega o estado e o raciocínio anteriores

Repara que num dos caminhos você manda a janela INTEIRA pro provedor pra receber a versão compactada, e boa parte dessa janela costuma ser código do seu projeto. Se essa parte te deixa desconfortável, vale ler antes sobre quem vê o seu código quando ele sai da sua máquina

O erro comum deste passo: tratar as duas estratégias como a mesma coisa na sua camada. Uma corta histórico dentro da conversa, a outra é uma chamada a um endpoint

  1. Rode o mesmo conjunto de prompts nos dois caminhos antes de virar a chave. Mesma tarefa, mesmas ferramentas, mesmo nível de esforço, e compare custo, comportamento e tempo. É aqui que a camada isolada paga o investimento: você troca uma implementação, não o app
   for caso in SUITE_DE_PROMPTS:
       a = chamar_modelo(caso.mensagens, caso.ferramentas, "high", 8000)  # claude-fable-5-1
       b = chamar_modelo(caso.mensagens, caso.ferramentas, "high", 8000)  # gpt-6-astra
       registrar(caso.nome, a, b)

O erro comum deste passo: comparar com configurações diferentes e achar que descobriu algo sobre o modelo, quando descobriu algo sobre a sua config

Erros que aparecem na migração (e como prevenir)

Se liga nos casos que aparecem de verdade

Forced tool use retornando erro no Fable 5.1

Sintoma: a chamada que sempre funcionou volta com erro assim que você aponta pro claude-fable-5-1

Causa: forced tool use retorna erro nesse modelo

Solução: remover o tool_choice do tipo any ou tool, e mover a garantia de schema pra strict tool use com tool_choice do tipo auto, ou pra structured outputs

Thinking blocks inválidos depois de mexer no histórico

Sintoma: a conversa quebra depois que o seu código "limpa" ou reescreve mensagens antigas

Causa: editar turnos anteriores invalida os thinking blocks, e modelos anteriores não conseguem ler os thinking blocks do Fable 5.1

Solução: tratar histórico com raciocínio como imutável. Se precisa cortar contexto, use as ferramentas próprias pra isso (context editing e compaction) em vez de reescrever turno na mão

Cache hit caindo quando você mexe no esforço

Sintoma: você passou a variar o effort por requisição e o cache read despencou

Causa: alterar effort entre requisições afeta o cache

Solução: usar a mudança de effort por mensagem (mensagem com role system, em beta), suportada em Fable 5.1, Mythos 5.1 e Opus 5. Lembrando que o mínimo pra prompt caching no Fable 5.1 é de 512 tokens, então prompt curtinho nem entra nessa conta

tool_result fora de ordem ou sem tool_use_id

Sintoma: erro de formato na hora de devolver o resultado da ferramenta

Causa: o tool_result não veio imediatamente depois do tool_use correspondente, ou foi enviado sem o tool_use_id

Solução: na sua camada, emita o par na mesma função. Quem cria o resultado é quem já tem o id em mãos

call_id não correlacionado na Responses API

Sintoma: o modelo age como se a ferramenta nunca tivesse respondido

Causa: function_call e function_call_output são Items distintos, e o que liga os dois é o call_id

Solução: nunca gere id novo do seu lado. Propague o call_id que veio na chamada

Recusa em prompts de cibersegurança no GPT-6 Astra

Sintoma: prompts de segurança ofensiva que passavam no seu pipeline anterior voltam recusados

Causa: o GPT-6 Astra é o primeiro modelo da OpenAI a atingir o nível Critical de capacidade em cibersegurança no Preparedness Framework, e a versão liberada a usuários pagantes recusa certos prompts nessa área, incluindo criação de exploits de prova de conceito

Solução: não tem gambiarra aqui. Se o seu produto vive nessa área, isso é critério de decisão, não bug de integração

Prevenção que resolve os seis de uma vez

Escreva testes de contrato na camada isolada

Um teste que garante que toda chamada de ferramenta volta com id preservado, outro que garante que o nível de esforço traduzido é um dos cinco válidos, outro que garante que o app nunca vê um campo cru do provedor

É chato de escrever uma vez e salva toda troca futura

Quando a troca compensa e quando não vale mexer

Com a fronteira pronta, a decisão vira aritmética e caso de uso

Aplicação com muito cache read: aqui a diferença aparece. O cache read do Fable 5.1 sai por US$ 0,25 por milhão de tokens, e o do GPT-6 Astra por US$ 1 por milhão. Se o seu app repete um prompt gordo o dia inteiro, é nesse número que a conta se decide, porque entrada e saída custam igual nos dois (US$ 10 e US$ 50 por milhão)

Orquestração de várias ferramentas com loops e condições: isso encosta direto no Programmatic Tool Calling da Responses API, que permite ao modelo escrever e executar JavaScript pra coordenar as ferramentas do request, com chamadas em paralelo, loops e condições, e resultados intermediários em runtime hospedado. As ferramentas usam allowed_callers com valores direct e/ou programmatic. Não levantei equivalente direto confirmado do outro lado, então trate isso como diferencial de desenho

Pipeline em lote: se o seu trabalho é assíncrono e cabe em fila, o batch do Fable 5.1 sai por US$ 5 por milhão de entrada e US$ 25 por milhão de saída, metade do preço padrão

Contexto que vem do seu próprio código: boa parte do que enche a janela é repositório. Antes de brigar por preço de token, vale olhar como o seu contexto é montado, tipo manter o índice do código atualizado sem reindexar tudo a cada mudança

Trabalho ligado a segurança ofensiva: esbarra na versão restrita do Astra, como falei ali em cima

E os benchmarks? A OpenAI divulgou no anúncio do GPT-6 Astra 72,6% no OSWorld 2.0 de computer use, 97,6% no FrontierMath Tier 4 e 100% no ExploitBench

Isso é o que a empresa declarou, não é veredito meu nem seu

O veredito que vale pro seu app é o resultado da sua suíte de prompts rodando nos dois caminhos

Como foi rodar os dois modelos no mesmo projeto

Tem uma parte disso que eu já vivi na prática

No vídeo abaixo eu coloco dois modelos pra construir o MESMO projeto, com os mesmos prompts e as mesmas configurações sempre que possível, ambos no nível máximo de raciocínio

O projeto foi um SaaS chamado Insight AI, que transforma feedbacks de clientes em um dashboard de insights acionáveis, com stack Next, TypeScript e Tailwind

Montei quatro rounds, os três primeiros construindo o mesmo projeto, cada um avaliando um aspecto (design da landing page, autenticação e sistema base, e evolução do projeto)

O que ficou registrado em números: um dos modelos terminou a primeira etapa (landing page e estrutura base) em 11 minutos, enquanto o outro estava com 12 minutos rodando quando fui checar, e o mais lento passou de 20 minutos sem entregar de fato

A cota caiu de 100% para 83% só nessa primeira etapa 😅

E teve o clássico conflito de porta: um dos modelos tentou subir o projeto numa porta já ocupada por outro projeto meu, e eu precisei pedir pra ele subir em outra, indo parar na porta 32

Vi um dos lados disparar dois subagents em paralelo enquanto o outro ainda estava raciocinando, e vi um deles gerar imagens durante a construção da landing page pra usar como logo de cliente, coisa que o outro não fazia por padrão

No meio do teste eu tive que baixar o nível de raciocínio dos dois pra conseguir terminar sem esperar horas, e isso virou uma conclusão minha: raciocínio máximo raramente compensa no dia a dia

Eu mesmo costumo programar num nível acima do normal (alto, às vezes extra alto) porque tenho resultado mais rápido, qualidade que não percebo cair e consumo de cota menor

Importante: o vídeo testou a geração anterior desses modelos, então ele serve como leitura de COMPORTAMENTO (tempo, cota, como cada um conduz a execução) e não como benchmark do Fable 5.1 contra o GPT-6 Astra

E tem um ponto que amarra com o artigo inteiro: quando a chamada está isolada, comparar os dois deixa de ser reescrever o app e vira trocar uma implementação, sobrando só comportamento e tempo pra observar

Resumo e próximo passo

Trocar Fable 5.1 por GPT-6 Astra (e voltar) é barato quando existe uma única fronteira de chamada, e caro quando o formato do provedor está espalhado pelo app

Os preços de entrada e saída batem, o teto de saída bate, os cinco níveis de esforço batem no nome, e é justamente por isso que a diferença se concentra no que não bate: cache read, formato de ferramenta, estado de raciocínio e estratégia de contexto cheio

Próximo passo concreto pra hoje: abre o projeto e mapeia todo ponto que toca tool_choice, thinking ou reasoning

Move tudo isso pra uma camada só

Depois roda o mesmo conjunto de prompts nos dois modelos e compara custo, latência e comportamento antes de escolher um lado

É menos empolgante que trocar o model ID e torcer, mas é o que evita descobrir o problema em produção 😀

Até o próximo post!

Perguntas frequentes

O Claude Fable 5.1 e o GPT-6 Astra aceitam os mesmos níveis de esforço de raciocínio?

Sim, os dois aceitam low, medium, high, xhigh e max. A diferença é que o GPT-6 Astra não suporta o valor none, e o nome do parâmetro muda: effort no Claude, reasoning.effort na Responses API da OpenAI e reasoning_effort na Chat Completions. No Fable 5.1 o padrão da API é high, e o effort funciona como sinal comportamental, não como orçamento estrito de tokens.

Meu código usa tool_choice forçado, isso quebra ao migrar para o Claude Fable 5.1?

Quebra sim: forced tool use (tool_choice do tipo any ou tool) retorna erro no Fable 5.1. A saída recomendada é mover essa garantia de schema para strict tool use com tool_choice do tipo auto, ou usar structured outputs no lugar do forced tool use.

O preço de cache read é igual entre Claude Fable 5.1 e GPT-6 Astra?

Não. O Fable 5.1 cobra US$ 0,25 por milhão de tokens de cache read, enquanto o GPT-6 Astra cobra US$ 1 por milhão de tokens de entrada em cache. Como o preço de entrada e saída padrão é igual nos dois (US$ 10 e US$ 50 por milhão), é justamente o cache que muda a conta final de custo.

Como cada modelo lida com o contexto quando a conversa fica muito longa?

O Claude Fable 5.1 tem compaction, que resume automaticamente o contexto antigo perto do limite da janela, e context editing, que remove blocos tool_result antigos sem reiniciar a conversa. O GPT-6 Astra usa o endpoint /responses/compact, que recebe a janela completa e devolve uma versão compactada com um item de compactação criptografado carregando o estado e o raciocínio anteriores.

O GPT-6 Astra recusa algum tipo de pedido depois do lançamento público?

Sim, na área de cibersegurança. Ele foi o primeiro modelo da OpenAI a atingir o nível Critical de capacidade em cibersegurança no Preparedness Framework, e a versão liberada a usuários pagantes recusa certos prompts nessa área, incluindo a criação de exploits de prova de conceito.

Vale usar o modo batch do Claude Fable 5.1 para baratear a migração?

Se o seu fluxo tolera processamento assíncrono, sim: o batch do Fable 5.1 sai por US$ 5 por milhão de tokens de entrada e US$ 25 por milhão de saída, metade do preço da chamada síncrona (US$ 10 e US$ 50). Vale planilhar isso antes de comparar custo direto com o GPT-6 Astra, que na API padrão da OpenAI não entra nessa conta de batch.




Escrito por | Matheus Battisti

Matheus Battisti
Fundador da Hora de Codar

Programador apaixonado pelo mundo das tecnologias, sempre buscando em aprender e se aprofundar em linguagens, frameworks e o que mais for necessário para executar um bom trabalho. Agora tem uma nova missão que é de passar seu conhecimento adiante para formar novos programadores e especializar mais os que já são.

Subscribe
Notify of
guest

0 Comentários
Oldest
Newest Most Voted

Formações

Formação Vibe Coding

Formação Vibe Coding

Do Prompt ao Produto: Crie Software Real com IA

  • 474 aulas
  • 20 projetos
  • 39h 27min

Blog | Mais populares