Conteúdo da trilha
7 minNarração em inglês, legenda em portuguêsPodcast (RSS)
Capítulos
  1. 0:00Abertura
  2. 0:45O diagnóstico
  3. 1:39Por que acontece
  4. 2:23Quanto custa
  5. 3:11Um desafio
  6. 3:58O tratamento
  7. 5:32Quando ignorar
  8. 6:17Fechamento
Transcrição

Abertura

São duas da manhã. Um assistente financeiro tenta agendar um Pix para um cliente. O banco diz não.

O código pega o erro, espera um pouco e tenta de novo. E de novo. Quatro vezes, a mesma resposta: o limite noturno foi excedido.

Na quinta tentativa, o limite tinha acabado de virar, e a transferência passou. Mas o cliente já tinha sido avisado da falha. Então pagou de novo, pelo app do banco. Pagou duas vezes.

O retry funcionou. Esse é o problema. Nesta aula, você vai aprender a separar o erro que vale tentar de novo do erro que é um não, e por que essa diferença tem que morar no seu código.

O diagnóstico

O formato é este. A chamada sai.

Qualquer erro volta, e todo erro é tratado do mesmo jeito.

A mesma chamada é repetida, com os mesmos argumentos, sem ninguém perguntar por que falhou.

E quando finalmente passa, o efeito pode acontecer duas vezes, ou na hora errada.

O limite noturno não é uma oscilação de rede. É uma regra de negócio que quer dizer: agora não. Insistir até o relógio virar transforma esse não num efeito que ninguém pediu.

Esse smell se esconde em dois lugares. No código, é um tratamento que pega qualquer exceção e repete.

Num agente, é o modelo. Ele lê a palavra erro e chama a mesma ferramenta de novo, com os mesmos argumentos. Nos dois casos, quem decidiu repetir nunca classificou o erro.

Por que acontece

Embrulhar uma chamada num loop de retry é a receita mais conhecida para rede instável. Parece proteção. E a receita vaza para erros que ela nunca deveria pegar: sem saldo, sem permissão, entrada inválida.

O erro volta como texto, sem tipo. O seu código não distingue tente de novo de isso nunca vai funcionar.

O agente aprende a insistir. Se a ferramenta só diz erro, ela parece quebrada, e o modelo faz o razoável. Tenta de novo.

E ninguém pensou em idempotência. A ferramenta foi escrita como se toda chamada fosse única. Aí um timeout que aconteceu depois de o banco aceitar a transferência vira uma segunda transferência.

Quanto custa

O pior custo é o efeito duplicado. Dois pagamentos, dois emails, dois pedidos. Num pagamento, o estorno vira horas de suporte, e um cliente que deixa de confiar em você.

Depois, o efeito na hora errada. Um retry que se recupera de um limite noturno agenda um pagamento que o usuário já considerava cancelado.

Depois, desperdício. Imagine dez mil pedidos recusados por dia, cada um tentado cinco vezes. São quarenta mil chamadas a mais, todas inúteis. E martelar um serviço com problema pode te render um bloqueio, ou piorar a queda dele.

E o diagnóstico fica confuso. O trace mostra cinco falhas e um sucesso, e ninguém lê a primeira mensagem, a que dizia o porquê.

Um desafio

Uma pergunta para você. Você já corrigiu a parte óbvia. Só repete em timeout e erro do servidor, e manda uma chave de idempotência. E mesmo assim um cliente recebeu dois emails de cobrança. O que você olha primeiro?

Se a chave muda a cada tentativa. A idempotência só vale se a chave for a mesma em todas as tentativas da mesma operação. Se cada retry gera uma chave nova, o serviço de email fez exatamente o que você pediu. Mandou dois emails.

Trocar de provedor de email não ajuda, nem aumentar o limite de tentativas. O duplicado já passou. A correção é uma chave que pertence à operação, não à tentativa.

O tratamento

O tratamento é uma refatoração chamada classify errors before retry. Ela tem três partes, e pular qualquer uma deixa um buraco. A primeira é classificar.

