Como rotear requisições entre Sonnet 5.5 e Opus 5.5 automaticamente na API

Ilustração de um roteador de modelos Claude direcionando requisições entre Sonnet 5.5 e Opus 5.5

Um roteador de modelos Claude é uma função no seu backend que decide qual modelo atende cada requisição. Antes de chamar a API, ela classifica a tarefa (por regra fixa ou com um modelo barato como o Haiku 5.5), escolhe entre claude-sonnet-5-5 e claude-opus-5-5 e define o nível de esforço em output_config.effort. Depois, registra o model e o usage da resposta para você comparar qualidade e custo.

Este tutorial é para quem já sabe quando usar Sonnet ou Opus na mão e agora quer que a própria aplicação tome essa decisão. Um roteador não economiza nada por definição: a economia só existe se você medir com o tráfego real do seu app.

O que você precisa antes de montar o roteador

O mínimo é ter acesso à Claude API e usar um SDK oficial. Os exemplos abaixo estão em Python, com client.messages.create, que é a forma que a documentação usa para o parâmetro de esforço.

Separe também estes itens:

  • IDs de modelo corretos: claude-opus-5-5 (Opus 5.5), claude-sonnet-5-5 (Sonnet 5.5) e claude-haiku-5-5 (Haiku 5.5), este último para servir de classificador.
  • Parâmetro de esforço: ele vai no corpo da requisição, em output_config.effort. Segundo a documentação de effort, está disponível em todos os modelos suportados sem header beta.
  • Uma amostra de requisições reais do seu app: sem isso você inventa regra no escuro. Pegue pedidos de verdade e anote o que cada um exige.

Se o seu código ainda chama um modelo antigo e você vai migrar junto, vale revisar o que muda ao trocar para o Sonnet 5.5 na API antes de colocar um roteador por cima.

Que tipo de requisição vai para o Sonnet 5.5 e qual vai para o Opus 5.5

A regra de roteamento sai do posicionamento oficial dos dois modelos. O Sonnet 5.5 é descrito como complemento mais rápido e mais barato ao Opus 5.5. Ele é forte em tarefas do dia a dia bem delimitadas (código, agentes, trabalho de conhecimento) e em tarefas de agente bem definidas, como investigação, revisão e rascunho.

O Opus 5.5 é feito para trabalho agêntico de longa duração. A documentação cita agentes de código autônomos rodando por horas, refatoração em larga escala, engenharia de sistemas complexos e fluxos com muita visão e computer use.

Traduzindo isso para categorias de um app:

Tipo de requisiçãoModelo
Correção pontual, revisão de PR, investigação, rascunho de textoclaude-sonnet-5-5
Agente que roda por muito tempo sozinhoclaude-opus-5-5
Refatoração que atravessa muitos arquivosclaude-opus-5-5
Fluxo pesado em imagem ou computer useclaude-opus-5-5

O tamanho do pedido não serve de critério. Os dois modelos têm 1M tokens de contexto e 128K tokens de saída máxima, então o que decide é a natureza da tarefa.

Essa ideia é documentada pela própria Anthropic. No guia Optimizing for cost and intelligence, a recomendação é decompor a tarefa e mandar cada parte ao modelo mais barato capaz de resolvê-la. Planejamento e julgamento tendem a pedir modelo maior, e execução mecânica pode ir para o Haiku ou nem precisar de modelo.

O mesmo guia cita dois padrões multimodelo: um executor que escala decisões difíceis para um advisor, e um orquestrador que delega trabalho em volume para workers mais baratos. O roteador deste tutorial é a versão mais simples disso, uma decisão por requisição.

E o preço? Pela tabela oficial, o Opus 5.5 custa US$ 4 por milhão de tokens de entrada e US$ 20 por milhão de saída. O Sonnet 5.5 sai por US$ 2 e US$ 10. A diferença por token existe, mas o custo final depende de quantos tokens cada modelo gasta nas suas tarefas, e isso só o seu log responde.

Como montar o roteador passo a passo

O fluxo tem cinco partes: classificar, escolher modelo e esforço, chamar, tratar falha e registrar. O código abaixo é um exemplo didático para você adaptar, não uma implementação pronta para produção.

  1. Classifique pela heurística do próprio app. O jeito mais barato de classificar é não chamar modelo nenhum. Seu app geralmente já sabe muita coisa sobre o pedido: de qual endpoint veio, se tem imagem, se vai rodar como agente com ferramentas.
    def classificar_por_heuristica(req):
        # req é um dict montado pelo seu app (exemplo didático)
        if req.get("tem_imagem") or req.get("usa_computer_use"):
            return "visao_ou_computer_use"
        if req.get("agentico") and req.get("execucao_longa"):
            return "agente_longo"
        if req.get("endpoint") == "/refatorar-projeto":
            return "refatoracao_ampla"
        if req.get("endpoint") in {"/revisar", "/investigar", "/rascunho", "/corrigir-bug"}:
            return "tarefa_delimitada"
        return None  # sem sinal claro: segue para o classificador

    O resultado esperado é um rótulo para a maioria dos pedidos e None só nos casos ambíguos. Um endpoint de correção de bug, por exemplo, cai no Sonnet porque é tarefa delimitada, e o prompt pode reforçar isso com instruções para corrigir bug sem reescrever tudo.

    O erro comum deste passo: regra vaga do tipo "se o texto for grande, vai pro Opus" ou "se mencionar código, vai pro Opus". Essas regras parecem prudentes e acabam mandando quase tudo para o modelo mais caro.

  2. Use o Haiku 5.5 quando a heurística não decidir. Para os pedidos que sobraram com None, um modelo barato lê o texto e devolve só um rótulo. A Anthropic tem um guia oficial de ticket routing que serve de referência para usar o Claude como classificador.

    O Haiku 5.5 custa US$ 0,10 por milhão de tokens de entrada e US$ 0,50 por milhão de saída em prompts de até 100K tokens, e um prompt de classificação curto fica bem abaixo disso.

    import anthropic
    
    client = anthropic.Anthropic()
    
    ROTULOS_VALIDOS = {
        "tarefa_delimitada",
        "agente_longo",
        "refatoracao_ampla",
        "visao_ou_computer_use",
    }
    
    PROMPT_CLASSIFICADOR = """Classifique o pedido abaixo em UM destes rótulos:
    tarefa_delimitada, agente_longo, refatoracao_ampla, visao_ou_computer_use.
    Responda somente com o rótulo, sem explicação.
    
    Pedido:
    {pedido}"""
    
    def classificar_com_haiku(texto, **parametros_extras):
        resposta = client.messages.create(
            model="claude-haiku-5-5",
            messages=[{"role": "user", "content": PROMPT_CLASSIFICADOR.format(pedido=texto)}],
            **parametros_extras,  # inclua os demais parâmetros obrigatórios da Messages API
        )
        rotulo = resposta.content[0].text.strip().lower()
        if rotulo not in ROTULOS_VALIDOS:
            return "tarefa_delimitada"  # valor padrão definido por você
        return rotulo

    Para checar, rode o classificador nas requisições da sua amostra e compare com a classificação que você faria na mão.

    O erro comum deste passo: aceitar a saída do classificador sem validar. Se o modelo responder com uma frase, um rótulo com acento ou algo fora da lista, o roteador quebra ou manda o pedido para lugar nenhum. Por isso o código checa contra ROTULOS_VALIDOS e tem um valor padrão.

  3. Mapeie cada rótulo para modelo e esforço. Aqui entra o segundo botão do roteador. Os níveis de esforço são low, medium, high, xhigh e max, suportados no Opus 5.5 e no Sonnet 5.5.

    A documentação indica high para raciocínio complexo, código e tarefas agênticas em que qualidade importa mais que velocidade ou custo. xhigh fica para as tarefas de código e agênticas mais difíceis, max é capacidade máxima sem limite de gasto de tokens, e low é o mais eficiente, com economia significativa de tokens.

    ROTAS = {
        "tarefa_delimitada": ("claude-sonnet-5-5", "medium"),
        "agente_longo": ("claude-opus-5-5", "high"),
        "refatoracao_ampla": ("claude-opus-5-5", "xhigh"),
        "visao_ou_computer_use": ("claude-opus-5-5", "medium"),
    }
    
    def chamar_modelo(rotulo, messages, **parametros_extras):
        modelo, esforco = ROTAS.get(rotulo, ROTAS["tarefa_delimitada"])
        resposta = client.messages.create(
            model=modelo,
            messages=messages,
            output_config={"effort": esforco},
            **parametros_extras,
        )
        return modelo, esforco, resposta

    Os pares da tabela são um ponto de partida para você ajustar com dados, não uma recomendação medida. Se você não mandar effort, cada modelo usa o padrão dele: high no Sonnet 5.5 e medium no Opus 5.5. Ou seja, o Sonnet sem configuração já roda num esforço maior que o Opus sem configuração.

    O esforço afeta TODOS os tokens da resposta: texto, explicações, chamadas de ferramenta e seus argumentos, e o thinking quando está ativo. No Opus 5.5 o adaptive thinking fica sempre ligado, e no Sonnet 5.5 vem ligado por padrão. Mexer no esforço muda o custo da resposta inteira, não só o texto final.

    O erro comum deste passo: subir para max "por garantia". Como max não tem limite de gasto de tokens, ele é para casos raros, não para uma rota inteira.

  4. Trate falhas com fallback consciente. Dois erros da API importam para o roteador, conforme a página de erros. O 529 overloaded_error indica API temporariamente sobrecarregada, o que pode acontecer com tráfego alto entre todos os usuários.

    O 429 rate_limit_error indica limite de taxa ou teto de gasto do tier. Quando vem com o header retry-after, basta esperar aquele número de segundos. Já o 429 de teto de gasto do tier não traz retry-after e continua falhando até o acesso voltar.

    Os SDKs oficiais já repetem falhas transitórias (erro de conexão, rate limit, 5xx) com backoff exponencial, 2 vezes por padrão, respeitando o retry-after. Cada cliente tem uma opção de máximo de retentativas para ajustar ou desligar esse comportamento. O seu código entra só depois que o SDK desistiu.

    def chamar_com_fallback(rotulo, messages, **parametros_extras):
        try:
            modelo, esforco, resposta = chamar_modelo(rotulo, messages, **parametros_extras)
            return modelo, esforco, resposta, False
        except Exception as erro:  # troque pela exceção com status HTTP do seu SDK
            status = getattr(erro, "status_code", None)
            modelo_original, _ = ROTAS.get(rotulo, ROTAS["tarefa_delimitada"])
            if status == 529 and modelo_original == "claude-opus-5-5":
                # decisão de produto: degradar para o Sonnet em vez de falhar
                modelo, esforco, resposta = chamar_modelo("tarefa_delimitada", messages, **parametros_extras)
                return modelo, esforco, resposta, True
            raise  # 429 de teto de gasto não se resolve trocando de modelo

    Cair do Opus para o Sonnet é uma decisão de produto. Para um agente de horas, talvez seja melhor falhar e reagendar do que entregar um resultado pior. O flag True no retorno serve para você saber depois quantas respostas vieram de fallback.

    O erro comum deste passo: empilhar um loop de retentativa próprio em cima do SDK sem ajustar a opção de máximo de retentativas do cliente. Aí cada falha vira uma cascata de chamadas, e num 429 de teto de gasto você só bate na mesma parede várias vezes.

  5. Registre tudo o que precisa para comparar. Sem log, o roteador vira achismo automatizado. A Messages API devolve o campo model e o objeto usage com input_tokens, output_tokens, cache_creation_input_tokens e cache_read_input_tokens. O total de entrada é a soma desses três campos de entrada.
import json
import time

def registrar(rotulo, modelo_pedido, esforco, resposta, fallback):
    u = resposta.usage
    criacao_cache = u.cache_creation_input_tokens or 0
    leitura_cache = u.cache_read_input_tokens or 0
    registro = {
        "ts": time.time(),
        "rotulo": rotulo,
        "modelo_pedido": modelo_pedido,
        "modelo_resposta": resposta.model,
        "esforco": esforco,
        "fallback": fallback,
        "input_tokens": u.input_tokens,
        "cache_creation_input_tokens": criacao_cache,
        "cache_read_input_tokens": leitura_cache,
        "entrada_total": u.input_tokens + criacao_cache + leitura_cache,
        "output_tokens": u.output_tokens,
        "nota_qualidade": None,  # preenchida depois, na revisão manual
    }
    print(json.dumps(registro))  # troque pelo seu sistema de logs

Para conferir, faça uma chamada de cada rota e veja se modelo_resposta bate com modelo_pedido e se os campos de usage estão preenchidos.

O erro comum deste passo: estimar custo contando o texto que aparece na tela. Os tokens em usage não batem 1 para 1 com o conteúdo visível da requisição e da resposta, porque a saída passa por uma etapa de parsing. Calcule custo sempre a partir do usage.

Como saber se o roteamento está funcionando

A checagem final é olhar os logs agrupados por rótulo. Para cada categoria, compare a nota de qualidade, o volume de tokens e o custo calculado a partir do usage. Só depois disso dá para dizer se o roteador ajudou ou se só complicou o código.

Alguns sintomas aparecem rápido:

  • Quase tudo indo para o Opus. A causa costuma ser uma regra larga demais, na heurística ou no prompt do classificador. Abra os pedidos classificados como agente_longo ou refatoracao_ampla e veja quantos eram tarefas delimitadas.
  • Queixas de qualidade numa categoria roteada ao Sonnet. Antes de trocar o modelo, suba o esforço daquela rota. Se você colocou medium, lembre que o padrão do Sonnet 5.5 é high, então talvez você mesmo tenha baixado a qualidade.
  • Muitos 429 sem retry-after. Isso aponta para o teto de gasto do tier, não para sobrecarga momentânea. Trocar de modelo no fallback não resolve.
  • Muitas respostas com fallback verdadeiro. O Opus está sendo trocado com frequência, então a qualidade daquela rota no log não representa o Opus. Separe essas linhas na análise.

Para prevenir, mantenha uma amostra de revisão manual: algumas respostas por rótulo, avaliadas por alguém que entende da tarefa, preenchendo nota_qualidade. Ajuste as regras a partir do que os dados mostram, nunca pela intuição de que "o Opus é melhor em tudo".

E se parte do trabalho não precisa de resposta na hora? Relatórios noturnos, reprocessamento e classificação em lote podem ir para a Batch API, que dá 50% de desconto em entrada e saída para trabalho que pode esperar até 24 horas. É outra camada de roteamento, por urgência em vez de dificuldade.

Próximo passo: comece pela heurística e meça

Escolha UMA rota do seu app, de preferência uma com volume e com tarefas variadas. Implemente só o passo 1 (heurística), o mapeamento de modelo e esforço e o logging, deixando o classificador com Haiku de fora por enquanto.

Rode assim por um período, preencha a nota de qualidade de uma amostra e compare as categorias. Se sobrarem muitos pedidos sem rótulo, aí vale colocar o Haiku na frente. Se uma categoria estiver mal, mexa primeiro no esforço, depois no modelo.

Com os números da sua própria aplicação, você vai saber se o roteador compensa, e quanto.

Perguntas frequentes

O roteador de modelos funciona também fora da Claude API, tipo no Bedrock?

O tutorial usa o SDK oficial chamando a Claude API direto, mas o Opus 5.5 também está disponível no Amazon Bedrock, no Claude Models on Google Cloud, no Microsoft Foundry e no Claude Platform on AWS. A lógica de classificar, escolher modelo e esforço é a mesma, mas os parâmetros de chamada mudam de plataforma para plataforma, então vale checar a documentação específica de cada uma antes de portar o código.

Dá para rotear só o nível de esforço, sem trocar de modelo?

Sim. Nada impede manter o mesmo modelo, por exemplo o Sonnet 5.5, e variar apenas o output_config.effort entre low e high conforme a complexidade do pedido. Isso é uma versão mais simples do roteador deste tutorial, útil quando os dois tipos de tarefa cabem no mesmo modelo e só a profundidade do raciocínio muda.

Fontes consultadas

Consulta em .

Encontre outros guias no YouTube da Hora de Codar. Se quiser aprofundar o contexto, veja Dizem que o Sonnet 5.5 bateu o Opus 5.5, será? Teste completo.

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.

Formações

Formação Vibe Coding

Formação Vibe Coding

Do Prompt ao Produto: Crie Software Real com IA

  • 474 aulas
  • 20 projetos
  • 39h 30min

Blog | Mais populares