Varejo · 2026
Um agente que atende no WhatsApp e sabe a hora de chamar um humano
Atendimento consultivo por WhatsApp: entende a necessidade, recomenda a partir de catálogo próprio, responde dúvida conceitual por RAG e passa para um especialista com briefing pronto.
Meu papel · Projeto meu
Do desenho do grafo ao deploy, incluindo os guardrails e a suíte de avaliação.
- 3
- clientes em produção sobre a mesma arquitetura2026 · ajuste por operação, não reescrita
- 14
- cenários de eval rodando em CIdesde jun/2026
- 9
- nós no grafo de conversaarquitetura atual
Este caso descreve arquitetura e decisões sem expor código proprietário, credenciais, clientes ou dados de operação.
O problema
Atendimento consultivo no WhatsApp quebra o laço ingênuo de mensagem → modelo → resposta. A pessoa escreve em rajada, o canal reentrega o evento se você demorar, e a conversa precisa lembrar de ontem. Qualquer um dos três, sozinho, já produz um atendimento que parece quebrado.
As restrições reais
- A pessoa manda três mensagens em oito segundos. São um pensamento só — responder cada uma gera três respostas desencontradas.
- O webhook não pode esperar o modelo. Se a resposta demora, a API do WhatsApp reentrega o evento e a conversa duplica.
- A conversa é longa e precisa lembrar. O estado não cabe no prompt e não pode viver em memória de processo, que morre no primeiro redeploy.
- O agente não pode inventar preço nem prometer prazo. Em venda consultiva, errar isso custa mais caro que não responder.
Arquitetura
- carregar — Hidrata o estado a partir do checkpointer em Postgres e da memória acumulada.
- entender — Extrai intenção, entidades e o que ainda falta saber sobre quem está do outro lado.
- decidir — Roteia: seguir conversando, agendar, ou entregar a um humano.
- recuperar — Resolve o catálogo canônico e, em dúvida conceitual, consulta o índice vetorial.
- agendar — Conversa com a agenda real e devolve horários que existem.
- compor — Redige a resposta usando só o contexto que foi recuperado.
- guard — Barreira de saída: não inventa preço, não promete prazo, não extrapola o catálogo. Roda sobre o texto pronto.
- persistir — Grava memória e entendimento acumulado para o próximo turno.
- handoff — Monta o briefing estruturado e entrega ao especialista humano.
Decisões e o que custaram
A barreira roda depois de compor, não dentro do prompt
- Escolhi
- Verificar o texto já pronto contra regras explícitas, como última etapa antes de persistir.
- Descartei
- Confiar na instrução do prompt para o modelo não inventar preço nem prazo.
- Custou
- Uma passada a mais por resposta e um conjunto de regras para manter. Em troca, a classe de erro deixa de ser probabilística: pedir no prompt reduz a chance, verificar a saída elimina o caso.
Estado tipado em vez de dicionário solto
- Escolhi
- Contrato explícito entre os nós do grafo, verificável antes de rodar.
- Descartei
- Passar um dicionário livre de nó para nó, que é o caminho mais rápido.
- Custou
- Mais cerimônia para adicionar um campo. Em troca, renomear algo quebra no import e não às duas da manhã em produção.
Dois motores, selecionados por variável de ambiente
- Escolhi
- Manter o orquestrador imperativo antigo vivo ao lado do grafo novo, alternável sem redeploy.
- Descartei
- Migrar de uma vez e apagar o caminho antigo.
- Custou
- Código duplicado e duas implementações para manter durante a transição. Em troca, o rollback é uma variável de ambiente, não uma madrugada.
Telefone pseudonimizado antes de sair do processo
- Escolhi
- Hash com salt aplicado antes de qualquer log ou trace de observabilidade.
- Descartei
- Logar o número cru, que é mais simples de depurar quando algo dá errado.
- Custou
- Depurar um caso específico exige recalcular o hash. Em troca, nenhum trace devolve o número de ninguém.
Resultado
- O agente conduz a conversa inteira, recomenda a partir do catálogo e entrega ao especialista com briefing estruturado, em vez de transferir uma transcrição crua.
- A avaliação automatizada roda com um modelo como juiz e devolve código de saída binário, então entra em CI como qualquer teste. Os cenários cobrem o que mais dói: inventar preço, prometer prazo, responder fora do catálogo e perder o fio entre turnos.
- Rollback de motor sem redeploy durante toda a migração para o grafo.
O que levei disso
Guardrail dentro do prompt é pedido; guardrail fora do prompt é garantia. Passei a tratar a saída do modelo como entrada não confiável — a mesma postura que qualquer um tem com entrada de usuário, e que por algum motivo se perde quando o texto vem de um LLM.
Stack
- LangGraph
- Python
- FastAPI
- PostgreSQL
- RAG
- LLM
- Langfuse
- Docker