Timeout, servidor fora do ar ou limite de requisições é transitório. Repita, com espera crescente, um limite baixo, e se o servidor diz quanto esperar, espere isso.

Entrada inválida é permanente. O pedido está errado, e vai estar errado na oitava tentativa também. Uma armadilha clássica é repetir um pedido inválido porque a API às vezes oscila. Oscilação de rede aparece como timeout e erro de servidor. Pedido inválido quer dizer corrija o pedido.

Sem saldo, limite ou sem permissão é permanente, pelo menos por agora. Não repita. Avise o usuário, ou reagende de propósito.

E timeout numa escrita é o caso difícil. Você não sabe se aconteceu. Repita, mas só com a mesma chave de idempotência, para o serviço poder dizer: essa eu já fiz.

Num agente, a classificação também precisa chegar ao modelo. A ferramenta devolve um erro que ele consegue usar. Um código, se dá para repetir, e o que está faltando. Um erro seco empurra o modelo de volta para a mesma chamada.

E coloque um detector de repetição no código. A mesma ferramenta, com os mesmos argumentos, três vezes seguidas, encerra o loop. Isso pega o caso em que o modelo ignora a mensagem.

Quando ignorar

Quando um retry simples está ok? Numa leitura sem efeito colateral, repetir erro transitório com limite e espera é boa prática. Uma busca que deu timeout pode rodar de novo.

E o SDK do provedor do modelo que repete duas vezes em limite de requisições e erro de servidor não é esse smell. Ele é seletivo. Só confira o que ele repete. Um SDK que cuida da rede não desculpa um tratamento genérico que você colocou em volta de um pagamento.

Mas repare: o smell não precisa de efeito duplicado. Um job de leitura que repete acesso negado e arquivo inválido oito vezes não tem efeito colateral. Continua cego. Só queima cota em vez de dinheiro.

Fechamento

Então, a ideia para levar. Um retry não é uma rede de proteção que você joga sobre tudo. É uma decisão que você toma sobre um tipo de erro, o tipo que o tempo resolve de verdade. O resto precisa de uma resposta, não de mais uma tentativa. E tudo que muda o mundo carrega uma chave que deixa a segunda tentativa inofensiva.

Na próxima aula, a gente faz essa refatoração passo a passo, num fluxo de pagamento de verdade: classify errors before retry. Até lá.

SmellAbusos de controle

Retry Cego

Blind Retry

Retry Cego (Blind Retry) é um smell de IA, ou seja, um sinal de problema em sistemas com LLM, do grupo Abusos de controle. Qualquer erro dispara nova tentativa, inclusive erros que nunca vão passar.

Elemento
11/37
Nível
Intermediário
Leitura
4 min
Atualizado
Nesta página 7
  1. 01Como reconhecer
  2. 02Por que acontece
  3. 03Quanto custa ignorar
  4. 04Tratamento
  5. 05O que você ganha
  6. 06Quando ignorar
  7. 07É esse smell?
  8. ··Perguntas rápidas

Como reconhecer

Um assistente financeiro agenda Pix (o sistema brasileiro de pagamento instantâneo). O código que chama o banco (anonimizado):

for attempt in range(5):
    try:
        return bank.schedule_pix(key, amount, date)
    except Exception as e:
        log.warning(f"tentativa {attempt} falhou: {e}")
        time.sleep(2 ** attempt)
raise PaymentFailed()

O log de uma madrugada:

02:14:03 tentativa 0 falhou: LIMITE_NOTURNO_EXCEDIDO
02:14:05 tentativa 1 falhou: LIMITE_NOTURNO_EXCEDIDO
02:14:09 tentativa 2 falhou: LIMITE_NOTURNO_EXCEDIDO
02:14:17 tentativa 3 falhou: LIMITE_NOTURNO_EXCEDIDO
02:14:33 tentativa 4 ok

Na quinta tentativa o limite noturno tinha virado, e o Pix passou. O cliente, avisado da falha minutos antes, já tinha feito o pagamento pelo app. Pagou duas vezes.

