OpenClaw 记忆搜索(Memory Search)完全指南:混合检索、Embedding 供应商与排序调优
【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 🦞项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw
OpenClaw 的memory_search工具能够在记忆文件中找到与当前问题语义相关的笔记,即使查询措辞与原文完全不同。其核心是"混合检索":向量语义检索负责"意思相近",BM25 关键词检索负责"字面精确",两者并行、合并、再经确定性排序与多样性重排后返回结果。本文以 docs/concepts/memory-search.md 为主体,结合 memory-core 扩展 的源码实现与 Memory 配置参考,完整讲解供应商选择、检索原理、排序机制(recency / importance / MMR)、多模态索引、会话记忆检索与常见故障排查,帮助你在实际部署中把记忆召回质量调到最优。
Quick start:一分钟切换到目标 Embedding 供应商
OpenClaw 默认使用 OpenAI 的 Embedding。若OPENAI_API_KEY或models.providers.openai.apiKey已配置,向量检索开箱即用。需要切换供应商时,在openclaw.json中显式指定memory.search.provider:
{ memory: { search: { provider: "openai", // 或 "gemini"、"voyage"、"mistral"、"bedrock"、"local"、"ollama"、"lmstudio"、"github-copilot"、"openai-compatible" }, }, }几点关键说明:
provider支持自定义 provider id:可以引用models.providers.<id>中的条目(例如ollama-5080),只要该条目的api指向"ollama"或其它带有 memory embedding 适配器的 provider id。这允许在多 GPU / 多主机场景下把记忆向量化固定到某个本地端点,完整示例见 Memory 配置参考 - Custom provider ids。- 本地 Embedding(无需 API Key):安装并配置官方 llama.cpp provider 后,设置
provider: "local":
openclaw plugins install @openclaw/llama-cpp-provider在交互式安装中为 llama.cpp 选择一次即可。OpenClaw 会安装经校验的llama-server、自动下载 Embedding GGUF 模型(默认embeddinggemma-300m-qat-Q8_0.gguf,约 0.3 GB),并写入其托管服务配置。默认模型路径见 memory-builtin 文档 中的local.modelPath示例。
- 非对称 Embedding 端点:部分 OpenAI 兼容端点要求区分
input_type标签——查询用"query",索引块用"document"/"passage"。通过queryInputType与documentInputType配置,详见 Memory 配置参考 - Provider-specific config。
支持的 Embedding 供应商一览
下表汇总了 memory-search.md 中列出的全部供应商。默认模型列补充自 Memory 配置参考 与 memory-builtin.md:
| Provider | ID | 需要 API Key | 说明 |
|---|---|---|---|
| Bedrock | bedrock | 否 | 走 AWS 凭证链,无明文密钥 |
| DeepInfra | deepinfra | 是 | 默认模型BAAI/bge-m3 |
| Gemini | gemini | 是 | 支持图片 / 音频索引(多模态) |
| GitHub Copilot | github-copilot | 否 | 使用你的 Copilot 订阅 |
| Local | local | 否 | 托管 llama.cpp GGUF,约 0.3 GB |
| LM Studio | lmstudio | 否 | 本地 / 自托管服务器 |
| Mistral | mistral | 是 | 默认模型mistral-embed |
| Ollama | ollama | 否 | 本地 / 自托管服务器 |
| OpenAI | openai | 是 | 默认,模型text-embedding-3-small |
| OpenAI-compatible | openai-compatible | 通常需要 | 通用/v1/embeddings端点 |
| Voyage | voyage | 是 | 默认模型voyage-4-large |
各远程供应商的 API Key 解析方式(环境变量 / 配置键)在 Memory 配置参考 - API key resolution 有完整表格;Bedrock 走 AWS SDK 默认凭证链(实例角色、SSO、访问密钥或 Bedrock API key)。注意:Codex OAuth 仅覆盖聊天 / 补全,不满足 Embedding 请求。
检索如何工作:两条检索路径并行 + 确定性排序
OpenClaw 并行运行两条检索路径,再合并结果,流程如下:
- 向量检索(Vector search):匹配语义相近的内容,例如查询 "gateway host" 能命中 "the machine running OpenClaw"。
- BM25 关键词检索:匹配精确词条,例如 ID、错误字符串、配置键。
- 文件名检索:路径与正文分开索引。完整路径、basename、文件名词干排在部分路径匹配之前;而摘要与正文关键词分数仍来自笔记内容本身。
若只有一条路径可用(例如未配置 Embedding 供应商或 FTS 不可用),则另一条单独运行。从 manager-search-orchestration.ts 的源码看,当keywordOnly(无 provider 或显式lexicalOnly)时直接走关键词检索;当hybrid.enabled且 FTS 与 provider 均可用时才进入合并流程。
内置引擎随后应用确定性排序公式:
hybrid relevance × recency decay × importance multiplier合并与选择:源码视角
真正的合并逻辑在 hybrid.ts 的mergeHybridResults:向量与关键词结果按 chunk id 归并,分别累计vectorScore/textScore,再按vectorWeight与textWeight加权得到contentScore;随后依次执行时间衰减、importance 乘数、项目亲和度排序,再按exactPathSpecificity(0–3,路径精确度分级)分档,对非精确命中应用 MMR。最终由selectHybridSearchResults(hybrid.ts#L319-L359)按minScore阈值筛选并截取maxResults条:
- 所有得分低于配置阈值的加权结果被过滤,但关键词命中的候选可以回填剩余结果位(
keyword-only回退); - 当全部排名结果都低于最低分时,检索仍会保留关键词匹配;
- 这些规则同样适用于项目会话(project sessions),纯语义命中仍需达到配置的最低分。
Importance 乘数:写入时的一次性打分
Importance 在记忆条目写入时由"已有模型参与"的记忆工作流打分一次,属于可空字段。缺失的 importance 是中性值(乘数为 1),因此旧索引保持原有的相关性信号。实现位于 importance.ts:bounded = clamp(floor(importance), 1, 10),乘数0.75 + bounded * 0.05,即重要性 1 对应 0.8 倍、重要性 10 对应 1.25 倍。
该"相关性 × 时效性 × 重要性"的设计遵循 Generative Agents 研究(arXiv:2304.03442)的结论,但不引入查询时的模型调用,保持确定性、低延迟。
MMR:只做多样性重排,不改分、不设阈值
MMR(Maximal Marginal Relevance)对混合候选集重排,减少冗余摘要:如果五条笔记都提到同一份路由器配置,MMR 倾向于换入一条相关但内容不同的结果。实现见 mmr.ts,核心公式为:
MMR = λ × relevance − (1 − λ) × max_similarity_to_selected- 默认固定 λ =
0.7(偏向相关性),Jaccard 相似度基于摘要 token 重叠; - 本地计算复杂度为
O(k²):默认每条检索腿请求 200 个候选(常量SEARCH_CANDIDATE_UNIVERSE = 200,见 manager-search-orchestration.ts#L36),去重后最多 400 个非精确候选参与重叠计算;更宽的项目与标识符搜索另有独立上限; - MMR不改变分数、不改变阈值资格、不发起额外的 provider 调用;
- FTS-only 与 vector-only 回退路径不执行混合 MMR 通道,因此无需任何配置。
确定性触发召回(Deterministic trigger recall)
在符合条件的交互轮次中,内置引擎会把入站消息与已索引条目上存储的短触发短语(triggers)比对。强匹配可在回复前向隐藏上下文注入最多三条紧凑记忆。预过滤复用现有的关键词与向量检索路径,不运行召回模型。
自动注入比memory_search刻意更窄:只有被提升(promoted)、可信(trusted)的条目才合格。在索引 provenance(来源溯源)可用之前,这意味着只有根目录MEMORY.md与USER.md中的条目会参与自动注入。每日笔记、导入的转录与会话转录仍可通过显式记忆工具或 Active Memory 升级访问,但永远不会被自动注入。相关配置见 Memory 配置参考 - Hybrid search config。
FTS-only 模式与显式 provider 不可用时的行为
- FTS-only 模式:设置
provider: "none"可刻意禁用 Embedding,仅用关键词检索。provider未设置或为"auto"(legacy 配置,现在解析为openai)时,若 Embedding 初始化或请求失败,会回退到关键词排序;provider: "local"(GGUF / llama.cpp)同样如此。创建时的回退仍会为关键词检索索引文本——包括首次搜索前的手动与后台索引。memory_search即使无匹配结果,也会在debug.embeddingBootstrap中返回脱敏后的 Embedding 引导原因。 - 显式 provider 不可用:若你显式命名其它供应商(如
openai、ollama、gemini)且它在请求时不可用(认证失败、网络故障),memory_search会报告"记忆不可用",而不是静默降级为 FTS-only 结果——让坏掉的配置暴露出来。需要刻意 FTS-only 就设provider: "none",否则修复 provider / 认证配置以恢复语义排序。
提升搜索质量:Recency 衰减与 MMR
混合检索默认开启两趟确定性排序。
Recency 衰减(时间衰减)
旧笔记逐渐降低排名权重,让近期信息优先浮现。默认 30 天半衰期:一个月前的笔记得分衰减为原始的 50%。公式与判定逻辑在 temporal-decay.ts:
score × exp(−(ln2 / halfLifeDays) × ageInDays)- 常青(evergreen)文件不衰减:
MEMORY.md、USER.md,以及memory/下无日期的文件。 - 带日期的
YYYY-MM-DD.md与YYYY-MM-DD-<slug>.md在任何目录深度都衰减,包括会话记忆笔记与嵌套的 dreaming 报告。路径正则DATED_MEMORY_PATH_RE(temporal-decay.ts#L15)支持memory/dreaming/light/2025-01-01.md这类嵌套路径,也兼容 Windows 风格分隔符(见 temporal-decay.test.ts 的测试用例)。 - 时间戳来源:会话转录命中使用索引时捕获的源活动时间戳;保留的转录档案使用其被索引时的文件修改时间。单条消息时间戳仍是 provenance 元数据,不决定源的 recency 权重。
extraPaths下的普通文件则取文件 mtime(测试覆盖见 temporal-decay.test.ts#L206-L222)。
MMR(多样性重排)
如前述,MMR 在混合排序后对候选重排,减少近重复摘要。默认启用、λ=0.7,无需配置;FTS-only 与 vector-only 回退路径不运行混合 MMR。
多模态记忆:用 Gemini 索引图片与音频
使用gemini-embedding-2时,可以在 Markdown 之外一并索引图片与音频。注意以下几点约束:
- 仅作用于
memory.search.extraPaths下的文件;默认记忆根(MEMORY.md、memory/*.md)保持纯 Markdown; - 查询仍为文本,但会与视觉和音频内容匹配;
- 配置项:
multimodal.enabled(默认false)、multimodal.modalities(["image"]、["audio"]或["all"])、multimodal.maxFileBytes(默认 10485760,即 10 MiB),并要求fallback: "none"; - 支持格式:图片
.jpg、.jpeg、.png;音频.mp3、.wav; - 完整设置见 Memory 配置参考 - Multimodal memory。
会话记忆搜索(Session memory search)
需要从会话转录中做精确全文召回时,优先使用sessions_search定位,再用sessions_history打开结果。memory_search的会话检索是语义化、实验性的补充。
开启会话转录索引
这是 opt-in 功能:设置experimental.sessionMemory: true,并向sources添加"sessions"(默认sources为["memory"]):
{ memory: { search: { experimental: { sessionMemory: true }, sources: ["memory", "sessions"], }, }, }- 使用
corpus: "memory"可只搜记忆笔记;若结果不含会话转录,则不加载会话历史、不做会话可见性查询。 - 会话命中遵循
tools.sessions.visibility(默认"all")。memory_search仍只检索当前所选 agent 的已索引语料;跨 agent 的转录检索请用 Gateway 上的sessions_search。 - 跨 agent 会话访问默认开启,由
tools.agentToAgent管理:设enabled: false阻止普通跨 agent 访问(请求方自有的原生子 agent 与 ACP 子会话在tree或all下仍可达),或用allow限制 agent 对。 - 每个对端可设置
session.dmScope隔离 DM 上下文,但这不限制通过会话工具读取转录。选择显式"agent"(同 agent 召回)、"tree"(当前 + 衍生范围,main 有 agent 级例外)、或"self"(严格当前会话召回)。沙箱 spawn-only 钳制与 incognito 排除仍然生效。 - 会话索引是异步且 opt-in 的,结果可能略微滞后;配置细节与排除规则见 Memory 配置参考 - Session memory search。
相关配置项速查
| 配置键 | 类型 | 默认 | 说明 |
|---|---|---|---|
rememberAcrossConversations | boolean | 个人安装开启;配置 DM 隔离后关闭 | 允许私密跨会话召回 |
experimental.sessionMemory | boolean | false | 开启会话转录索引 |
sources | string[] | ["memory"] | 加入"sessions"以包含转录 |
注意:内部 dreaming 叙事、cron 与 heartbeat 会话转录不会被索引(包括其保留的压缩叙事归档);被openclaw memory forget清除的会话也会被持久排除,即使源转录仍留在会话存储中。
故障排查(Troubleshooting)
对应 memory-search.md 与 cli/memory.md 中的命令,逐项排查:
| 症状 | 排查动作 |
|---|---|
| 无结果 | openclaw memory status检查索引;为空则openclaw memory index --force |
| 只有关键词匹配 | 可能未配置 Embedding 供应商;用openclaw memory status --deep探测 |
| 本地 Embedding 超时 | ollama、lmstudio、local使用更长的 provider 自有批量截止时间;先openclaw memory status --deep检查托管服务器端点再重建索引 |
| CJK 文本搜不到 | 用openclaw memory index --force重建 FTS 索引 |
memory status相关参数:--deep探测向量存储、Embedding 供应商与语义搜索就绪状态(会发起额外 provider 调用);--index检查并可重建不兼容索引;--fix修复可自动修复的问题;--json输出结构化结果。更换 Embedding 供应商 / 模型 / 相关设置会改变索引身份(index identity),OpenClaw 会暂停向量搜索并提示,直到你用openclaw memory index --force --agent <id>显式重建。
索引重建注意事项
- 索引与其它 agent 状态(会话、转录)共享
~/.openclaw/agents/<agentId>/agent/openclaw-agent.sqlite,切勿删除该数据库或其-wal、-shm、-journal边车文件来重置记忆; - 需要清空派生索引与 Embedding 缓存时,使用
openclaw memory reset --agent <id>(加--yes跳过确认),随后openclaw memory index --agent <id>; - 若要回收磁盘空间,可对 agent 数据库执行
openclaw doctor --session-sqlite compact --session-sqlite-agent <id>,详见 memory-builtin.md 的 "Reclaim disk space" 章节。
进一步阅读
- Memory overview:记忆文件体系(
USER.md/MEMORY.md/memory/*.md)与记忆工具 - Memory architecture:存储、索引与检索层
- Builtin memory engine:默认 SQLite 后端,chunk 默认 400 token / 80 token 重叠,文件监听 1.5s 防抖重索引
- Active memory:交互会话的子 agent 记忆
- Memory configuration reference:全部配置旋钮(查询限额、
extraPaths、Embedding 缓存、批量索引、sqlite-vec、FTS tokenizer 等) - Memory LanceDB:基于 LanceDB 的记忆插件(若使用替代记忆引擎)
- CLI: openclaw memory:
memory status/index/reset/search命令参考
如需深入源码:混合合并与选择逻辑在 hybrid.ts,时间衰减在 temporal-decay.ts,MMR 在 mmr.ts,importance 乘数在 importance.ts,搜索编排在 manager-search-orchestration.ts,行为均有对应测试(如 temporal-decay.test.ts)可对照验证。
【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 🦞项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考