Dê Memória Semântica ao Hermes Agent com LanceDB: Instalação, Configuração, Benchmark


Uma das experiências mais frustrantes com um agente de IA é ele esquecer as coisas. Na segunda-feira você diz: “uso pnpm workspaces e faço deploy via wrangler.” Na sexta-feira, em uma sessão nova, ele não faz ideia do que você está falando. O Hermes Agent até tem memória integrada (MEMORY.md / USER.md em ~/.hermes/memories/) e recall entre sessões — mas, no fundo, é correspondência lexical. Diga “deploy” como “ship it”, ou “pnpm” como “o gerenciador de pacotes”, e a memória simplesmente não é encontrada.

Em agosto de 2026, a LanceDB lançou um plugin oficial de memória semântica para o Hermes Agent — hermes-agent-memory — que transforma isso em um problema puramente de engenharia: os fatos são armazenados como vetores em uma tabela LanceDB local, e o recall faz a correspondência por similaridade semântica em vez de palavras-chave. No benchmark LongMemEval do plugin, o recall puramente vetorial marca 0.661 de precisão / 0.795 de Recall@5, claramente à frente da busca de sessão FTS5 integrada do Hermes, com 0.533 / 0.659.

Este post guia você por toda a instalação, explica como funcionam as quatro ferramentas de memória, como escolher entre os modos de recuperação híbrida e faz uma leitura cuidadosa dos números do benchmark.


1. Entenda primeiro a arquitetura de memória do Hermes

Antes de instalar qualquer coisa, gaste dois minutos entendendo como a camada de memória do Hermes foi desenhada — caso contrário, você pode instalar tudo e ficar se perguntando por que nada funciona.

A memória do Hermes é uma arquitetura de providers. agent/memory_provider.py define uma interface abstrata MemoryProvider, e agent/memory_manager.py a orquestra (prefetch, sync, shutdown). Dois hooks importam mais:

  • on_pre_compress(messages) — extrai o que vale a pena manter antes de a compressão de contexto rodar;
  • on_session_end(messages) — uma passada final de extração ao fim de uma sessão.

O comando interativo hermes memory setup varre os providers instalados em plugins/memory/, deixa você escolher um e grava memory.provider: <name> em ~/.hermes/config.yaml (a linha 277 de hermes_cli/memory_setup.py é exatamente essa gravação). Em outras palavras: o backend de memória é um registro plugável. De fábrica, o Hermes vem com oito providers: mem0, hindsight, honcho, supermemory, byterover, retaindb, holographic e openviking.

O plugin LanceDB usa o mesmo canal: ele se registra como memory provider, é instalado em ~/.hermes/plugins/lancedb/ via hermes plugins install e depois é selecionado no hermes memory setup.

Quer testar sem mexer na sua configuração atual? hermes profile create lancedb-demo cria um perfil isolado; adicione -p lancedb-demo a todos os comandos abaixo e rode rm -rf ~/.hermes/profiles/lancedb-demo quando terminar.

2. Instalação: quatro passos, cerca de cinco minutos

Passo 1: Instale o plugin

hermes plugins install lancedb/hermes-agent-memory

Isso faz um shallow clone de https://github.com/lancedb/hermes-agent-memory.git em ~/.hermes/plugins/lancedb/. Rode o mesmo comando de novo mais tarde para puxar atualizações.

Passo 2: Instale as dependências de runtime no Python do próprio Hermes

O Hermes carrega plugins dentro do próprio interpretador, então as dependências precisam ir para a venv do Hermes — não para um virtualenv separado:

# Se você usou o instalador de uma linha:
uv pip install --python ~/.hermes/hermes-agent/venv/bin/python3 lancedb openai pyyaml

Nota: o interpretador do Hermes é compartilhado entre todos os perfis, então este passo não tem a flag -p e só precisa rodar uma vez. A configuração padrão não precisa de stack de ML local — os embeddings passam pela API da OpenAI. Só se você habilitar o reranker cross-encoder é que precisará de sentence-transformers (que arrasta ~2GB de torch).

Passo 3: Ative o provider

hermes memory setup
# escolha "lancedb" no menu interativo

Espere uma saída assim, com memory.provider: lancedb gravado em ~/.hermes/config.yaml:

# ✓ LanceDB memory configured (embedding dim: 1536)
#  Start a new session to activate.

Os embeddings usam por padrão o modelo text-embedding-3-small da OpenAI (1536 dimensões), então é preciso ter uma OPENAI_API_KEY disponível.

Passo 4: Verifique (não pule este passo)

O relato mais comum de “a memória não está funcionando” é simplesmente o provider não estar ativo — se memory.provider não estiver definido, o Hermes cai silenciosamente para as notas integradas e você nunca verá as ferramentas lancedb_*. Confirme que está ligado:

