# Memória de agentes em uma query SurrealQL: vetores, grafos e texto para infoprodutos
> Como combinar busca vetorial HNSW, texto completo BM25 e travessia de grafos em uma única query SurrealQL para dar memória real a agentes de IA no WhatsApp, recuperação de Pix/cartão e suporte de infoprodutos no Brasil.
**Autores:** Mauro Mequelussi
**Publicado:** 2026-11-09T18:24:30.851988317Z
**Atualizado:** 2026-11-09T18:24:32.054756962Z
**Tags:** grafos, agentes-de-ia, surrealdb, busca-vetorial, agent-memory, surrealql, infoprodutos
---
Uma **única query `SELECT` no SurrealQL** consegue buscar memórias de um agente de IA simultaneamente pelo **significado semântico** (índice vetorial HNSW), pelas **palavras exatas** (índice Full-Text BM25), pelas **conexões de grafo** (`RELATE`) e por **filtros temporais** dentro de uma mesma transação ACID. Em vez de manter quatro sistemas separados — um banco relacional, um banco vetorial, um motor de busca textual e um banco de grafos — e juntar tudo no código da aplicação, o SurrealDB executa os quatro índices sobre o mesmo registro.

No mercado brasileiro de **infoprodutos, lançamentos, perpétuos e áreas de membros**, essa arquitetura resolve o maior gargalo dos agentes de vendas e suporte no WhatsApp: lembrar o que o lead quis dizer, qual palavra específica ele usou (como `"Pix"`, `"boleto"`, `"reembolso"` ou o nome de um cupom), a qual produto, Order Bump ou gateway aquela conversa está ligada e quem é o responsável comercial pela oferta.

> **Quer dominar memória de agentes na prática?** Assista gratuitamente ao nosso [Curso de SurrealDB Agent Memory (15 aulas em português)](/cursos/surrealdb-agent-memory) e ao [Curso SurrealDB para Engenheiros de IA (11 aulas)](/cursos/surrealdb-para-engenheiros-de-ia).

## Assista na prática: como funciona a memória de agentes no SurrealDB

::video-player{src="https://www.youtube.com/watch?v=WzIITdKwvr4" title="Sua IA tem amnésia? SurrealDB lançou o Agent Memory"}
::

## O que um agente de IA para infoprodutos precisa lembrar ao mesmo tempo?

Quando um lead ou aluno manda mensagem no WhatsApp comercial durante uma abertura de carrinho ou recuperação de vendas, a memória do agente precisa responder a **quatro perguntas simultâneas** antes de gerar a resposta no LLM:

| Pergunta da Memória | Recurso Nativo no SurrealQL | Exemplo Real em Infoproduto no Brasil |
| --- | --- | --- |
| **1. O que isso significa?** (Semântica) | Índice vetorial `HNSW` + operador KNN `embedding <\|3,COSINE\|> $q` | Lead diz *"meu limite do cartão tá tomado pelo valor cheio"*, que tem significado próximo de parcelamento inteligente ou Pix parcelado. |
| **2. O que foi dito exatamente?** (Léxico) | Índice `FULLTEXT` com `ANALYZER` em português + `BM25` (`text @@ 'parcelado'`) | Localizar menções exatas a `"Pix"`, `"Kiwify"`, `"Hotmart"`, `"garantia"`, código de cupom ou regra de lote. |
| **3. A que isso se conecta?** (Grafo) | Arestas `RELATE` e travessia `->mentions->entity->relates_to->entity` | Saber que a oferta mencionada inclui um Order Bump específico, usa checkout Pagar.me e pertence à closer Marina. |
| **4. Quando, por quem e de que tipo?** (Metadados) | Campos tipados do documento (`kind`, `speaker`, `said_at`) | Distinguir uma fala recente do lead (`kind = 'turn'`) de um documento fixo de política de reembolso (`kind = 'document'`). |

Na maioria das stacks tradicionais de IA, cada uma dessas perguntas mora em um serviço diferente (PostgreSQL + Pinecone/Qdrant + Elasticsearch + Neo4j), exigindo múltiplas chamadas de rede e reconciliação manual em TypeScript ou Python. No SurrealDB, elas são **quatro índices operando na mesma tabela `memory`**.

