Postmortem: o eval que derrubou o chat
Em 12/10/2026, o chat deste site parou de responder perguntas sobre mim a partir das 17:45. Nenhuma métrica do Worker acusou erro. A causa foi o meu próprio eval, que gastou a cota grátis do Workers AI que a busca do chat também usa.
Os gráficos com os dados do dia estão no dashboard do incidente. Os horários aqui são de Brasília.
Resumo
- Impacto: perguntas sobre mim, o site ou o chat voltavam sem texto, com qualquer modelo do seletor. Perguntas gerais continuavam funcionando.
- Causa: a ferramenta
buscar_sitecalcula o embedding da pergunta no Workers AI. Com a cota diária esgotada, essa chamada voltava com o erro4006e a ferramenta falhava inteira. - Por que ninguém viu: o
/chatresponde 200 antes de a busca rodar, e a falha da ferramenta não escrevia nada no log. - Correção: a #287, mergeada às 18:24. Sem embedding, a busca cai para o ranking BM25 e registra o fallback no log.
Linha do tempo
- 11:45 e 12:45. Duas rodadas do eval do chat com o Llama 3.3 70B no Workers AI. Cada rodada manda as mesmas perguntas para todos os modelos do seletor.
- 17:30 a 17:40. Terceira rodada. O consumo do dia passa de 10.000 neurons, que é a cota grátis diária.
- 17:45. Primeiras chamadas recusadas com
4006, no embedding e no modelo. Daqui em diante a busca do chat falha. - 18:24. A #287 é mergeada.
- 21:00. A cota é renovada (meia-noite UTC).
No dia, foram 11.877 neurons e 182 chamadas recusadas pelo Workers AI.
O que as métricas mostravam
Nas métricas do Worker, o dia inteiro aparece limpo: 0 erros em 632 requisições, todas com status success. Isso acontece porque o /chat abre o stream e responde 200 logo no começo. A busca roda depois, dentro do stream, e o erro dela vira um evento do protocolo do chat. Para o runtime, a requisição deu certo.
O único sinal no Worker era a latência. A mediana caiu de 2,9 s para 0,5 s quando os erros começaram. A resposta ficou mais rápida porque o modelo não recebia o resultado da busca e não tinha o que escrever. Num chat, uma queda brusca de latência sem mudança de código merece tanta atenção quanto um pico.
Como chegar na causa
Com os dados que existiam, o caminho é este:
- Reproduzir o sintoma. Uma pergunta sobre mim volta sem texto. Uma conta simples funciona. Então o problema está na busca, não no modelo nem no Worker inteiro.
- Olhar o stream, não o status. O stream da resposta tem um evento de erro da ferramenta com a mensagem do Workers AI:
4006: you have used up your daily free allocation of 10,000 neurons. - Confirmar na Analytics do Workers AI. As chamadas com
errorCode 4006começam às 17:45, no embedding e no modelo. - Achar quem gastou a cota. Somando os neurons do dia por modelo, quase tudo é do Llama 3.3 70B, em três blocos que batem com as rodadas do eval. O embedding da busca gastou poucos neurons.
O passo 2 é o que mais demora quando não há log. Sem uma linha no Worker dizendo que a ferramenta falhou, a única forma de ver o erro era abrir o stream de uma resposta.
Causa raiz
Três coisas juntas:
- O eval e o chat de produção usam a mesma conta e a mesma cota grátis do Workers AI.
- A busca dependia do embedding da pergunta e não tinha alternativa quando ele falhava. O ranking BM25 já existia em memória e ficava sem uso.
- A falha da ferramenta não deixava nenhuma linha no log.
A correção e a reprodução
A #287 faz o retrieval seguir só com o BM25 quando o embedding falha e escreve embed_error_bm25_fallback no log. Para conferir, rodei o bundle do Worker de antes e de depois do fix com o embedding devolvendo o erro de cota. Foram 8 perguntas do eval do chat que dependem da busca, corrigidas pelas mesmas verificações do benchmark:
| Fase | Aprovadas | Erro de ferramenta | Com linha de log | Mediana |
|---|---|---|---|---|
| Normal | 7/8 | 0 | 0 | 5,5 s |
| Sem cota, antes do fix | 0/8 | 8 | 0 | 1,6 s |
| Sem cota, com o fix | 8/8 | 0 | 8 | 5,4 s |
Antes do fix, todas as perguntas falham e nenhuma deixa log. Com o fix, 8 de 8 passam e cada fallback aparece no log. Na rodada normal, uma pergunta falhou por variação do modelo, sem relação com o incidente. A reprodução também mostra a queda de latência: 1,6 s de mediana sem a busca, contra 5,4 s com ela.
O que ainda falta
A correção resolve o sintoma. Ainda estão em aberto:
- Separar o eval da produção. Rodar o eval com outro limite ou outra conta, para que ele não consuma a cota de que o chat depende.
- Alerta de consumo. Avisar quando os neurons do dia passarem de 80% da cota. Às 13:00 o consumo já passava de 9,5 mil.
- Logs persistidos. Os Workers Logs não estão ligados neste Worker. No dia, só havia métricas agregadas.
- Medir respostas vazias. Contar respostas sem texto como métrica. Essa contagem teria mostrado o incidente na hora.
- O modelo do Workers AI no seletor continua indisponível quando a cota acaba. Só o plano pago resolve isso.