O retry “funcionou”. Esse é o problema. LIMITE_NOTURNO_EXCEDIDO não é falha de rede. É uma regra de negócio: agora não. Insistir até o relógio mudar transforma um “não” em um efeito que ninguém pediu de novo.

Sinais de Retry Cego:

  • O código captura qualquer exceção e tenta de novo.
  • Erros permanentes (saldo, permissão, validação) são repetidos como se fossem temporários.
  • Chamadas com efeito são repetidas sem chave de idempotência.
  • O agente repete a mesma chamada de ferramenta depois de um erro, com os mesmos argumentos.
  • Os logs mostram sequências do mesmo erro, várias vezes seguidas.
flowchart LR
  C["1. Chamada"]:::tool --> E{"2. Erro?"}
  E -->|qualquer erro| R["3. Tentar de novo"]:::tool
  R --> C
  E -->|"passou por acaso"| D[("4. Efeito duplicado")]:::store
  1. A chamada é feita.
  2. Qualquer erro é tratado do mesmo jeito.
  3. A mesma chamada é repetida, sem entender o motivo.
  4. Quando passa, o efeito pode ser duplicado ou acontecer na hora errada.

Há dois desenhos que produzem o mesmo cheiro. No código, um except Exception envolve a chamada. No agente, o modelo lê “erro” e chama a mesma ferramenta de novo. Nos dois casos, quem decide repetir não classificou o erro.

Checagem +20 XP de primeiraA ferramenta agendar_pix devolve LIMITE_NOTURNO_EXCEDIDO. Seu código captura qualquer exceção, espera 2, 4, 8 segundos e tenta de novo, até cinco vezes. Qual é o diagnóstico?

Por que acontece

  • Retry genérico parece proteção. Envolver tudo num laço de tentativas é a receita mais conhecida para falha de rede. A receita vaza para saldo insuficiente, permissão e validação.
  • Erros não têm tipo. A API devolve texto, e o código não diferencia “tente de novo” de “nunca vai dar”. O modelo, vendo só “erro”, insiste.
  • O agente aprende a insistir. Sem uma mensagem que diga retryable: false, a ferramenta parece quebrada, e o modelo tenta a mesma coisa.
  • Ninguém pensou em idempotência. A ferramenta foi escrita como se cada chamada fosse única. Um timeout depois de o banco aceitar o Pix vira um segundo Pix.

Como classificar na prática

Suponha que a API do banco (ou o HTTP por baixo) devolva códigos. A tabela abaixo é o mapa que o laço cego não tem:

Sinal Tipo O que fazer
Timeout, 503, conexão resetada Transitório Retry com espera, limite baixo
429 com Retry-After Transitório Esperar o que o servidor pediu
400, validação, chave Pix inválida Permanente Não repetir. Corrigir o pedido
Saldo, limite, permissão Permanente (agora) Não repetir. Avisar ou remarcar
409, “já existe” Idempotente Tratar como sucesso
Timeout em escrita, resultado desconhecido Indeterminado Só repetir com a mesma chave de idempotência

A armadilha clássica de quem está começando: tratar 400 como transitório “porque a API às vezes oscila”. Oscilação de rede vem como timeout ou 5xx. 400 quer dizer que o pedido está errado.

Quanto custa ignorar

  • Efeitos duplicados. Pagamentos, emails, notas fiscais e pedidos repetidos. No Pix, o cliente paga duas vezes e o estorno vira um chamado de horas.
  • Efeito na hora errada. O retry que “recupera” um limite noturno agenda um pagamento que o usuário já cancelou na cabeça.
  • Custo. Tentativas inúteis gastam chamadas, tempo e cota. Imagine 10 mil agendamentos recusados por dia, cada um com 5 tentativas: são 40 mil chamadas a mais, todas inúteis.
  • Bloqueios. Muitas tentativas contra um serviço com problema podem gerar bloqueio por abuso ou piorar a falha. O padrão Disjuntor existe exatamente para esse caso.
  • Diagnóstico confuso. O erro real se perde entre tentativas. O trace mostra cinco falhas e um sucesso, e ninguém lê a mensagem da primeira.