::callout{type="info" title="Inspirado na engenharia oficial do SurrealDB, adaptado ao cenário brasileiro"}
Este guia adapta o padrão arquitetural apresentado por Tobie Morgan Hitchcock no artigo oficial [*Agent memory in one SurrealQL query: vectors, graph, text*](https://surrealdb.com/blog/agent-memory-in-one-surrealql-query-vectors-graph-text) para a realidade de operações digitais brasileiras: funis de WhatsApp, recuperação de checkout e suporte a alunos.
::

## Como modelar a memória do agente no SurrealQL?

A modelagem inteira exige apenas **duas tabelas de registros** (`memory` e `entity`) e **duas tabelas de relação em grafo** (`mentions` e `relates_to`).

Cada registro em `memory` armazena um `embedding`: um array de números de ponto flutuante que representa o significado semântico do texto. Em produção, modelos reais geram vetores longos para capturar nuances finas de significado:
- **`text-embedding-3-small` (OpenAI):** `1536` dimensões;
- **`text-embedding-3-large` (OpenAI):** `3072` dimensões;
- **`voyage-3.5` (Voyage AI, recomendado pela Anthropic):** `1024` dimensões por padrão.

Como vetores de `1024` ou `1536` números seriam ilegíveis em um exemplo didático, os blocos abaixo utilizam vetores de **3 números** (`array<float, 3>`). Para levar o mesmo código para produção, basta alterar o tamanho do tipo e o parâmetro `DIMENSION` do índice HNSW.

::code-demo{lang="surql" title="schema-memoria-infoproduto.surql"}
-- 1. Memórias: o que foi dito, por quem, quando e o que significa
DEFINE TABLE memory SCHEMAFULL;
DEFINE FIELD text      ON memory TYPE string;
DEFINE FIELD kind      ON memory TYPE 'turn' | 'document';
DEFINE FIELD speaker   ON memory TYPE string;
DEFINE FIELD said_at   ON memory TYPE datetime;
DEFINE FIELD embedding ON memory TYPE array<float, 3>;

-- Índice vetorial HNSW: encontra memórias por significado semântico
DEFINE INDEX memory_embedding ON memory
  FIELDS embedding HNSW DIMENSION 3 DIST COSINE;

-- Analisador de texto em português: separa palavras, remove acentos
-- e reduz cada termo ao radical (ex.: "parcelamentos" -> "parcel")
DEFINE ANALYZER memo_text
  TOKENIZERS blank, punct
  FILTERS lowercase, ascii, snowball(portuguese);

-- Índice Full-Text BM25: encontra memórias pelas palavras exatas
DEFINE INDEX memory_text ON memory
  FIELDS text FULLTEXT ANALYZER memo_text BM25 HIGHLIGHTS;

-- 2. Entidades: especialistas, infoprodutos, order bumps e sistemas
DEFINE TABLE entity SCHEMAFULL;
DEFINE FIELD name ON entity TYPE string;
DEFINE FIELD kind ON entity TYPE string;

-- 3. Arestas de grafo: de uma memória para a entidade que ela menciona
DEFINE TABLE mentions TYPE RELATION IN memory OUT entity;

-- Garante que cada memória mencione a mesma entidade apenas uma vez
DEFINE INDEX unique_mention ON mentions FIELDS in, out UNIQUE;

-- 4. Arestas entre entidades (ex.: especialista -> produto -> checkout)
DEFINE TABLE relates_to TYPE RELATION IN entity OUT entity;
DEFINE FIELD label ON relates_to TYPE string;
::

Repare em um detalhe crucial para produtos no Brasil: no `DEFINE ANALYZER memo_text`, combinamos o filtro `ascii` (que normaliza acentuação como `"inscrição"` e `"inscricao"`) com `snowball(portuguese)`. Assim, quando o agente busca por `"parcelamento"`, o índice BM25 encontra automaticamente variações como `"parcelamentos"`, `"parcelado"` ou `"parcelar"`.

## Carregando o grafo de um lançamento e as memórias do agente

Imagine um agente de IA que auxilia o time comercial de uma escola online ou infoprodutor durante a semana de abertura de carrinho. Na nossa operação existem quatro entidades conectadas:

- **`entity:marina`**: Marina, head comercial e responsável pela oferta;
- **`entity:mentoria_ia`**: o produto principal (*Mentoria IA para Infoprodutores*);
- **`entity:checkout_pagarme`**: o motor de pagamentos com split e retentativa (veja quanto você economiza na nossa [Calculadora de Taxas Hotmart, Kiwify e Pagar.me](/ferramentas/calculadora-taxas-hotmart-kiwify));
- **`entity:bump_prompts`**: o Order Bump (*Pack de Prompts de Copy e Vendas*) oferecido no checkout.

Primeiro, criamos as entidades e conectamos o grafo de negócio com `RELATE`:

::code-demo{lang="surql" title="seed-grafo-infoproduto.surql"}
-- Pessoas, infoprodutos e sistemas do funil
CREATE entity:marina           CONTENT { name: 'Marina', kind: 'person' };
CREATE entity:mentoria_ia      CONTENT { name: 'Mentoria IA', kind: 'product' };
CREATE entity:checkout_pagarme CONTENT { name: 'Checkout Pagar.me', kind: 'system' };
CREATE entity:bump_prompts     CONTENT { name: 'Order Bump Prompts', kind: 'product' };

-- Como as entidades se relacionam no ecossistema do infoproduto
RELATE entity:marina->relates_to->entity:mentoria_ia           SET label = 'owns';
RELATE entity:mentoria_ia->relates_to->entity:checkout_pagarme SET label = 'uses';
RELATE entity:mentoria_ia->relates_to->entity:bump_prompts     SET label = 'includes_bump';
::

Em seguida, gravamos quatro memórias e ligamos cada uma às entidades mencionadas. Três são turnos de conversa (`kind: 'turn'`) registrados na operação e uma é um trecho da documentação técnica do checkout (`kind: 'document'`):

::code-demo{lang="surql" title="seed-memorias-conversas.surql"}
CREATE memory:m1 CONTENT {
  text: 'Marina liberou o parcelamento via Pix em 4x na Mentoria IA até sexta antes de fechar o carrinho',
  kind: 'turn',
  speaker: 'user',
  said_at: d'2026-11-02T09:00:00Z',
  embedding: [0.9, 0.1, 0.0]
};

CREATE memory:m2 CONTENT {
  text: 'O Checkout Pagar.me repete pagamentos recusados no cartão três vezes com backoff automático',
  kind: 'document',
  speaker: 'docs',
  said_at: d'2026-10-20T09:00:00Z',
  embedding: [0.8, 0.3, 0.1]
};

CREATE memory:m3 CONTENT {
  text: 'O criativo de Reels do lote 2 precisa de um gancho novo nos primeiros 3 segundos',
  kind: 'turn',
  speaker: 'user',
  said_at: d'2026-11-01T12:00:00Z',
  embedding: [0.0, 0.2, 0.9]
};

CREATE memory:m4 CONTENT {
  text: 'O Order Bump Prompts entra junto no parcelamento especial da Mentoria IA sem taxa extra',
  kind: 'turn',
  speaker: 'user',
  said_at: d'2026-11-03T10:00:00Z',
  embedding: [0.7, 0.2, 0.2]
};

-- Conecta cada memória às entidades que ela menciona
RELATE memory:m1->mentions->entity:marina;
RELATE memory:m1->mentions->entity:mentoria_ia;
RELATE memory:m2->mentions->entity:checkout_pagarme;
RELATE memory:m4->mentions->entity:bump_prompts;
RELATE memory:m4->mentions->entity:mentoria_ia;
::

::read-more{to="/blog/surrealdb-vetores-grafos-agentes-ia-brasil" title="Uma query, não dois bancos: vetores e grafos no SurrealDB para Pix e cursos"}
::

## O que cada índice retorna quando consultado separadamente?

Antes de unir tudo em uma única query, vale observar como o índice vetorial e o índice de texto completo se comportam isoladamente quando um lead pergunta sobre as condições de pagamento da mentoria (vetor `$q = [0.85, 0.15, 0.05]`):

- O operador KNN `<|3,COSINE|>` busca as três memórias mais próximas em significado semântico, e `vector::distance::knn()` calcula a distância de cosseno de cada uma.
- O operador Full-Text `@0@` busca a palavra analisada no texto, enquanto `search::score(0)` e `search::highlight('<b>', '</b>', 0)` entregam a pontuação de relevância BM25 e o trecho exato destacado.

::code-demo{lang="surql" title="busca-isolada-vetor-vs-bm25.surql"}
-- Embedding da pergunta do lead/agente
LET $q = [0.85, 0.15, 0.05];

-- 1. Busca apenas por significado (HNSW KNN): as 3 memórias mais próximas
SELECT id, text, vector::distance::knn() AS distance
FROM memory
WHERE embedding <|3,COSINE|> $q
ORDER BY distance;

-- 2. Busca apenas por palavras (Full-Text BM25): memórias com radical de "parcelamento"
SELECT
  id,
  text,
  search::score(0) AS score,
  search::highlight('<b>', '</b>', 0) AS hit
FROM memory
WHERE text @0@ 'parcelamento'
ORDER BY score DESC;
::

A busca vetorial pura traz `memory:m1` (distância `0.0037`), `memory:m2` (o documento técnico de retentativa de cartão, distância `0.0185`) e `memory:m4` (distância `0.0272`), deixando de fora `memory:m3` (sobre criativo de Reels). Já a busca por palavras com BM25 encontra exatamente `memory:m1` e `memory:m4`, que contêm o termo `"parcelamento"` destacado em `<b>parcelamento</b>`.

::video-player{src="https://www.youtube.com/watch?v=lgl9RYrxf90" title="Embeddings e busca vetorial por significado no SurrealDB"}
::

## Como recuperar significado, palavras e grafo em uma única query SurrealQL?

Agora juntamos todas as condições na mesma cláusula `WHERE` e atravessamos o grafo diretamente na projeção do `SELECT`.

A consulta abaixo localiza memórias próximas ao vetor da pergunta (`<|3,COSINE|>`), que contenham o termo `"parcelamento"` (`@@`), que sejam turnos reais de conversa (`kind = 'turn'`) ocurridos após `1º de novembro de 2026`. Para cada memória encontrada, a mesma query percorre as arestas `mentions` e `relates_to` para descobrir **quais sistemas e Order Bumps são afetados** e **quem é a pessoa dona daquela oferta** — tudo dentro de um bloco `BEGIN ... COMMIT` com leitura consistente:

::code-demo{lang="surql" title="recall-completo-em-uma-query.surql"}
BEGIN;

LET $q = [0.85, 0.15, 0.05];

SELECT
  id,
  text,
  speaker,
  said_at,
  vector::distance::knn() AS distance,
  -- Entidades mencionadas diretamente na memória
  ->mentions->entity.name AS mentions,
  -- Sistemas e produtos conectados às entidades mencionadas (2º salto do grafo)
  ->mentions->entity->relates_to->entity.name AS connected_to,
  -- Quem é dono do produto mencionado (travessia reversa filtrada por aresta)
  ->mentions->entity<-(relates_to WHERE label = 'owns')<-entity.name AS owners
FROM memory
WHERE embedding <|3,COSINE|> $q            -- por significado (vetor HNSW)
  AND text @@ 'parcelamento'               -- por palavras exatas (BM25)
  AND kind = 'turn'                        -- por tipo de registro
  AND said_at > d'2026-11-01T00:00:00Z'   -- por janela de tempo
ORDER BY distance;

COMMIT;
::

O resultado devolvido ao agente em uma única viagem ao banco é um pacote de contexto completo e auditável:

```json
[
  {
    "id": "memory:m1",
    "text": "Marina liberou o parcelamento via Pix em 4x na Mentoria IA até sexta antes de fechar o carrinho",
    "speaker": "user",
    "said_at": "2026-11-02T09:00:00Z",
    "distance": 0.0037,
    "mentions": ["Mentoria IA", "Marina"],
    "connected_to": ["Checkout Pagar.me", "Order Bump Prompts", "Mentoria IA"],
    "owners": ["Marina"]
  },
  {
    "id": "memory:m4",
    "text": "O Order Bump Prompts entra junto no parcelamento especial da Mentoria IA sem taxa extra",
    "speaker": "user",
    "said_at": "2026-11-03T10:00:00Z",
    "distance": 0.0272,
    "mentions": ["Order Bump Prompts", "Mentoria IA"],
    "connected_to": ["Checkout Pagar.me", "Order Bump Prompts"],
    "owners": ["Marina"]
  }
]
```

Observe como cada item retornado entrega ao agente de vendas do WhatsApp exatamente o que ele precisa para responder com segurança:
1. **Significado:** a memória tem altíssima proximidade semântica (`distance: 0.0037`) com a dúvida do lead;
2. **Palavras exatas:** o filtro léxico garante que a regra fala especificamente sobre `parcelamento` na conversa atual;
3. **Conexões de negócio:** o grafo revela que a `Mentoria IA` usa o `Checkout Pagar.me`, possui o `Order Bump Prompts` vinculado e tem `Marina` como responsável comercial (`owners`).

O documento genérico sobre retentativa de cartão (`memory:m2`) ficou de fora porque não é um turno de conversa nem trata do parcelamento liberado, e a conversa sobre Reels (`memory:m3`) nunca teve proximidade semântica suficiente para poluir o prompt.

## O agente pode gravar uma nova memória e consultá-la na mesma transação?

Sim. No SurrealDB, uma transação enxerga imediatamente suas próprias escritas tanto no índice vetorial HNSW quanto no índice Full-Text BM25 e nas arestas do grafo.

Imagine que, no meio do plantão de fechamento de carrinho, a Marina avisa no grupo da operação que prorrogou o corte do Pix parcelado para segunda-feira às 23h59. O webhook grava `memory:m5`, cria os vínculos `RELATE` e já executa o `recall` antes mesmo do `COMMIT`:

::code-demo{lang="surql" title="write-and-recall-transacional.surql"}
BEGIN;

CREATE memory:m5 CONTENT {
  text: 'Marina prorrogou o encerramento do parcelamento da Mentoria IA para segunda-feira',
  kind: 'turn',
  speaker: 'user',
  said_at: d'2026-11-04T08:00:00Z',
  embedding: [0.88, 0.12, 0.02]
};

RELATE memory:m5->mentions->entity:marina;
RELATE memory:m5->mentions->entity:mentoria_ia;

-- A nova memória já está visível nos três índices dentro da mesma transação
SELECT
  id,
  text,
  vector::distance::knn() AS distance,
  ->mentions->entity.name AS mentions
FROM memory
WHERE embedding <|2,COSINE|> [0.85, 0.15, 0.05]
  AND text @@ 'encerramento'
ORDER BY distance;

COMMIT;
::

O `SELECT` retorna imediatamente `memory:m5` com distância `0.0014` e `mentions: ["Mentoria IA", "Marina"]`.

### Proteção contra duplicidade de entidades extraídas por LLM

Quando um agente usa um LLM para extrair entidades de uma mensagem de áudio ou texto no WhatsApp, é muito comum que duas expressões na mesma frase apontem para a mesma entidade do banco. Por exemplo, o cliente diz *"quero entrar na **Mentoria IA** e aproveitar o desconto do **programa de inteligência artificial**"* — e o extrator resolve ambas as expressões para `entity:mentoria_ia`.

Como definimos o índice `DEFINE INDEX unique_mention ON mentions FIELDS in, out UNIQUE`, a segunda tentativa de `RELATE memory:m6->mentions->entity:mentoria_ia` é recusada pelo banco e cancela a transação inteira, impedindo que memórias órfãs ou arestas duplicadas sujem o grafo:

::code-demo{lang="surql" title="transacao-protegida-unique-mention.surql"}
BEGIN;

CREATE memory:m6 CONTENT {
  text: 'A Mentoria IA exige confirmação de webhook no Checkout Pagar.me para liberar o programa',
  kind: 'turn',
  speaker: 'user',
  said_at: d'2026-11-05T08:00:00Z',
  embedding: [0.8, 0.25, 0.05]
};

RELATE memory:m6->mentions->entity:mentoria_ia;
RELATE memory:m6->mentions->entity:checkout_pagarme;

-- Se "o programa" também foi resolvido para entity:mentoria_ia pelo LLM,
-- o índice unique_mention barra a aresta duplicada e desfaz toda a transação:
RELATE memory:m6->mentions->entity:mentoria_ia;

COMMIT;
::

::callout{type="tip" title="Dica prática para deduplicar no código da aplicação"}
Ao extrair entidades com IA (usando [Cloudflare Workers AI](/blog/cloudflare-workers-ai-custo), Claude ou OpenAI), aplique um `Array.from(new Set(entityIds))` no back-end antes de disparar os comandos `RELATE` (ou utilize nosso [Conversor de JSON para SurrealQL](/ferramentas/json) para validar o formato dos registros) e mantenha o índice `UNIQUE` no banco como guarda final de integridade.
::

## Prompt de sistema para o agente comercial usar a memória híbrida

Recuperar os dados certos em uma query SurrealQL é metade do trabalho; a outra metade é instruir o LLM a respeitar a hierarquia entre **regras atuais da oferta**, **conexões do grafo** e **documentação fixa**:

::prompt-snippet{title="Agente Closer / Suporte de Infoproduto com Memória SurrealQL"}
Você é o assistente comercial e de suporte da operação. Responda à mensagem do lead no WhatsApp usando exclusivamente as memórias recuperadas pelo SurrealDB.

MEMÓRIAS RECUPERADAS (ordenadas por proximidade semântica):
- Cada item contém: `text` (o que foi dito), `said_at` (data/hora), `mentions` (produtos/pessoas citados), `connected_to` (Order Bumps e sistemas de checkout vinculados) e `owners` (responsável pela oferta).

REGRAS DE DECISÃO:
1. Priorize fatos mais recentes (`said_at`) quando houver prorrogação de lote, cupom ou parcelamento.
2. Se o produto mencionado tiver um Order Bump em `connected_to`, apresente o benefício complementar de forma natural quando o lead perguntar sobre condições de pagamento.
3. Nunca invente links de pagamento, descontos ou prazos que não estejam explícitos em `text`.
4. Se a dúvida exigir aprovação de exceção comercial, informe que vai acionar a pessoa listada em `owners`.
::

## Trilha recomendada para implementar no seu produto

Se você quer sair de agentes que esquecem tudo a cada mensagem e construir sua própria infraestrutura de IA e automação comercial em português, siga estes próximos passos no portal:

1. **[Curso Grátis: SurrealDB Agent Memory (15 aulas)](/cursos/surrealdb-agent-memory):** aprenda a usar fatos com fonte, reconciliação temporal (`remember`, `recall`, `reflect`) e servidor MCP no Claude Code;
2. **[Curso Grátis: SurrealDB para Engenheiros de IA (11 aulas)](/cursos/surrealdb-para-engenheiros-de-ia):** domine índices HNSW, BM25, RAG híbrido e Graph RAG passo a passo;
3. **[SurrealDB 4 e SurrealDB Earth na Cloudflare](/blog/surrealdb-4-earth-saas-agentes-ia):** entenda como rodar instâncias serverless do SurrealDB na borda da Cloudflare integradas aos seus Workers;
4. **[Crie sua conta no SurrealDB Cloud pelo link da Escola](https://l.escoladeaplicativos.com.br/surrealdb):** teste todas as queries deste artigo diretamente no Surrealist Studio.

## Perguntas frequentes sobre memória de agentes em uma query SurrealQL

### Como buscar vetores, grafos e texto na mesma query no SurrealDB?

Basta combinar na cláusula `WHERE` de um único `SELECT` o operador de vizinhança vetorial KNN (`embedding <|K,COSINE|> $vetor`), o operador de busca textual BM25 (`text @@ 'termo'`) e filtros em campos escalares (`kind`, `said_at`), projetando as travessias de grafo (`->mentions->entity->relates_to->entity.name`) nas colunas retornadas dentro de uma transação `BEGIN ... COMMIT`.

### Por que usar o analisador `snowball(portuguese)` no índice Full-Text do SurrealDB?

O filtro `snowball(portuguese)` aliado ao filtro `ascii` no `DEFINE ANALYZER` remove acentos e reduz palavras em português ao seu radical morfológico (stemming). Com isso, uma busca por `"parcelamento"` encontra automaticamente memórias que contenham `"parcelamentos"`, `"parcelado"` ou `"parcelar"`, aumentando a precisão do ranking BM25 em conversas reais de WhatsApp.

### Qual a vantagem de usar SurrealDB em vez de Postgres + Pinecone + Neo4j para agentes de IA?

Unificar documentos, vetores HNSW, busca textual BM25 e relações de grafo no SurrealDB elimina a latência e a complexidade de sincronizar três ou quatro bancos diferentes no código da aplicação. Além disso, todas as escritas e leituras ocorrem na mesma transação ACID, garantindo que uma memória recém-gravada e suas conexões de grafo fiquem imediatamente visíveis para o agente.

### Como evitar arestas duplicadas quando o LLM extrai entidades de uma conversa?

Crie uma tabela de relação tipada (`DEFINE TABLE mentions TYPE RELATION IN memory OUT entity`) acompanhada de um índice composto único (`DEFINE INDEX unique_mention ON mentions FIELDS in, out UNIQUE`). Se o modelo de linguagem resolver duas expressões do mesmo texto para a mesma entidade, o índice bloqueia a duplicata e preserva a integridade transacional do grafo.

### Qual dimensão de embedding devo configurar no índice HNSW em produção?

O parâmetro `DIMENSION` do índice HNSW deve corresponder exatamente ao tamanho do vetor gerado pelo seu modelo de embedding: use `1536` para `text-embedding-3-small` da OpenAI, `3072` para `text-embedding-3-large` ou `1024` para `voyage-3.5` da Voyage AI.