hermes memory status          # procure por: Provider: lancedb, installed ✓, available ✓
hermes plugins list           # deve listar "lancedb"
hermes chat -q "Hello"        # o agent.log deve conter "lancedb provider initialized"

Se memory status não mostrar nada (ou mostrar o provider errado), rode hermes memory setup de novo e escolha lancedb novamente.

3. As quatro ferramentas de memória

Uma vez ativo, o agente ganha quatro novas ferramentas:

Ferramenta Finalidade
lancedb_recall Recall vetorial (padrão) ou híbrido sobre a memória do workspace; retorna IDs, trechos, scores e IDs dos turnos de proveniência
lancedb_remember Armazena um fato durável, tipado como preference / entity / event / case / pattern / general; deduplicado por hash de conteúdo
lancedb_read Busca uma memória pelo ID, opcionalmente com os turnos de proveniência dos quais ela foi extraída
lancedb_forget Exclusão em duas etapas: action: preview lista os candidatos pela descrição; depois action: delete com o ID exato

O bloco de system prompt do provider diz ao modelo quando usar cada ferramenta: lancedb_remember só quando o usuário pedir explicitamente para lembrar, e sempre preview antes de qualquer exclusão — assim o agente não apaga uma memória importante por acidente.

Além das chamadas explícitas, existe um pipeline de extração automática: quando uma sessão acumula turnos suficientes (padrão min_turns: 3), fatos duráveis são extraídos da conversa por um LLM auxiliar, tanto antes da compressão de contexto quanto no fim da sessão. Mesmo que você nunca diga “lembre disto”, informações úteis a longo prazo acabam persistidas — é esse o mecanismo do “o agente fica mais inteligente quanto mais você o usa”.

4. Modos de recuperação: vetorial vs híbrido

O recall é o coração da memória semântica, e o plugin dá a você duas camadas de controle:

1. Modo de busca (por chamada): vector (padrão) ou hybrid (vetorial + full-text BM25), sobrescrito a cada chamada pelo parâmetro mode do lancedb_recall.

2. Fusão híbrida (config global): no modo hybrid, a forma como as pernas vetorial e full-text se combinam é definida por plugins.lancedb.retrieval.reranker.type:

  • rrf (padrão) — Reciprocal Rank Fusion, fusão baseada em rank com pesos iguais;
  • linear — combinação linear ponderada; reranker.weight (padrão 0.7) pende para a perna vetorial;
  • cross-encoder — reranqueia um pool superamostrado com um modelo sentence-transformers local; melhor qualidade, mais lento.

Exemplo de configuração (~/.hermes/config.yaml — grave apenas as chaves que quiser sobrescrever):

plugins:
  lancedb:
    retrieval:
      mode: hybrid          # vector (default) | hybrid
      top_k: 10
      reranker:
        type: linear        # rrf | linear | cross-encoder
        weight: 0.7

Também existe um modo fts puramente lexical, mas os autores recomendam explicitamente não usá-lo: a correspondência apenas por palavras-chave tende a trazer linhas coincidentes e irrelevantes que poluem o contexto do agente. O recall semântico vive no vector / hybrid.

5. Backends de embedding: não só OpenAI

Na configuração padrão, a única chamada remota é a API de embeddings — todo o resto é local. Aponte o cliente compatível com OpenAI para qualquer endpoint que fale o mesmo formato e pronto, sem mudar código. Alguns exemplos práticos:

# Modelo não-OpenAI via OpenRouter
plugins:
  lancedb:
    embedding:
      model: google/gemini-embedding-001
      base_url: https://openrouter.ai/api/v1
      api_key_env: OPENROUTER_API_KEY

# Totalmente local: Ollama
plugins:
  lancedb:
    embedding:
      model: nomic-embed-text
      base_url: http://localhost:11434/v1
      api_key_env: OLLAMA_API_KEY    # any value works for local Ollama

Trocar de modelo de embedding exige cuidado: se a dimensão do novo modelo não bater com a tabela existente, o plugin falha de forma ruidosa em vez de retornar nada silenciosamente. A solução é apagar ~/.hermes/lancedb/memories.lance/ e deixar a próxima sessão recriar a tabela (tudo bem se você não se importar com as memórias antigas).

O LLM auxiliar usado para extração de fatos também pode apontar para um modelo mais barato, pelo roteamento auxiliar do próprio Hermes (roteamento de provider, fallback e esgotamento de créditos tratados para você):

auxiliary:
  lancedb_extraction:
    provider: openrouter
    model: google/gemini-3-flash

6. Lendo o benchmark: o recall semântico é realmente melhor?

O repositório do plugin traz um harness de QA de conversas longas LongMemEval-S (60 casos estratificados, respondidos por gpt-5.4, avaliados por gpt-5.4-mini, top-k 5). Ele compara as opções de recall que um usuário do Hermes realmente tem:

