Sistema de produção que evoluiu de um retriever para um curador autônomo do grafo. Dados reais, medidos em execução.
Antes da engenharia, o propósito.
| Pergunta | Resposta |
|---|---|
| O problema | Marcas perdem vendas sem entender o porquê. A decisão de compra acontece fora do alcance delas: o consumidor desconfia, compara, valida e decide em conversas, avaliações e fóruns que a marca não enxerga. |
| O que o sistema faz | Escuta conversas reais de consumidores, modela o caminho de decisão como um grafo (Ciclo de Decisão™: Desconfiança → Comparação → Validação → Decisão), conecta cada objeção a fatos verificados e fontes com URL, e responde perguntas com evidência ancorada no grafo. |
| Para que serve | Diagnosticar por que uma marca é escolhida ou descartada (qual momento do ciclo ela perde) e orientar o que fazer em cada momento. O grafo é o ativo acumulado: cada ciclo de operação adiciona fatos, fontes e padrões à Biblioteca de Decisão™. |
| Por que grafos | A decisão é um caminho, não um documento. A pergunta "por que o consumidor não comprou?" exige navegar de objeção em objeção até a fonte que a sustenta. Um grafo modela isso nativamente; uma tabela ou um texto não. |
Exemplo real de uso: a pergunta "quais as principais objeções de preço na fase de Validação?" retorna as objeções do grafo, cada uma com o fato que a sustenta e as fontes com URL (Reclame AQUI, Forbes, Mundo do Marketing). Sem fonte, o sistema recusa a afirmação: prefere declarar um gap a fabricar um dado. É o comportamento demonstrado na seção 05.
98 nós, 108 arestas. Objeções de consumidor conectadas a fatos verificados e fontes com URL. Navegável: arraste, clique, passe o mouse.
Cadeia típica: (:Objeção) ← SUSTENTA ← (:Fato) ← CITA ← (:Fonte). Cada Fato carrega URL real; cada Fonte tem nome, tipo e link verificados.
| Componente | Antes | Depois | Técnica |
|---|---|---|---|
| RAG (embedding + busca híbrida) | 10.7s | 0.92s | Daemon persistente ONNX (modelo carregado 1x) |
| Consulta textual do grafo | 3.7s | 0.85s | Driver Bolt persistente (sem reconexão por chamada) |
| Pre-flight completo (Memória + Grafo + RAG) | 10.7s | 0.54s | HTTP local + fallback gracioso p/ subprocess |
Um daemon local segura o modelo e o driver; o pre-flight tenta HTTP e cai para subprocess se o daemon estiver fora. O watchdog (cron 5min) restaura em OOM.
pre_flight_memoria.py │ tenta HTTP local (0.2-0.9s) ▼ embedding_daemon.py :9120 ──► Neo4j Aura (driver persistente) • /health vector index 384d (cosine) • /perguntar (RAG híbrido) fulltext index • /grafo (consulta textual) + neighbor ▲ │ se fora do ar ▼ subprocess neo4j_rag.py (fallback gracioso, ~10s) watchdog_embedding_daemon.py (cron a cada 5min) • pgrep padrão específico → kill órfãos • Popen start_new_session (filho órfão sobrevive ao OOM) • confirma no próximo ciclo (não segura memória no boot)
O filho órfão (start_new_session) sobrevive ao OOM killer durante o boot do modelo (~700MB RSS). O watchdog morre, o daemon fica. No pior caso, o fallback subprocess mantém a consulta viva até a restauração.
O agente detectou gaps estruturais, gerou Cypher, executou e verificou — com aprovação humana do plano.
| Gap detectado | Ação executada | Resultado |
|---|---|---|
2 objeções com campo momento nulo (quebrava filtros por fase) | SET o.momento = 'Desconfiança' | Fases íntegras |
| Objeções de Validação sem fatos ("dinheiro de volta", "budget pro board") | MERGE Fato + SUSTENTA + CITA (Reclame AQUI, Forbes, Mundo do Marketing) | 9 nós |
| Objeções de Desconfiança sem fatos (franquia, agência, eletrólito, skincare) | MERGE Fato + SUSTENTA + CITA (Reddit, soar.sh, Reclame AQUI) | 16 nós |
| Reindexação dos nós novos | neo4j_rag.py indexar | 98/98 com embedding |
# Exemplo do padrão de carga (verificado em produção)
MERGE (f:Fato {titulo: $titulo})
SET f.descricao = $descricao, f.data = $data, f.url = $url
WITH f
MATCH (o:Objeção {titulo: $obj})
MERGE (f)-[:SUSTENTA]->(o)
WITH f
UNWIND $fontes AS ft
MERGE (fonte:Fonte {nome: ft.nome})
SET fonte.tipo = ft.tipo, fonte.url = ft.url
MERGE (f)-[:CITA]->(fonte)
Regra rígida: afirmação factual só existe se ancorada em nó do grafo com fonte. Caso real, em produção:
| Pergunta | Entidade inexistente ("EcoSysTechhx") |
|---|---|
| Fontes consultadas | Memória™ · Grafo Neo4j (query + RAG vetorial) · Arquivos em disco · Sessões passadas (FTS5) |
| Resultado | 0 resultados em todas as fontes |
| Resposta do agente | "Não tenho nenhum dado sobre a EcoSysTechhx no sistema Tulejur" + tabela de fontes consultadas |
| Comportamento | Declara o gap em vez de fabricar uma aresta |
Descobertas reais de operação, documentadas para o time de engenharia.
| # | Pitfall | Sintoma | Workaround |
|---|---|---|---|
| 1 | Acesso dinâmico de propriedade no planner do Aura 5.27 | any(k IN keys(n)) ... n[k] IS STRING → CypherTypeError hasALabelOrType() | Campos explícitos por label (toLower(coalesce(n.campo,'')) CONTAINS $t) |
| 2 | db.index.vector.queryNodes deprecado | Warning de deprecação no Aura 5.27 | Migrar para SEARCH (neo4j-graphrag ainda emite o warning) |
| 3 | Namespace-package shadowing | import neo4j resolvia para diretório doc local sem __init__.py | Remover diretório neo4j/ sem pacote; path injection do venv |
| 4 | OOM em box de 2GB durante reindexação | SIGKILL no watchdog durante boot do modelo ONNX (~700MB RSS) | Popen órfão (start_new_session) + fallback subprocess + watchdog |
| 5 | Vetor multi-label conflita com índice mono-label | CREATE VECTOR INDEX FOR (n:A|B) vs índice existente | Label comum :Embeddable + IF NOT EXISTS |
| Camada | Tecnologia |
|---|---|
| Banco de grafos | Neo4j Aura (5.27), driver neo4j 6.3.0 |
| RAG | neo4j-graphrag 1.19.0 (HybridRetriever: vector + fulltext) |
| Embeddings | fastembed 0.8.0 · paraphrase-multilingual-MiniLM-L12-v2 (ONNX, 384d, cosine) |
| Orquestração | Hermes Agent (Nous Research) + Python 3.13 |
| Visualização | pyvis/vis-network 9.1.2 (este grafo ao vivo) |