Consumindo Modelos de IA
Tratamento de Erros
Timeout, rate limits, falhas de rede, retry com backoff e respostas seguras ao usuário.
Nesta aula você vai
- Identificar erros comuns das APIs de LLM
- Implementar retry idempotente com exponential backoff
- Retornar mensagens amigáveis sem vazar detalhes internos
Tratamento de Erros
Objetivos
- Criar integrações robustas — demo quebra, produção aguenta
- Saber quando repetir chamada e quando desistir
Demo vs produção
No seu notebook, a API quase sempre responde. Em produção, na terça às 15h com pico de tráfego, aparecem 429, timeout, JSON inválido e instabilidade do provedor.
A diferença entre um hack de fim de semana e um produto confiável está aqui: o que o usuário vê quando algo dá errado — e o que você loga para investigar depois.
Pense nesta aula como seguro de carro. Esperamos não usar — mas quando precisar, salva o projeto.
Erros frequentes
| HTTP | Código típico | Causa | Ação |
|---|---|---|---|
| 401 | invalid_api_key | Key errada/revogada | Alerta ops, não retry |
| 429 | rate_limit_exceeded | Muitas req/min | Retry com backoff |
| 500 | server_error | Instabilidade provedor | Retry limitado |
| 503 | overloaded | Pico de demanda | Retry + fallback message |
| Timeout | — | Rede lenta / resposta longa | Retry ou reduzir max_tokens |
Context length exceeded (400): prompt + histórico > limite — não adianta retry; resuma ou truncue histórico.
Diálogo de plantão:
Monitor: "Taxa de 503 subiu para 12%."
Dev: "É o provedor ou nosso timeout curto?"
Dev: "Logs mostram 45s de latência — aumentamos timeout e backoff."
Suporte: "Usuário vê mensagem amigável?"
Dev: "Sim — 'tente em instantes', com requestId."
Retry com exponential backoff
Regra de ouro: retry só em 429, 500, 503 e timeouts — nunca em 400/401.
Por quê? Repetir uma requisição com key inválida ou prompt gigante só gasta dinheiro e tempo sem resolver nada.
async function chatWithRetry(messages, maxAttempts = 3) {
let delay = 1000;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await chat(messages);
} catch (err) {
const retryable = err.status === 429 || err.status >= 500;
if (!retryable || attempt === maxAttempts) throw err;
await sleep(delay);
delay *= 2; // 1s → 2s → 4s
}
}
}
Use jitter (delay + random(0, 500)) se muitas instâncias retry juntas — evita que todos batam na API no mesmo segundo.
Analogia: backoff é como esperar filas espaçadas no banco, não empurrar a porta a cada meio segundo.
Circuit breaker (conceito)
Se 5 falhas seguidas em 1 minuto → pare de chamar LLM por 30s, retorne:
"Assistente temporariamente indisponível. Tente em instantes."
Evita cascata de custo e timeout no seu servidor. Sem circuit breaker, seu backend pode ficar preso esperando uma API que já está sobrecarregada.
Resposta ao usuário vs log interno
// ❌ Não exponha ao frontend
res.status(500).json({ error: err.stack, openai: err.raw });
// ✅ Mensagem genérica + correlation id
const requestId = crypto.randomUUID();
logger.error({ requestId, err });
res.status(503).json({
error: 'Não foi possível processar sua mensagem agora.',
requestId, // suporte pode rastrear
});
O usuário precisa de clareza e calma. O time de engenharia precisa de stack trace, status HTTP e requestId. Nunca misture os dois no JSON do frontend.
Timeout em camadas
- HTTP client: 45–60s para LLM
- Seu endpoint: 55s (menor que load balancer)
- Frontend: loading state + cancel após 60s
Cada camada um pouco menor que a anterior — assim o erro chega organizado, não como conexão pendurada.
Idempotência
Retry pode gerar duas respostas cobradas para a mesma pergunta. Para operações críticas:
- Gere
idempotencyKeypor mensagem do usuário - Armazene hash(prompt) → resposta em cache curto (5 min)
Cenário:
Usuário clica "Enviar" duas vezes por impaciência. Sem idempotência, você paga dois completions. Com cache de 5 min, a segunda requisição devolve a mesma resposta sem nova chamada.
Checklist produção
- Try/catch em toda chamada externa
- Log estruturado: latência, tokens, status, model
- Retry máximo 3× com backoff
- Mensagem amigável ao usuário
- Alertas se taxa de 429 > 5% por hora
Resumo
- Nem todo erro merece retry — 401 e context overflow são fix no código/dados
- Backoff exponencial para 429/5xx
- Usuário vê mensagem simples; você loga detalhe
- Timeout explícito evita thread/worker preso
Com a API consumida e erros tratados, você tem a base técnica. Na próxima matéria entramos no que separa resposta genérica de resposta útil: engenharia de prompt — o contrato entre seu sistema e o modelo.