O problema
Todo o atendimento acontecia no WhatsApp, e o histórico ficava só lá. Saber quem perguntou sobre o quê, em que mês, e o que ficou combinado exigia rolar centenas de conversas. O dado existia, só não era consultável.
O que construí
- Coleta. A Evolution API expõe as conversas; um script Python lê as mensagens novas desde a última execução bem-sucedida.
- Classificação. Cada conversa passa pela API da Anthropic, que devolve o estágio do funil e um resumo estruturado. Para contato que já existe, o estado atual do CRM entra no prompt, então o modelo consolida em vez de sobrescrever o que a última janela de conversa não menciona.
- Persistência. Banco local, com deduplicação por mensagem para que reexecuções não inflem o histórico.
- Agendamento. O Task Scheduler do Windows dispara às 07h30, com recuperação quando a máquina passou o horário desligada.
- Fila de triagem. Uma varredura separada analisa o histórico antigo, que a janela do sync diário nunca alcançou, e deposita o resultado numa fila para revisão.
- Espelho de catálogo. Consome a API pública do site e mantém um cache local, então a ficha do contato já mostra o item sobre o qual ele perguntou.
Decisões técnicas
Simplificação que também resolveu privacidade. A primeira versão passava por um orquestrador de workflows na nuvem. Funcionava, mas era mais uma peça para manter e fazia conversa de cliente trafegar sem necessidade. Trocar por um script agendado deixou o sistema mais simples e mais privado ao mesmo tempo, que é a combinação rara. O orquestrador foi aposentado desse fluxo.
Saída de IA tratada como entrada não confiável. A classificação vem de um modelo, então a resposta é validada contra um conjunto fechado de estágios antes de tocar o banco. Se vier algo fora do esperado, a conversa fica sem classificação em vez de gravar um valor inventado. Prefiro campo vazio a dado errado que ninguém vai auditar depois. Na mesma linha, há travas em código, e não só no prompt: o modelo nunca fecha uma negociação sozinho e nunca move alguém para fora da própria categoria.
A anotação de quem atende vence a leitura da máquina. As notas ficam em tabela própria, append-only e datada. A IA lê essas notas com precedência sobre a conversa e nunca as reescreve. Antes disso, elas dividiam campo com o resumo automático e sumiam na análise seguinte, sem erro nenhum. São duas fontes com donos diferentes.
A varredura não escreve no funil. Analisar o histórico antigo podia bagunçar meses de classificação de uma vez, então ela grava numa fila separada e só um clique promove alguém para a base. Custo não era o obstáculo, curadoria era.
Deduplicação na fonte. Reexecutar é normal, seja por falha de rede ou máquina desligada. Sem chave de deduplicação por mensagem, cada reexecução duplicaria o histórico.
Como verifiquei
Reexecução sobre a mesma janela. A primeira carga real criou 23 contatos, atualizou 1 e não deu erro; a segunda passada, sobre o mesmo intervalo, foi 100% deduplicação.
Piloto antes de soltar a varredura no histórico inteiro. Rodei em 15 conversas e conferi uma a uma: 13 eram contatos legítimos. O caso difícil foi o que mais me interessou, porque a conversa mais longa da fila era de um fornecedor e o classificador acertou. Um filtro por tamanho de conversa, que era o caminho óbvio e barato, teria colocado justamente ela no topo.
Teste da trava de conexão nos dois sentidos. Aqui estava o problema mais perigoso do projeto: com o WhatsApp desconectado, a API continuava respondendo normalmente, servindo do cache dela. O sync rodaria, não encontraria mensagem nova e registraria “0 criados, 0 atualizados, 0 erros” por semanas. Sucesso aparente é pior que erro, porque ninguém vai investigar. Passei a checar o estado da conexão antes de qualquer coisa e a abortar quando ele não estiver aberto, tratando “não consegui verificar” também como falha. Testei desconectado, e abortou; reconectei, e importou 62 conversas.
Foi o terceiro caso da mesma família neste projeto. Antes dele, uma rotina de backup que falhava devolvendo só um código de erro que ninguém lia, e um nome de usuário mal configurado que invertia métricas de conversa sem nunca dar erro. Desde então, cada rotina agendada grava o resultado da própria execução em arquivo, para que o silêncio deixe de parecer sucesso.