给 Hermes Agent 装上语义记忆:LanceDB 插件安装、配置与基准测试


AI 代理最让人沮丧的体验之一,是它“转头就忘”。你在周一告诉它“我用 pnpm workspace,部署走 wrangler”,周五新开一个会话再问,它一脸茫然。Hermes Agent 的内置记忆(~/.hermes/memories/ 下的 MEMORY.md / USER.md)和跨会话回溯确实存在,但本质上是词汇匹配——你把“部署”换成“发布”,把“pnpm”说成“包管理器”,它就找不到那条记忆了。

2026 年 8 月,LanceDB 官方发布了一个 Hermes Agent 的语义记忆插件 hermes-agent-memory,把这个问题变成了纯工程问题:事实以向量形式存入本地的 LanceDB 表,召回时按语义相似度而非关键词匹配。官方 LongMemEval 基准里,纯向量召回的准确率 0.661、Recall@5 0.795,明显超过 Hermes 内置 FTS5 会话搜索的 0.533 / 0.659。

这篇文章手把手带你装好它,讲清四个记忆工具怎么用、三种混合检索怎么选,并把基准数据拆开解读。


一、先理解 Hermes 的记忆架构

在装插件之前,值得花两分钟搞懂 Hermes 的记忆层是怎么设计的,否则你很可能装完发现“没生效”。

Hermes 的记忆系统是provider 架构agent/memory_provider.py 定义了一个 MemoryProvider 抽象接口,agent/memory_manager.py 负责统一调度(预取、同步、关停)。核心钩子有两个:

  • on_pre_compress(messages) —— 上下文压缩之前,把值得记住的内容提取出来;
  • on_session_end(messages) —— 会话结束时做一轮提取。

hermes memory setup 这个交互式命令会扫描 plugins/memory/ 下已安装的 provider 让你选择,选中后把 memory.provider: <名称> 写进 ~/.hermes/config.yaml(源码 hermes_cli/memory_setup.py 第 277 行就是这行写入)。也就是说:记忆后端是一个可插拔的注册表,默认情况下 Hermes 自带 8 个 provider:mem0、hindsight、honcho、supermemory、byterover、retaindb、holographic、openviking。

LanceDB 插件走的是同一条通道:它把自己注册为一个 memory provider,通过 hermes plugins install 装进 ~/.hermes/plugins/lancedb/,再在 hermes memory setup 里选中即可。

想先用独立环境试玩?hermes profile create lancedb-demo 建一个隔离 profile,后面所有命令加 -p lancedb-demo,用完 rm -rf ~/.hermes/profiles/lancedb-demo 即可,完全不碰你现有的 Hermes。

二、安装:四步,约五分钟

第 1 步:安装插件本体

hermes plugins install lancedb/hermes-agent-memory

这条命令会浅克隆 https://github.com/lancedb/hermes-agent-memory.git~/.hermes/plugins/lancedb/。以后要更新,重跑同一条命令即可。

第 2 步:把运行时依赖装进 Hermes 自己的 Python 环境

Hermes 在它自己的解释器里加载插件,所以依赖必须装进 Hermes 的 venv,而不是单独建虚拟环境:

# 用官方一键安装脚本装的话:
uv pip install --python ~/.hermes/hermes-agent/venv/bin/python3 lancedb openai pyyaml

注意:Hermes 的解释器是所有 profile 共享的,所以这步不带 -p,而且只需要装一次。默认配置不需要任何本地 ML 环境——embedding 走 OpenAI API。只有当你启用 cross-encoder 重排器时才需要 sentence-transformers(会拖进约 2GB 的 torch)。

第 3 步:激活 provider

hermes memory setup
# 在交互菜单里选 "lancedb"

成功后会看到类似输出,并把 memory.provider: lancedb 写入 ~/.hermes/config.yaml

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

embedding 默认用 OpenAI text-embedding-3-small(1536 维),所以环境里要有 OPENAI_API_KEY

第 4 步:验证(别跳过这步)

“记忆没生效”的反馈里,最常见的原因就是 provider 根本没激活——memory.provider 没设置时,Hermes 会静默回退到内置 notes,你永远调不到 lancedb_* 工具。确认命令:

hermes memory status          # 期待: Provider: lancedb, installed ✓, available ✓
hermes plugins list           # 应该列出 "lancedb"
hermes chat -q "Hello"        # agent.log 里应出现 "lancedb provider initialized"

如果 memory status 显示空白或别的 provider,重跑 hermes memory setup 再选一次。

三、四个记忆工具

激活后,agent 的工具箱里会多出四个工具:

工具 作用
lancedb_recall 按向量(默认)或混合模式召回工作区记忆,返回 ID、片段、相似度分数、溯源 turn ID
lancedb_remember 存储一条持久事实,类别为 preference(偏好)/ entity(实体)/ event(事件)/ case(案例)/ pattern(模式)/ general(通用),按内容哈希去重
lancedb_read 按 ID 取回一条记忆,可选附带提取它的完整上下文 turn
lancedb_forget 两步删除:先 action: preview 按描述列出候选,再 action: delete 用精确 ID 删除

插件的系统提示会引导模型何时用哪个工具:只有用户明确要求记住时才调用 lancedb_remember;删除前必须先 preview——避免 agent 手滑把重要记忆抹掉。

除了显式调用,插件还有一条自动提取链路:会话中积累足够轮次(默认 min_turns: 3)后,在上下文压缩前和会话结束时,用辅助 LLM 从对话里抽取持久事实写入记忆库。这样即使你不主动说“记住这个”,长期有用的信息也会沉淀下来——这正是“代理越用越聪明”的机制。

四、检索模式:vector 与 hybrid

召回是语义记忆的核心,插件给你两层控制:

1. 检索模式(每个调用可选)vector(默认)或 hybrid(向量 + BM25 全文混合),通过 lancedb_recallmode 参数按次覆盖。

2. 混合融合方式(全局配置)hybrid 模式下向量腿和全文腿怎么合并,由 plugins.lancedb.retrieval.reranker.type 决定:

  • rrf(默认)—— Reciprocal Rank Fusion,基于排名的等权融合;
  • linear —— 加权线性合并,reranker.weight(默认 0.7)偏向向量;
  • cross-encoder —— 用本地 sentence-transformers 模型对超采样池重排,质量最高但最慢。

配置示例(~/.hermes/config.yaml,只写你想覆盖的键):

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

还有一个人为留的 fts 纯词法模式,但官方不推荐:纯关键词匹配容易捞出一堆巧合命中的无关行,污染上下文。语义召回的价值就在 vector / hybrid

五、embedding 后端:不止 OpenAI

默认配置全链路只有 embedding 调用 OpenAI API,其余全部本地。如果你不想用 OpenAI,把 OpenAI 兼容客户端指向任何同形状的端点即可,无需改代码。几个实用例子:

# 通过 OpenRouter 用非 OpenAI 模型
plugins:
  lancedb:
    embedding:
      model: google/gemini-embedding-001
      base_url: https://openrouter.ai/api/v1
      api_key_env: OPENROUTER_API_KEY

# 完全本地:Ollama
plugins:
  lancedb:
    embedding:
      model: nomic-embed-text
      base_url: http://localhost:11434/v1
      api_key_env: OLLAMA_API_KEY    # 本地 Ollama 任意值即可

改 embedding 模型要小心:换模型(或维度)后,旧表里的向量维度不匹配,插件会大声报错而不是静默返回空结果。应对方式是删掉 ~/.hermes/lancedb/memories.lance/ 让下个会话重建表(前提是你不在乎旧记忆)。

提取事实用的辅助 LLM 也可以单独指定便宜的模型,走 Hermes 自己的 auxiliary 路由(自动处理 provider 路由、fallback、额度耗尽):

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

