Tratamento de erros em tool calling de LLM: guia de arquitetura
Quem já testou um agente de IA chamando uma API externa sabe: no notebook local tudo funciona bonito. Em produção é outra história. Se você jogar toda a responsabilidade de tratar erro de chamada de ferramenta nas costas do próprio modelo, seu pipeline vai quebrar assim que o serviço conectado engasgar.
Um guia recente do time do n8n propõe uma defesa em camadas para isso, separando o que é responsabilidade da orquestração e o que é responsabilidade do modelo. Faz todo sentido dividir assim: infraestrutura resolve infraestrutura, raciocínio resolve raciocínio.
Quatro tipos de falha, quatro respostas diferentes
O material classifica as falhas de tool calling em quatro categorias e recomenda uma camada responsável para cada uma:
- Falhas de transporte e rede: conexão TCP caiu, timeout de DNS, HTTP 503. São transitórias e a camada de orquestração deve resolver sozinha, com retry de rede. O modelo nem precisa saber que isso aconteceu.
- Erros de serviço externo: rate limit (429) ou erro interno do provedor (500). Aqui a orquestração precisa ler os headers da resposta, respeitar o Retry-After e só então tentar de novo.
- Falhas de validação de entrada: schema errado, parâmetro faltando, 400 Bad Request. Como o payload está estruturalmente errado, só o modelo pode corrigir a chamada, não tem retry de infraestrutura que resolva isso.
- Erros de lógica ou formato de saída inesperado: query que devolve zero registros, JSON malformado. O modelo precisa ler esse resultado, entender que algo saiu fora do esperado e decidir o próximo passo: trocar de ferramenta, mudar de rota ou escalar para um humano.
Misturar essas categorias é o jeito mais rápido de derrubar um agente em produção. Se você trata um 400 como se fosse um 503, vai ficar repetindo a mesma chamada inválida até esgotar as tentativas.
Retry com backoff exponencial e jitter
Para as falhas transitórias, o guia recomenda o padrão consagrado: backoff exponencial combinado com jitter completo, técnica que a própria AWS documentou. Sem jitter, várias instâncias tentam de novo no mesmo instante e você recria o thundering herd, um monte de retry batendo na API ao mesmo tempo. Com jitter, os intervalos ficam espalhados e a carga fica mais suave.
Vale também parsear o header Retry-After quando o serviço externo mandar. Ignorar isso e confiar só no seu backoff interno é receita para continuar sendo bloqueado.
Erro como dado, não como exceção jogada fora
Em vez de capturar a exceção e simplesmente abandonar a execução, formate o erro como uma string estruturada e devolva como resultado da tool call, associado ao id da chamada original.
Essa é a parte que eu acho mais prática do artigo. É comum ver time capturando o erro, cortando a execução e perdendo o contexto todo. Devolvendo o erro formatado como resultado de tool call, o próprio modelo lê aquilo como dado de entrada e decide o que fazer a seguir, seja tentar de outro jeito, seja escalar para revisão humana.
No fim, a receita não tem segredo: separar bem o que é problema de rede do que é problema de raciocínio, automatizar o retry de infraestrutura e devolver contexto de erro suficiente para o modelo trabalhar. Nada de esperar que o LLM adivinhe por que uma API caiu.