Suporte multiagente: do protótipo ao widget em produção
Um sistema multiagente com defesa contra prompt injection validou a necessidade. A arquitetura final foi outra, e eu construí o que ela usa.
Resultados
3+
agentes especialistas, cada um com seu próprio corpus RAG
declaradoREADME do protótipo
Produção
widget de atendimento com identidade verificada por HMAC no portal
declaradoambiente de produção do portal
Resumo
Contexto
O suporte ao cliente da Revvo precisava triar dúvidas técnicas e de negócio, responder com base na documentação e escalar para humanos quando necessário, sem expor dados pessoais e sem cair em prompt injection.
Ação
Construí um sistema multiagente em LangGraph. Uma camada de entrada detecta prompt injection e sanitiza PII, um roteador por intenção (LLM) escolhe entre agentes especialistas com bases RAG próprias e o escalonamento abre tickets no PostgreSQL, acompanhados num backoffice em React. Quando a empresa adotou outra arquitetura de agente, passei a integrar o widget de atendimento ao portal: CSP, persistência da conversa no iframe e identidade verificada por HMAC.
Resultado
O protótipo funcionou e validou a necessidade, mas a solução adotada foi o agente de outro engenheiro, construído do zero. O widget de atendimento que integrei está em produção no portal, com histórico que acompanha o usuário entre dispositivos. As ferramentas que construí depois (triagem do Jira e gateway MCP) alimentam justamente esse agente.
Lição
Perder a disputa de arquitetura não é perder o problema: vale construir as peças de que a solução adotada vai precisar.
Arquitetura
Versão longa
O protótipo multiagente
- Guarda de entrada. Antes de qualquer agente, a mensagem passa por detecção de prompt injection e sanitização de dados pessoais.
- Roteador por intenção. Um LLM classifica a mensagem e escolhe o especialista.
- Especialistas com RAG próprio. Cada especialista, técnico ou de negócio, consulta o seu corpus no Vertex AI. Isso evita que um contexto contamine o outro.
- Escalonamento. Quando o agente não resolve, abre um ticket no PostgreSQL com o histórico. O backoffice em React mostra a fila para o time humano.
A decisão que não foi minha
A empresa seguiu com o agente de suporte de um AI Engineer sênior, que construiu a própria arquitetura. Em vez de insistir na minha, passei a construir o que esse agente precisava: o servidor de triagem do Jira e o gateway MCP pelo qual ele acessa as ferramentas (ver o case do gateway).
O widget em produção
Faltava levar o atendimento para dentro do portal do cliente. Três problemas apareceram:
- CSP. O iframe do widget era bloqueado; declarei o
frame-srccorreto. - A conversa sumia a cada carregamento. Lendo o código do widget, descobri que, dentro de um
iframe, ele só busca o histórico quando a página-pai responde
config-setao eventoloaded. Confirmei em homologação enviando o evento à mão e depois implementei o handshake comtargetOriginexplícito, nunca*. - Identidade. O backend deriva um HMAC-SHA256 do e-mail com a chave do inbox, e só o hash vai ao navegador. Sem ele, o histórico fica preso a um navegador; com ele, acompanha o usuário em qualquer dispositivo.
Os segredos entraram no Secret Sync via Terraform, nos ambientes de desenvolvimento e homologação.
Lições aprendidas
- Defesa na entrada. Injection e PII são tratados antes do roteador, e não dentro de cada agente.
- Leia o código do terceiro. O widget só carregava o histórico depois de um handshake não documentado, e eu o encontrei lendo o código-fonte.
- HMAC não é só cadeado. Sem o hash, o histórico não atravessa dispositivos: o mecanismo de segurança é também o de continuidade.