Tratamento

Refatoração Escolha quando
Classificar Erro Antes de Tentar de Novo Sempre. Erros transitórios (rede, 429, 503) têm retry com espera; erros permanentes voltam ao usuário ou ao modelo com explicação. Chamadas com efeito usam chave de idempotência. Destinos: Disjuntor e Ação Idempotente.

O tratamento tem três peças, e pular qualquer uma deixa um furo:

  1. Classificar. Transitório, permanente ou indeterminado. A classificação vive no código, não no palpite do modelo.
  2. Esperar só no transitório. Backoff, teto de tentativas, respeito a Retry-After. Sem repetir o mesmo argumento depois de um permanente.
  3. Idempotência em efeito. Cada Pix, email ou emissão de NF-e (nota fiscal eletrônica) leva uma chave estável. O banco ou o serviço garante: a mesma chave não gera dois efeitos.

No loop do agente, a ferramenta precisa devolver um erro que o modelo consiga usar: código, se é repetível, e o que falta. “ok” e “erro” empurram o modelo de volta para a mesma chamada. Um detector de repetição (a mesma ferramenta, os mesmos argumentos, três vezes) corta o caso em que o modelo ignora o retryable: false.

Antes e depois, no laço:

# antes: qualquer exceção vira nova tentativa
# depois: só transitório, e a chave não muda entre tentativas
result = bank.schedule_pix(key, amount, date, idempotency_key=key)
# se LIMITE_NOTURNO_EXCEDIDO: return erro ao usuário, sem loop
# se timeout: retry com a mesma idempotency_key
Checagem +20 XP de primeiraVocê classificou erros, faz retry só em timeout e 503, e envia a mesma chave de idempotência. Mesmo assim um cliente recebeu dois emails de cobrança. O que falta olhar primeiro?

O que você ganha

  • Erros permanentes tratados na hora, com uma mensagem útil.
  • Nenhum efeito duplicado por retry.
  • Menos chamadas desperdiçadas.
  • Logs que mostram o erro real, uma vez.

Quando ignorar

  • Leituras sem efeito, com erros só transitórios. Um retry simples numa busca é aceitável, desde que tenha limite e espera.
  • Bibliotecas que já classificam. SDKs que fazem retry só em códigos transitórios resolvem a parte de rede. Confira o que eles repetem. Um SDK que retenta 429 não autoriza o seu except Exception em cima do Pix.

É esse smell?

Checagem +20 XP de primeiraO SDK do provedor de modelo faz retry automático em erros 429 e 5xx, até duas vezes, com espera. O time não acrescentou nada. É Retry Cego?

Checagem +20 XP de primeiraUm agente chama send_invoice, recebe 'cliente sem email cadastrado' e chama send_invoice de novo, com os mesmos argumentos, três vezes. Qual é o problema?

Checagem +20 XP de primeiraUma chamada de pagamento tem retry em erros de rede, e cada tentativa usa a mesma chave de idempotência. O banco garante que a mesma chave nunca gera dois pagamentos. É Retry Cego?

Checagem +20 XP de primeiraUm job de leitura de NF-e faz retry em qualquer exceção, inclusive 'acesso negado' e 'XML inválido', até 8 vezes. Não há efeito colateral. É Retry Cego?

Perguntas rápidas

O que é Retry Cego?

Retry Cego (Blind Retry) é um smell de IA, ou seja, um sinal de problema em sistemas com LLM, do grupo Abusos de controle. Qualquer erro dispara nova tentativa, inclusive erros que nunca vão passar.

Como corrigir Retry Cego?

Com Classificar Erro Antes de Tentar de Novo. Cada refatoração traz o passo a passo seguro, com eval antes e depois.

Onde Retry Cego aparece na prática?

Nos cenários reais Gerador de testes e Assistente financeiro com aprovação.

Para ir além

Relações

Aparece nas trilhas 1
Buscar