混合检索策略
混合检索策略:Claude-Mem 的具体实现
学习目标
本章聚焦 Claude-Mem 如何同时使用 SQLite FTS5 和 Chroma 向量数据库进行混合检索。建议先阅读前置知识,下文直接聚焦具体落地方案。
前置知识
本章涉及混合检索的通用原理,建议先阅读:
- 记忆系统的多信号混合检索 — 多信号融合评分公式
项目实践
SQLite FTS5 全文搜索
Claude-Mem 的 SQLite 数据库使用 FTS5 虚拟表实现快速全文搜索。搜索覆盖以下字段:
observations.text— 观察的主要文本内容observations.title— 观察标题observations.narrative— 叙述性描述observations.facts— 关键事实列表session_summaries的各文本字段
FTS5 支持布尔查询语法(AND、OR、NOT、前缀匹配),适合精确关键词检索。
Chroma 向量同步
ChromaSync 类(src/services/sync/ChromaSync.ts,约 36KB)负责将 SQLite 中的观察和摘要同步到 Chroma 向量数据库:
关键设计:
- 水位线机制:
ChromaSyncState记录每个项目最后同步的观察 ID,每次同步只处理新增部分 - 每项目独立集合:集合名格式为
cm__{sanitized_project_name},确保不同项目的向量隔离 - 批量写入:
BATCH_SIZE = 100,避免单次请求过大 - 元数据过滤:Chroma 文档携带
project、type、memory_session_id等元数据,支持查询时过滤
Chroma 通过 MCP 调用
Claude-Mem 不直接嵌入 Chroma SDK,而是通过 MCP 工具调用与 Chroma 交互:
ChromaMcpManager管理 Chroma MCP 服务器的连接- 通过
@modelcontextprotocol/sdk的 Client 调用chroma_query、chroma_add等工具 - 好处:Chroma 作为独立进程运行,不阻塞 Worker 主进程
混合搜索策略
当 Agent 执行 search 工具时,Claude-Mem 的搜索管线按以下顺序执行:
- FTS5 查询:将用户查询转为 FTS5 语法,获取匹配结果
- 结果格式化:将 SQLite 行转为紧凑的索引格式(ID + 标题 + 日期 + 类型)
- Chroma 补充(可选):在 FTS5 结果不足时,通过 Chroma 语义搜索补充
- 去重合并:按相关性评分排序,返回 Top-K
问题与规避
Chroma 进程管理
问题:Chroma 依赖 Python 环境,需要通过 uv(Python 包管理器)管理。
规避:Claude-Mem 在 Setup Hook 中检查并自动安装 uv,通过 uv 安装和运行 Chroma。Worker Service 启动时检查 Chroma MCP 服务器的健康状态。
集合名 sanitization
问题:Chroma 集合名有严格的命名限制(仅允许字母、数字、点、下划线、连字符)。
规避:ChromaSync 构造函数中将项目名通过正则替换为安全格式:cm__{sanitized_name},并将非法字符替换为下划线。
设计取舍
为什么用 MCP 调用 Chroma 而非直接 SDK?
- 优势:Chroma 作为独立进程,崩溃不影响 Worker;可以通过 MCP 协议切换不同的向量数据库后端
- 代价:额外的进程间通信开销
- 替代方案:直接使用
chromadbPython SDK 或 JS binding。Claude-Mem 选择 MCP 路径以保持进程隔离和可扩展性