MemPalace 记忆检索实操指南:Agent 的语义搜索流程、MCP 工具链与 CLI 回退方案
【免费下载链接】mempalaceThe best-benchmarked open-source AI memory system. And it's free.项目地址: https://gitcode.com/GitHub_Trending/me/mempalace
当你向 MemPalace 提问“我们上次为什么把登录切到 Clerk?”这类问题时,真正发生的是一次结构化的记忆检索:查询意图被解析、作用域(Wing/Room)被收敛、向量语义检索与关键词检索被联合打分,最后结果按来源归组呈现。本篇指南基于 MemPalace 的 search 指令(面向 AI Agent 的操作规程)展开,并结合仓库内 MCP 服务端与搜索引擎源码,完整还原一次搜索从“用户一句话”到“带出处、带相似度的记忆清单”的完整链路,以及没有 MCP 时的 CLI 兜底打法。
读完本文,你将掌握:如何解析检索意图与过滤器、如何按优先级调用 6 个记忆检索相关 MCP 工具、如何理解mempalace search命令的全部参数、如何把结果以“可引用、可追溯”的形式呈现,以及这些能力背后的混合检索(Hybrid Search)实现原理。
一、先理解要检索的对象:Wing / Room / Drawer 三级结构
MemPalace 的记忆不是一坨文本,而是被组织成层级化“宫殿”结构。搜索指令中反复出现的过滤器(Wing、Room)都建立在如下三级分类上:
| 层级 | 名称 | 含义 | 检索中的作用 |
|---|---|---|---|
| 顶层分类 | Wing | 领域 / 项目 / 主题(如 "work"、"personal"、"research";在项目挖掘流程中对应项目名) | mempalace_search的wing参数、CLI 的--wing |
| 子分类 | Room | Wing 内的子类 / 主题(如 "auth-migration"、"costs") | mempalace_search的room参数、CLI 的--room |
| 记忆单元 | Drawer | 一条被原样保存(verbatim)的记忆,元数据携带 wing、room、source_file 等归属信息 | 检索返回的正是这些 Drawer 的原文 |
关于“Wing 到底代表什么”,仓库内有两种具体形态可以互相印证:面向项目的挖掘流程把它当作项目名(mcp-tools.md 中mempalace_add_drawer将 wing 描述为 “project name”);而日记写入工具mempalace_diary_write的文档写明“each agent gets its own wing”——即多 Agent 共享脑场景下每个 Agent 拥有独立 Wing。因此把它理解为“最顶层的归属分类”即可,不必纠结于单一命名。
检索到的最底层单元是 Drawer,其核心特征是原文返回(verbatim):搜索引擎 searcher.py 的模块文档串写着 “Search the palace. Returns verbatim drawer content.”,返回的是当初写入的确切文字,而不是摘要或改写,这正是记忆检索区别于普通问答的关键。
二、第一步:解析搜索查询(Parse the Search Query)
当用户提出一个需要回忆的问题时,不要把整句话原样丢给搜索,而是先做一次结构化解析,从消息中提取:
- 语义查询词(Keywords / semantic query)——真正要去匹配的记忆内容,通常是去掉寒暄后的核心短语,例如 “auth migration decision last month”。
- 显式或隐式的作用域过滤器:
- Wing——用户提到的领域 / 项目 / 上下文,如 “咱们的项目 X 里”、“在我的研究笔记里”;
- Room——用户提到的具体子主题,如 “关于数据库选型那部分”;
- 若用户没有给出任何维度线索,则这些过滤器缺省(见下文“全局检索”)。
三、第二步:判定并解析 Wing/Room 过滤器
解析出候选作用域之后,关键一步是把用户口语化的领域描述映射为仓库中真实存在的分类名:
- 如果用户明确提到具体域名 / 主题 / 上下文,尽量映射到合适的 Wing 或 Room;
- 如果不确定,宁可不加过滤器,进行全局检索——全局检索永远不会因为猜错了分类而漏掉本该命中的记忆;
- 需要时,可以先做一次“分类体系探查”(即用第 4 节中的
mempalace_list_wings/mempalace_list_rooms/mempalace_get_taxonomy),拿到真实存在的分类名后再发起搜索。
这一步的价值在仓库文档中有明确论述:searching.md 指出,当单个 palace 里存放着许多互不相关的项目或人时,Wing(或 Wing + Room)限定能让向量存储只在作用域内打分,从而随记忆规模增长保持检索结果的可预测性;同时它也被如实描述为“向量存储的元数据过滤能力,而非新的检索机制”,是任何人都能套用的清晰操作约定。
四、第三步:优先走 MCP 工具链
搜索指令规定:只要 MCP 工具可用,就按下面的优先级顺序使用它们。这套顺序的设计意图非常清晰:先直接检索(mempalace_search),检索前或检索后按需做结构探查(wings/rooms/taxonomy),需要深挖关联时再用图遍历(traverse、find_tunnels)。
| 优先级 | MCP 工具 | 用途 | 关键参数 |
|---|---|---|---|
| 1(首选) | mempalace_search | 语义搜索主工具:传入语义查询 + Wing/Room 过滤器 | query(必填)、wing、room、limit(默认 5) |
| 2 | mempalace_list_wings | 列出全部 Wing。当用户问“有哪些分类”或你需要解析 Wing 名称时使用 | 无 |
| 3 | mempalace_list_rooms(wing) | 列出某 Wing 内的 Rooms,用于帮助用户导航或解析 Room 名 | wing(可选,缺省列出全部) |
| 4 | mempalace_get_taxonomy | 取回完整 Wing → Room → Drawer 树,当用户想纵览整个记忆结构时使用 | 无 |
| 5 | mempalace_traverse(room) | 从某个 Room 出发在记忆图上漫游,当用户想探索关联记忆时使用 | start_room(必填)、max_hops(默认 2) |
| 6 | mempalace_find_tunnels(wing1, wing2) | 寻找两个 Wing 之间的跨域连接(tunnel),当用户关心不同知识域之间的关系时使用 | wing_a、wing_b(schema 中的参数名,均可选) |
说明:指令文档写作层面称
mempalace_traverse(room)、mempalace_find_tunnels(wing1, wing2);在 MCP 服务端实际暴露的 JSON Schema 中,前者参数为start_room/max_hops,后者为wing_a/wing_b,见 MCP Tools Reference。
4.1 工具在源码中的对应实现
这些工具并不是虚构的抽象,而是 MCP 服务端 mcp_server.py 中真实注册的调用面:
mempalace_search等读工具在服务端的工具清单(TOOLS)中被声明,其内部调用链会导向 searcher.py 的search_memories()——一个“返回 dict 而非打印”的程序化检索入口,专供 MCP 服务端与其它需要结构化数据的调用方使用;mempalace_traverse、mempalace_find_tunnels对应的底层逻辑在 palace_graph.py 中(traverse、find_tunnels等函数),它们工作在由实体与关系构成的记忆图谱上;- 服务端还内置了健壮性设计:例如在
chroma.sqlite3的启动完整性探针失败时,会先把状态类工具mempalace_status等放入允许名单,其余工具被拒绝并提示修复(见 mcp_server.py 中 SQLite integrity gate 的实现注释)。
4.2 搜索引擎的返回值契约
mempalace_search的返回结构是 Agent 呈现结果的数据基础:
{ "query": "auth decisions", "filters": { "wing": "myapp", "room": "auth" }, "results": [ { "text": "We decided to migrate auth to Clerk because...", "wing": "myapp", "room": "auth-migration", "source_file": "session_2026-01-15.md", "similarity": 0.892 } ] }注意三个细节:text是逐字原文;similarity是 [0,1] 区间上的相似度(由底层距离换算而来,见第 6 节);source_file在此处暴露的是文件名部分——服务端刻意把挖掘流程写入的绝对路径在返回前降为 basename,作为显示用途(详见 mcp-tools.md)。
五、第四步:CLI 兜底方案
搜索指令明确约定:如果 MCP 工具不可用,回退到命令行。基本形态为:
mempalace search "query" [--wing X] [--room Y]在 cli.py 的 search 子命令解析器中,实际可用参数比指令文档示例更完整:
| 参数 | 说明 | 默认值 |
|---|---|---|
query | 位置参数:要搜索的内容(自然语言语义查询) | 必填 |
--wing | 限定到某一个项目 / 领域 | 无(全局) |
--room | 限定到某一个 Room | 无(全局) |
--results | 返回结果条数 | 5 |
--since | 只检索归档时间 ≥ 该 ISO 日期/时间(含端点,如2026-04-01)的 Drawer;一旦设定日期边界,缺少filed_at的 Drawer 会被排除 | 无 |
--before | 只检索归档时间严格早于该 ISO 日期/时间的 Drawer(不含端点) | 无 |
--backend | 本次搜索使用的存储后端(默认走配置 / 环境变量 / 自动探测 / chroma) | 自动 |
一个组合示例(同时命中主题、来源文件路径与时间窗的实战查询):
# 全局检索 mempalace search "why did we switch to GraphQL" # 限定项目与主题 mempalace search "database decision" --wing myapp --room db # 限定项目 + 主题 + 最近归档区间,返回 10 条 mempalace search "deploy process" --wing driftwood --room infra --results 10 --since 2026-01-015.1 CLI 如何调用指令内容(命令插件形态)
仓库把“执行 search 指令”做成了可直接触发的命令:在 Cursor 等宿主里执行search命令时,commands/mempalace-search.md 会指引插件先运行mempalace instructions search打印出检索规程,再照章执行;该会话内也直接暴露了mempalace_searchMCP 工具。而mempalace instructions search之所以能工作,是因为 cli.py 把init/search/mine/help/status等指令名注册进了instructions子命令,它们对应 mempalace/instructions/ 目录下的同名 Markdown 文件——搜索规程正是 search.md。
六、第五步:如何向用户呈现搜索结果
指令文档对结果呈现提出了四条硬性要求,它们共同保证“可追溯、可深挖、不淹没重点”:
- 始终附带来源归属(source attribution):每条结果都要给出 Wing、Room(以及有值时给出 Drawer/source_file),让用户能判断这条记忆来自哪里;
- 给出相关度 / 相似度分数:如果检索返回了分数,就展示它(
similarity/cosine_sim/bm25); - 多条命中时按 Wing/Room 归组:不要平铺一长串,把同一领域的命中原样归并展示,便于用户按域浏览;
- 清晰引用或概括记忆内容:优先直接引用原文(MemPalace 的搜索契约就是返回 verbatim 原文);确实过长时给出忠实概括,而不是夹带模型推测。
6.1 CLI 的结果排版模板
搜索引擎 searcher.py 在 CLI 路径下使用如下排版,可作为呈现层参考——每条命中都带序号、归属路径、来源文件名、相似度与 BM25 分数、逐行缩进的原文:
============================================================ Results for: "auth decisions" Wing: myapp Room: auth ============================================================ [1] myapp / auth-migration Source: session_2026-01-15.md Match: cosine_sim=0.892 bm25=1.7 We decided to migrate auth to Clerk because... --------------------------------------------------------七、第六步:给出后续动作(Next Steps)
搜索往往不是终点。呈现结果后,指令建议向用户提供这些“深入一层”的选项,全部有对应的 MCP 工具支撑:
- Drill deeper(钻取)——在某个具体 Room 内继续搜,或收窄查询词(用
mempalace_search加wing/room重跑); - Traverse(图漫游)——从相关 Room 出发探索知识图谱上的关联记忆(
mempalace_traverse(start_room, max_hops),默认 2 跳); - Check tunnels(检查隧道)——如果话题跨领域,查找两个 Wing 之间的显式跨域连接(
mempalace_find_tunnels),例如一个项目的 API 设计与另一个项目的数据库 schema 在图上被显式“打通”; - Browse taxonomy(浏览分类树)——展示完整结构供用户手动浏览(
mempalace_get_taxonomy)。
这一层设计把“检索”升级为“检索—探索”闭环:纯文本命中之外,用户还能顺着图谱关系发现原本没想到的相邻记忆。
八、原理纵深:混合检索如何工作
搜索指令是操作层,而操作背后的检索质量由 searcher.py 的混合检索架构支撑。以下几点是“呈现相似度、解释命中原因”时必须理解的事实:
8.1 Drawer 检索是地板,Closet 只是排名信号
模块文档明确写下设计原则:drawer query(直接检索记忆)永远运行,作为兜底地板;closet(主题抽取文档)命中只是在它们“与 drawer 命中一致”时按排名加分。Closet 是排名信号(ranking signal),永远不是门禁(never a gate)——这避免了“弱 closet 回归”:叙述性内容抽取出的低信号 closet 可能掩盖直接检索本应命中的 Drawer。在search_memories的实现里,boost 表按source_file建立,命中的 drawer 若来自同一个有 closet 命中的源文件,会依据 closet 排名获得阶梯加分(源码中 rank-based boost 序列为[0.40, 0.25, 0.15, 0.08, 0.04],余弦距离超过 1.5 的弱 closet 不会被采信)。
8.2 向量相似度 + BM25 关键词的联合重排
即便在“纯向量”的默认路径下,最终排序也是混合的:_hybrid_rank用向量相似度(权重 0.6)与 Okapi-BM25 关键词得分(权重 0.4)的凸组合对候选集重排。BM25 的 IDF 是在当前候选集内计算并做 min-max 归一化,因此两路分数可比较;同分时按authored_at更新的排前。这是为什么 CLI 命中行会同时打印cosine_sim=与bm25=两列。
8.3 从距离到相似度的换算
后端返回的原始字段是“距离”(distance),语义为越小越近,与具体度量无关(这一契约来自 RFC 001 的后端度量声明,相关规范可见 docs/rfcs/001-storage-backend-plugin-spec.md)。展示给用户的similarity是换算后的 [0,1] 值:
cosine(默认):similarity = max(0, 1 - distance);l2(欧氏距离):1 / (1 + distance);ip(内积):logistic 压缩1 / (1 + e^distance)。
_distance_to_similarity与_metric_for_collection在 searcher.py 中实现,后者会读取后端集合声明的distance_metric,取不到时回退为cosine。
8.4 候选策略与降级路径
search_memories的candidate_strategy参数(默认"vector")决定混合重排的候选池来源:默认取向量索引前n_results × 4行;"union"模式会额外拉取前n_results × 3条词法候选并入池中(按 source_file 去重),从而捕获“与查询在向量空间很远、但 BM25 信号极强”的机械性文档(目录清单、diff、日志片段等)。此外,若 HNSW 向量段与 SQLite 元数据出现分歧(会导致原生崩溃),服务端会把vector_disabled=True传入,让检索自动降级为直接读 chroma.sqlite3 的 BM25-only 路径(经由 chromadb 自带的 FTS5 trigram 索引取候选,再套用同一套 BM25 重排),并在 CLI 输出中明确提示运行mempalace repair修复。换言之:索引坏了可以降级,但绝不能静默返回与健康索引不同规则的“空结果”。
九、给 Agent 的最终操作清单(速查)
综合指令文档与上述源码事实,一次规范的记忆检索可以收敛为以下动作序列:
- 解析:抽出语义查询词 + 候选 Wing/Room 过滤器;
- 确认作用域:能确定分类就用
--wing/--room(或wing/room参数)收窄;不确定就全局检索,绝不乱猜分类名; - 主检索:MCP 可用 →
mempalace_search(query, wing, room);MCP 不可用 →mempalace search "query" [--wing X] [--room Y]; - 结构探查(按需):
mempalace_list_wings/mempalace_list_rooms/mempalace_get_taxonomy; - 呈现:逐条标注 wing / room / source_file,附相似度,按域归组,优先引用原文;
- 延伸:根据用户意图提供钻取、图漫游(traverse)、跨域隧道(tunnels)或分类浏览。
上述每一步都可以在仓库中找到对应实现或规程文档——指令本体在 mempalace/instructions/search.md,命令触发方式见 commands/mempalace-search.md,MCP 工具的完整参数 schema 见 website/reference/mcp-tools.md,检索与搜索的引擎实现在 mempalace/searcher.py 与 mempalace/mcp_server.py,对应的回归测试则集中在 tests/test_searcher.py 等测试文件中。阅读源码时建议从search_memories()这个程序化入口入手,它串联了过滤器构建、混合重排、closet 加分与日期窗口过滤的全部逻辑。
【免费下载链接】mempalaceThe best-benchmarked open-source AI memory system. And it's free.项目地址: https://gitcode.com/GitHub_Trending/me/mempalace
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考