Variante Precisão Recall@5 MRR@5 Query p50
hermes-session-search (baseline FTS5/BM25 integrada) 0.533 0.659 0.639 0.002s
lancedb-vector (padrão) 0.661 0.795 0.682 0.207s
lancedb-hybrid-rrf 0.610 0.650 0.635 0.235s
lancedb-hybrid-linear 0.610 0.718 0.676 0.246s
lancedb-hybrid-cross-encoder 0.678 0.754 0.689 0.702s

Conclusões notáveis:

  • O recall semântico vence claramente a baseline lexical: 0.661 vs 0.533 de precisão, 0.795 vs 0.659 de Recall@5 — a paráfrase (deploy vs ship) é exatamente onde o BM25 fica cego, e a recuperação vetorial é muito mais robusta, a ~0.2s por consulta.
  • O RRF com pesos iguais na verdade atrapalha (0.610 < 0.661): hits lexicais ruidosos deslocam bons resultados vetoriais. É por isso que o padrão de fábrica é vector, e não hybrid.
  • Se você quer sinal lexical, use linear, não RRF: a fusão ponderada recupera o Recall@5 para 0.718 com um custo mínimo de latência.
  • O cross-encoder lidera em qualidade (0.678 / 0.754), mas o p50 sobe para ~0.7s e ele exige torch — para setups tolerantes a latência e sensíveis a precisão.

Os autores classificam esses números como ilustrativos: a precisão absoluta acompanha o modelo que responde (aqui o gpt-5.4), mas a ordem relativa dos métodos de recuperação é estável. O harness também mede apenas o substrato de recuperação (recall verbatim dos turnos originais), não o ciclo completo de extração de fatos — no uso real, a recuperação guiada por fatos pode ir ainda melhor.

7. Layout de armazenamento e auto-compactação

Tudo é local, sem serviço externo:

Caminho Conteúdo
~/.hermes/lancedb/memories.lance/ Dataset LanceDB (fragments, manifest, índices). Tabela única memories; a coluna kind separa linhas de fato e de turno
~/.hermes/lancedb/.last_optimize_version Arquivo sentinela: table.version no último optimize() bem-sucedido
~/.cache/huggingface/ Cache do reranker cross-encoder; só existe quando reranker.type: cross-encoder está habilitado

Quer fuçar no store diretamente, estilo SQL:

uv run --project ~/.hermes/hermes-agent python -c "
import lancedb
db = lancedb.connect('~/.hermes/lancedb')
df = db.open_table('memories').to_pandas()
print(df[['kind', 'category', 'content']].head())
"

As cargas de trabalho de agentes são dominadas por escritas de linha única, e cada add/delete do Lance é um commit — sem intervenção, pequenos fragments e arquivos de versão se acumulam para sempre. A auto-compactação do plugin (ligada por padrão) compara a versão com o arquivo sentinela e roda table.optimize(cleanup_older_than=timedelta(days=7)) em uma thread daemon quando o delta cruza optimize_every_commits (padrão 50). Um lock não bloqueante garante um optimize por vez e os writers nunca são bloqueados. Desabilite (maintenance.enabled: false) e o dataset crescerá sem limite — geralmente não recomendado.

8. Referência rápida de solução de problemas

  • hermes plugins list não mostra lancedb: confira se o symlink ~/.hermes/plugins/lancedb resolve para o repositório.
  • O agente só grava a memória integrada, sem ferramentas lancedb_*: o provider não está ativo. Rode hermes memory status — você quer ver Provider: lancedb com available ✓; se estiver vazio, rode hermes memory setup de novo.
  • O recall falha com erro de autenticação: os embeddings chamam a API da OpenAI — garanta que OPENAI_API_KEY está definida (no ambiente ou em ~/.hermes/.env).
  • O diretório .lance não para de crescer: confirme maintenance.enabled: true e que ~/.hermes/lancedb/.last_optimize_version avança entre sessões; lancedb optimize starting no agent.log significa que a compactação está rodando.
  • Mudou embedding.model e o recall não retorna nada: incompatibilidade de dimensão. Apague ~/.hermes/lancedb/memories.lance/ para recriar a tabela.

Conclusão

O plugin LanceDB preenche a lacuna mais importante na memória de longo prazo do Hermes Agent: recall pelo significado, não pela palavra-chave. Cinco minutos para instalar, zero ajuste fino nos padrões, todos os dados locais — em troca de ~24% a mais de precisão (0.661 vs 0.533) e um grande salto de Recall@5 no LongMemEval. Para trabalhadores do conhecimento, significa que “as coisas que você disse uma vez voltam mesmo quando você pergunta de outro jeito”.

Leituras relacionadas: