Falhas silenciosas em pipelines de IA: por que o status verde de um container mente, e como cortamos 90% do gasto com LLM
Um ramo de fallback dentro de um bloco catch, sem contador ou alerta próprios, pode mascarar uma falha total do sistema: um novo pipeline agêntico de três modelos nunca rodou com sucesso em produção por meses, enquanto a CLI travava em configurações OAuth vazias de servidores MCP. A adição de um pré-filtro determinístico de títulos e um deduplicador por trigramas antes da chamada ao LLM e da geração de mídia reduziu o ruído informacional em 76,5% e cortou o gasto diário com API em cerca de 90% (de mais de 100 para 22 chamadas por execução). Usar DEFAULT 0 em vez de DEFAULT NULL durante a migração de uma coluna de pontuação removeu silenciosamente 678 artigos de qualidade do feed, e um ciclo de sleep antes da primeira execução de uma tarefa em segundo plano zerava a atualização da cotação de moedas a cada deploy.

- Economia de tokens com o pré-filtro: a parcela de gasto desperdiçado caiu de 88% para quase zero, e as chamadas ao LLM caíram de mais de 100 para 22 por execução (-90% do orçamento)
- Eficiência do scoring determinístico: 76,5% do fluxo de entrada irrelevante foi filtrado com zero chamadas à API, liberando 4,9 GB de disco
- O custo de um erro na migração do banco de dados: 678 artigos perdidos por usar `DEFAULT 0` em vez de `DEFAULT NULL`, com a base aprovada crescendo de 341 para 943 após o backfill
- Recursos escondidos: 2.244 arquivos de áudio narrados (6 GB, 69% da base) que nunca apareciam na interface por causa de um campo ausente em um `SELECT`
A classe de bug mais cara em sistemas de IA autônomos não é a quebra com um stack trace vermelho, mas sim a falha silenciosa. O container aparece como `Up` no `docker ps`, o cron termina com código `0`, os artigos continuam sendo publicados no feed — e o código novo em que você passou uma semana trabalhando nunca chegou a rodar, nem uma vez.
Foi exatamente isso que aconteceu no meu pipeline de notícias com IA depois da migração de uma combinação `n8n + Airtable` para minha própria infraestrutura de servidor (40 horas de migração, um `MIGRATION.md` de mais de 600 linhas para preservar o contexto entre sessões). Montei uma cadeia de três agentes (`EditorAgent`, `WriterAgent`, `QAAgent`) e a envolvi em um `try / catch` bem organizado, com fallback para o antigo `AIProcessor`.
Por que um bloco catch com ramo de fallback pode mascarar uma falha em
cinco camadas por meses?
Como o ramo de fallback continuava publicando conteúdo normalmente, o sistema parecia saudável visto de fora. Só meses depois notei nos logs uma linha recorrente: `Agent pipeline failed. Falling back to AIProcessor`. Quando começamos a desmontar essa falha camada por camada (a sessão de depuração levou 1.320 mensagens e 517 execuções de subagentes), surgiu uma espécie de boneca russa com cinco causas:
1. O token de autenticação de curta duração da CLI expirava a cada poucas horas. 2. O parâmetro `timeout` era aceito pelo construtor do agente base, mas nunca era propagado para a chamada filha. 3. O modelo pesado usado na etapa de curadoria ultrapassava o limite de tempo em lotes grandes (trocar para um modelo mais rápido acelerou essa etapa de 3 a 4 vezes). 4. Um binário atualizado da CLI parou de aceitar a flag obsoleta `--max-tokens`. 5. Dentro do container, a CLI travava permanentemente na linha `Fetched 4 servers`, ao tentar inicializar conectores MCP na nuvem (Notion, Figma, Linear, Sentry) com configurações OAuth vazias.
A lição é inegociável: qualquer fallback sem contador e alerta próprios não é tolerância a falhas, é disfarce para um incidente. A mesma lógica vale para um container com status `Up` enquanto um script Python interno está preso em um loop de crash por um `SyntaxError`, consumindo 98% da CPU: a verificação real é um `PID` estável com mais de 60 segundos de vida, somada a uma execução de `python3 -m py_compile`.
Como reordenar as fases do pipeline e usar deduplicação por trigramas
economiza 90% do orçamento com modelos?
A segunda revisão revelou um buraco financeiro: das 3.235 notícias processadas, apenas 340 chegavam à publicação, mas as chamadas caras ao LLM, as capas e a narração (TTS) eram executadas antes do filtro final (88% do orçamento era queimado em vão, e um crontab duplicado acionava o coletor 288 vezes por dia em vez de 48). Colocamos na frente do modelo um pré-filtro gratuito baseado em expressões regulares e pesos de fontes (mais de 100 padrões em inglês, russo e chinês, usando `includes()` em vez de `\b` para idiomas sem espaçamento entre palavras, como o chinês):
```javascript function scoreArticle(title, sourceName) { let score = 0; const t = (title || '').toLowerCase(); const s = (sourceName || '').toLowerCase(); if (SOURCE_TIERS.tier1.some(x => s.includes(x))) score += 4; else if (SOURCE_TIERS.tier2.some(x => s.includes(x))) score += 3; let kw = 0; for (const rx of AI_KEYWORDS) { if (rx.test(title)) kw++; } score += Math.min(kw, 4); if (AI_COMPANIES.some(c => t.includes(c))) score += 2; if (title && title.length > 20) score += 1; if (/\d/.test(title)) score += 1; return score; } ```
Esse filtro elimina 76,5% do ruído de entrada com custo zero de tokens. Também tiramos a detecção de duplicatas do LLM e passamos para um híbrido de similaridade de Jaccard por trigramas e distância de Levenshtein (reduzindo o limiar de Jaccard para a morfologia russa de 0,65 para 0,40, cruzado com entidades nomeadas). O gasto com API caiu 90% (de mais de 100 para 22 chamadas por execução), e a limpeza de mídias órfãs liberou 4,9 GB (1.764 imagens e 1.398 áudios).
Por que um DEFAULT 0 numa migração de banco de dados e um sleep antes
da primeira execução escondem seus dados?
A terceira falha silenciosa custou um mês de investigação: ao adicionar uma coluna com `ALTER TABLE ... ADD COLUMN hot_score INTEGER DEFAULT 0`, todos os 678 artigos antigos receberam pontuação `0`, e o SQL deixou de conseguir distinguir entre "ainda não pontuado" e "pontuado com zero". A troca para `DEFAULT NULL`, seguida de um backfill, devolveu 581 artigos ao feed, triplicando a base aprovada de 341 para 943.
Ao lado disso, encontramos um `LIMIT 5` esquecido na consulta do orquestrador e um campo `audio_path` ausente em um `SELECT`, que escondia 2.244 arquivos de áudio já prontos, totalizando 6 GB (69% da base). Por fim, uma tarefa em segundo plano responsável pela cotação de moedas começava com `await asyncio.
sleep(86400)` antes da primeira execução e, com deploys diários, nunca chegou a disparar nem uma vez (corrigido com `FIRST_RUN_DELAY_S = 90` e um `last_success_at`), enquanto uma verificação de saúde de arquivos estáticos via `curl`, checando o código `200`, recebia `index.html` em vez de detectar PDFs desaparecidos, por causa da configuração SPA do nginx.
Esses invariantes de observabilidade estão incorporados na plataforma [Nomad AI](https://nomadnet.ai) e no runtime em nuvem [agent.nomadnet.ai](https://agent.nomadnet.ai). Um curso prático sobre depuração de pipelines autônomos está disponível na [Hamidun Academy](https://academy.hamidun.com) (teste de 72 horas), e os scripts de auditoria estão no [Vibe Club](https://hamidun.com/club).
Perguntas frequentes sobre a notícia
Por que um bloco catch com ramo de fallback pode mascarar uma falha em cinco camadas por meses?
Como o ramo de fallback continuava publicando conteúdo normalmente, o sistema parecia saudável visto de fora. Só meses depois notei nos logs uma linha recorrente: `Agent pipeline failed. Falling back to AIProcessor`. Quando começamos a desmontar essa falha camada por camada (a sessão de depuração levou 1.320 mensagens e 517 execuções de subagentes), surgiu uma espécie de boneca russa com cinco causas: 1. O token de autenticação de curta duração da CLI expirava a cada poucas horas. 2. O parâmetro `timeout` era aceito pelo construtor do agente base, mas nunca era propagado pa
Como reordenar as fases do pipeline e usar deduplicação por trigramas economiza 90% do orçamento com modelos?
A segunda revisão revelou um buraco financeiro: das 3.235 notícias processadas, apenas 340 chegavam à publicação, mas as chamadas caras ao LLM, as capas e a narração (TTS) eram executadas antes do filtro final (88% do orçamento era queimado em vão, e um crontab duplicado acionava o coletor 288 vezes por dia em vez de 48). Colocamos na frente do modelo um pré-filtro gratuito baseado em expressões regulares e pesos de fontes (mais de 100 padrões em inglês, russo e chinês, usando `includes()` em vez de `\b` para idiomas sem espaçamento entre palavras, como o chinês): ```javasc
Delegate Deep Research, Coding & Multi-Step Workflows to Nomad Agent
Deploy autonomous task execution with Nomad Agent (agent.nomadnet.ai) — automated web research, data synthesis, code generation, and MCP tool orchestration.
O essencial da IA — uma vez por semana
Sete histórias que realmente importaram, escolhidas a dedo. Sem ruído nem releases.
Pronto! Verifique seu e-mail para a confirmação.