六、基准数据解读:语义召回真的更强吗

插件仓库带了一个 LongMemEval-S 长对话 QA 评测(60 例分层抽样,gpt-5.4 作答、gpt-5.4-mini 评判,top-k 5)。它比较的是 Hermes 用户实际拥有的长期召回手段:

变体 Accuracy Recall@5 MRR@5 查询 p50
hermes-session-search(内置 FTS5/BM25 基线) 0.533 0.659 0.639 0.002s
lancedb-vector(默认) 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

几个值得注意的点:

  • 语义召回显著强于词法基线:纯向量准确率 0.661 对 0.533,Recall@5 0.795 对 0.659——同义改写(“部署” vs “发布”)正是 BM25 的盲区,向量检索在 paraphrase 上明显更稳,而单次查询仍只要约 0.2 秒。
  • RRF 等权融合反而拖后腿(0.610 < 0.661):噪声词法命中会把好的向量结果挤下去。这就是为什么插件默认 vector 而不是 hybrid
  • 想要词法信号,用 linear 而不是 RRF:加权线性融合把 Recall@5 拉回 0.718,代价只是多一点点延迟。
  • cross-encoder 质量封顶(0.678 / 0.754),但 p50 涨到 ~0.7s,且需要 torch——适合对准确率敏感、对延迟不敏感的场景。

作者明确标注这些是 illustrative(示例性)结果:绝对准确率跟着作答模型走(这里是 gpt-5.4),但检索方法的相对排序是稳定的。另外评测只测了“检索基座”(原文 turn 的逐字召回),没跑事实提取链路——真实使用中事实优先检索可能更好。

七、存储与自动压缩

一切数据都在本地,无外部服务:

路径 内容
~/.hermes/lancedb/memories.lance/ LanceDB 数据集(fragments、manifest、索引),单表 memorieskind 列区分 fact / turn
~/.hermes/lancedb/.last_optimize_version 上次成功 compact 的 table.version 哨兵文件
~/.cache/huggingface/ 仅启用 cross-encoder 时出现的重排模型缓存

想直接 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())
"

代理工作负载的特点是单行写入,Lance 每次 add/delete 都是一次 commit,碎片和版本文件会无限累积。插件的自动压缩(默认开)用哨兵文件跟踪版本号,delta ≥ optimize_every_commits(默认 50)时在后台线程跑 table.optimize(cleanup_older_than=timedelta(days=7)),非阻塞锁保证同一时间只有一个 compact 在跑、写入永不被阻塞。关掉它(maintenance.enabled: false)数据集就会无界增长,一般不建议。

八、常见问题速查

  • hermes plugins list 看不到 lancedb:检查 ~/.hermes/plugins/lancedb 软链接是否指向仓库本体。
  • agent 只写内置记忆、没有 lancedb_* 工具:provider 没激活。跑 hermes memory status,期待 Provider: lancedb + available ✓;空白就重跑 hermes memory setup
  • 召回报鉴权错误:embedding 走 OpenAI API,确认 OPENAI_API_KEY 已设置(环境变量或 ~/.hermes/.env)。
  • .lance 目录持续变大:确认 maintenance.enabled: true~/.hermes/lancedb/.last_optimize_version 在跨会话推进;agent.loglancedb optimize starting 出现即代表压缩在跑。
  • 换 embedding 模型后召回全空:维度不匹配。删掉 ~/.hermes/lancedb/memories.lance/ 重建。

总结

LanceDB 插件给 Hermes Agent 补上了长期记忆里最关键的一块拼图:按语义而非关键词召回。安装五分钟、默认配置零调优、数据全在本地,换来的是 LongMemEval 上 ~24% 的准确率提升(0.661 vs 0.533)和两倍多的召回率。对知识工作者来说,这意味着“告诉过它的事,换种说法问也能想起来”。

搭配阅读: