O provedor de LLM pode aceitar uma requisição e falhar antes de sua aplicação receber a resposta. Se o runtime mandar a mesma rodada para outro provedor sem verificar o estado, a resposta reserva pode gerar uma segunda tool call. Para efeitos externos, isso pode significar uma cobrança repetida, uma mensagem duplicada ou uma alteração aplicada duas vezes.
A forma segura de fazer fallback é separar três coisas: a tentativa de obter uma decisão do modelo, a intenção da ação da aplicação e a execução do efeito externo. Essa separação é o complemento prático da execução durável para agentes de IA. Cada tentativa de modelo pode ter seu próprio identificador, mas a ação precisa manter uma chave criada pela aplicação. O runtime então classifica o erro, respeita um limite de tempo e custo, troca de provedor somente quando a capacidade é compatível e confirma o estado antes de repetir.

Resposta curta
- Retry repete uma tentativa de modelo; fallback troca o provedor; parada registra que não há evidência suficiente para continuar.
- Um timeout depois do envio é estado desconhecido, não prova de que a ação não aconteceu.
- A chave de ação pertence ao seu runtime e deve chegar ao executor da tool call quando o efeito puder ser repetido.
- O provedor reserva precisa cumprir o contrato de capacidade, formato e autorização antes de assumir a rodada.
O que o fallback precisa decidir?
O fallback não é apenas uma lista de provedores em ordem. É uma política para quatro estados: erro antes de o modelo processar a requisição, erro transitório sem efeito externo conhecido, resposta inválida e resultado ambíguo depois que a aplicação pode ter iniciado uma ação. Cada estado tem uma saída diferente.
Se a falha for transitória e a operação ainda for uma tentativa de modelo sem efeito externo, o runtime pode tentar de novo dentro do orçamento. Se o provedor estiver indisponível, pode mudar para outro que cumpra o mesmo contrato. Se a resposta for inválida, o runtime deve validar ou encerrar. Se uma tool call puder ter sido executada, deve consultar o estado ou aguardar uma confirmação antes de repetir.
Esse limite entre decisão e efeito é a parte que conecta o fallback à camada durável. Checkpoints preservam o que a execução sabe; eles não transformam automaticamente uma operação externa em idempotente.
Quando o erro permite retry ou fallback?
Comece pelo contrato do provedor, não por um catch que trata tudo como retryable. A documentação de códigos de erro da OpenAI separa limites de taxa e falhas temporárias de problemas de autenticação, configuração, cobrança e quota. A documentação de troubleshooting do Gemini também recomenda backoff com limite para erros transitórios e desaconselha repetir automaticamente erros de requisição ou permissão.
Uma classificação inicial pode ser esta:
| Estado observado | Ação preferível | O que ainda precisa ser confirmado |
|---|---|---|
| Rate limit ou indisponibilidade antes de uma tool call | Retry limitado ou fallback | Orçamento, prazo e capacidade do provedor reserva |
| Erro de autenticação, permissão, schema ou configuração | Parar e corrigir configuração | Se uma credencial diferente é autorizada fora do loop |
| Timeout enquanto só a resposta do modelo era esperada | Consultar a política e tentar com limite | Se a requisição foi aceita e se há cobrança por tentativa |
| Timeout depois de solicitar um efeito externo | Não repetir cegamente | Estado da ação, chave de idempotência ou consulta de operação |
| Resposta reserva sem a ferramenta ou formato exigido | Parar ou pedir nova decisão | Compatibilidade real, não apenas nome semelhante do modelo |
Os códigos não são uma política universal. SDKs podem aplicar retries próprios, proxies podem esconder respostas e provedores podem alterar detalhes. Registre a categoria original e a decisão tomada para que uma troca silenciosa não pareça sucesso.
Como separar a chamada do modelo da tool call?
Uma resposta do modelo é uma proposta. A aplicação deve transformar essa proposta em uma intenção de ação somente depois de validar nome, argumentos, autorização e estado da tarefa. A documentação de tool use da Anthropic expõe um identificador próprio para o bloco tool_use, mas esse identificador descreve a mensagem do provedor. Ele não substitui o identificador da ação no seu domínio.
O fluxo pode conservar dois identificadores:
modelAttemptIdidentifica a tentativa com um provedor e modelo.actionIdidentifica a intenção lógica, comoenviar-pedido-847, independentemente de quantas respostas foram obtidas.- O executor grava
actionIdantes de aplicar o efeito e devolve o resultado já conhecido quando a mesma ação chega novamente. - Um timeout mantém o estado como
unknownaté uma consulta, callback ou reconciliação mudar essa evidência.
O trecho abaixo é ilustrativo. Ele mostra a fronteira de decisão, não um roteador pronto para produção e não foi executado contra um provedor real.
type ActionState = "not_started" | "running" | "succeeded" | "failed" | "unknown";
type ProviderResult = {
kind: "answer" | "tool_call" | "error";
retryable?: boolean;
actionState?: ActionState;
};
async function resolveTurn(actionId: string): Promise<ProviderResult> {
const existing = await actionStore.read(actionId);
if (existing?.state === "succeeded") {
return { kind: "answer", actionState: "succeeded" };
}
const attempt = await askProviderWithBudget();
if (attempt.kind === "error" && attempt.retryable && !attempt.actionState) {
return failoverOnceWithTheSameAction(actionId);
}
if (attempt.kind === "tool_call") {
return executeWithIdempotencyKey(actionId, attempt);
}
return attempt;
}
O ponto importante não é o nome das funções. É impedir que failoverOnceWithTheSameAction repita uma ferramenta que já pode ter sido aceita. A ferramenta precisa conhecer o actionId, ou o runtime precisa consultar o estado em um serviço que conheça essa chave.
Para aprofundar a fronteira de schema e erro antes da execução, veja como validar tool calls em TypeScript. Validar o formato não prova que a ação ainda não foi aplicada, mas reduz a chance de mandar uma resposta incompatível ao executor.
Como limitar tempo, custo e tentativas?
Um fallback sem orçamento pode transformar uma indisponibilidade em uma sequência de chamadas caras e lentas. Defina um deadline para a rodada, um número máximo de tentativas e um teto de gasto que o runtime possa verificar antes de chamar outro provedor. O limite precisa ser compartilhado pela rodada, não reiniciado a cada salto.
O backoff deve respeitar a orientação do provedor e o prazo restante. Um retry com atraso que ultrapassa o deadline não é resiliência; é uma forma de entregar um erro mais tarde. Também registre o provedor, modelo, tentativa, classe do erro e duração. Essa trilha permite saber se o fallback economizou uma falha ou apenas acumulou custo.
Se a chamada de uma ferramenta ficar pendurada, o cancelamento tem uma fronteira própria. Cancelar um agente quando uma tool trava pode liberar o worker, mas não apaga um efeito que já chegou ao sistema externo. O próximo passo deve ser reconciliação, não uma repetição automática.
Como validar o provedor reserva?
Dois modelos podem responder no mesmo formato geral e ainda assim não oferecer a mesma capacidade. Antes de trocar, compare as ferramentas permitidas, o schema de argumentos, o limite de contexto, o comportamento de streaming, as políticas de segurança e a forma como erros são expostos. Se o provedor reserva não consegue executar a ferramenta exigida, retornar texto não é um fallback bem-sucedido.
Faça a validação em duas camadas. Primeiro, confirme que a resposta obedece ao contrato sintático. Depois, confirme que a decisão pode avançar na regra de negócio. O guia de validação de tool calls detalha por que um tipo TypeScript ou um JSON válido não prova que o resultado é seguro para o próximo passo.
O fallback também precisa manter o contexto que importa e descartar o que aumenta risco sem ajudar na decisão. Não envie segredos de uma integração para um provedor que não está autorizado a operar aquela ferramenta. Quando a capacidade não for equivalente, a saída honesta é parar ou pedir aprovação, não adaptar silenciosamente a ação.
Como registrar uma troca sem esconder o problema?
Use uma única identidade para a execução lógica e uma lista de tentativas dentro dela. Cada tentativa deve registrar provedor, modelo, motivo da saída, duração, tokens quando disponíveis, estado da ferramenta e decisão seguinte. Evite armazenar prompts ou argumentos sensíveis no log só para provar que houve fallback.
Uma métrica de sucesso isolada também engana. Observe quantas rodadas terminaram, quantas precisaram de troca, quantas ficaram em estado desconhecido e quantos efeitos exigiram reconciliação. A observabilidade de agentes de código no CI usa a mesma ideia de separar a execução lógica dos eventos que a compõem.
Quando o fluxo fica longo, uso o RemoteCode como minha ferramenta para trabalhar com sessões de agentes e manter esse tipo de contexto operacional visível. Isso descreve meu uso da ferramenta, não um benchmark deste artigo nem uma recomendação para um provedor específico.
Como testar o caminho de falha?
Não comece testando apenas se o provedor reserva respondeu. Teste se o runtime preserva a identidade da ação e para quando não consegue provar o estado. Um fake provider e um fake executor permitem exercitar as decisões sem enviar mensagens ou cobranças reais.
| Cenário | Resultado esperado |
|---|---|
| Provedor principal retorna rate limit antes da decisão | Uma nova tentativa dentro do orçamento ou troca registrada |
| Principal falha e reserva não oferece a tool exigida | Parada explícita por incompatibilidade |
| Timeout antes da resposta do modelo, sem ação iniciada | Retry limitado conforme deadline |
Timeout depois de enviar uma ação com actionId |
Consulta de estado ou unknown, nunca duplicação cega |
| Resposta reserva tem argumentos inválidos | Rejeição antes do executor |
| Todas as tentativas excedem o deadline | Falha observável com o motivo original e o estado da ação |
O teste mais valioso é o de ambiguidade: faça o executor aceitar a ação, descarte a resposta e simule um timeout. Uma segunda tentativa com o mesmo actionId deve devolver o resultado já registrado ou exigir reconciliação. Se ela cria um novo efeito, o fallback ainda está acoplado ao retry da mensagem.
Perguntas frequentes
Um fallback sempre deve trocar de provedor?
Não. Um erro de configuração, permissão, schema ou regra de negócio não fica correto por trocar de fornecedor. Troque apenas quando o erro for compatível com a política, o prazo permitir e o provedor reserva cumprir o contrato da rodada.
Posso repetir uma tool call depois de um timeout?
Não sem evidência adicional. Trate o efeito como desconhecido, consulte o estado ou use uma chave de idempotência que o sistema externo realmente respeite. Um timeout local informa o que seu cliente viu, não o que o servidor concluiu.
Uma chave de idempotência resolve tudo?
Não. A orientação da AWS sobre APIs idempotentes explica que o serviço precisa registrar a intenção e a operação de forma consistente para reconhecer uma repetição. A prática recomendada do Well-Architected também trata a chave como parte do contrato do serviço, não como um campo decorativo enviado pelo cliente.
Conclusão
Um fallback confiável começa com uma pergunta simples: o que exatamente pode ter acontecido antes da troca? Se a resposta for apenas uma tentativa de modelo, retry ou failover limitado pode ser suficiente. Se uma tool call entrou em estado desconhecido, preserve a ação, consulte o efeito e só então decida o próximo passo.
Esse desenho não depende de um provedor específico. Ele exige uma política explícita de erro, orçamento, capacidade, validação, idempotência e observabilidade. Sem essas fronteiras, o fallback pode melhorar a disponibilidade no painel e piorar a integridade do sistema.
Fontes consultadas
- OpenAI Developers, Error codes, consultada em 27/08/2026.
- Google AI for Developers, Troubleshooting, consultada em 27/08/2026.
- Anthropic, Implement tool use, consultada em 27/08/2026.
- AWS Builders' Library, Making retries safe with idempotent APIs, consultada em 27/08/2026.
- AWS Well-Architected, Prevent interaction failure with idempotent APIs, consultada em 27/08/2026.