MemPalace 深度解析:记忆宫殿架构如何让 AI Agent 告别"金鱼记忆"
引言:当 AI 遇见"最强大脑"记忆法
如果你是一位 Claude Code 或 Cursor 的重度用户,你一定经历过这个令人抓狂的时刻:
你花了半小时和 AI 一起重构了一个关键模块,做了无数决策和取舍,关掉对话窗口去干别的,回来问 AI:"我们之前讨论的那个数据库方案是什么来着?"
AI 一脸茫然:"抱歉,我不清楚你在说什么。"
这不是 AI 不够聪明,是每次对话都是一张白纸。 上下文窗口有上限,session 关闭即销毁,大多数 Agent 框架压根没有记忆持久化的机制。
今天要介绍的这个开源项目,试图从根本上解决这个问题——不是靠更好的 Prompt,不是靠 RAG 摘要,而是用一种听起来非常古典的概念:记忆宫殿。
这个项目叫 MemPalace,54k+ GitHub Stars,LongMemEval 开源记忆系统 benchmark 第一名(96.6% R@5),纯本地运行,零 API 调用。
它到底是怎么做到的?这篇文章从架构、设计哲学、代码实现三个层面深度拆解。
一、为什么现有的 AI 记忆方案都是"伪需求"
在深入 MemPalace 之前,我们先搞清楚现有方案的局限性。理解了这些局限性,才能理解 MemPalace 为什么值得花时间研究。
1.1 Prompt 塞入:Token 烧钱游戏
最朴素的方案是把历史对话塞进 context。问题显而易见:
- 成本爆炸:100 次对话的原文可能有 10 万 token,每次请求都要带着这部分内容,成本直接乘以 N
- 上下文窗口瓶颈:即使是最长的 200k context,存不下一个中型项目半年的决策历史
- 信号稀释:历史对话里 95% 是垃圾信息,真正有用的决策点被淹没
这不是解决方案,这是用战术上的勤奋掩盖战略上的懒惰。
1.2 RAG 摘要:信息失真的源头
RAG(检索增强生成)是当前的主流方案。它的套路是:
对话历史 → LLM 摘要 → 存入向量库 → 检索 → 塞入 Prompt
问题在于摘要这一步:
AI 怎么做摘要也赶不上原文信息量。你写代码时那个注释里的微妙含义、你和 AI 讨论时那个犹豫的过程、那个被否决的方案背后的权衡——摘要会把这些全部丢掉。
而且,摘要本质上是"事后重构",它依赖 LLM 对上下文的理解能力。如果原始对话本身就存在歧义或信息不完整,摘要会把歧义固化成"确定的事实"。
这是比"没有记忆"更危险的——有错误记忆。
1.3 云端记忆服务:隐私换便利
Mem0、Zep、Mastra 等商业化方案提供了云端记忆存储。
好处是开箱即用、跨设备同步。坏处也是显而易见的:
- 隐私风险:你的项目代码、决策上下文、对话内容全部上传到第三方服务器
- 厂商锁定:一旦记忆数据在云端,你的迁移成本极高
- 额外费用:除了模型 API 费用,还要付记忆存储费用
对于商业项目来说,把内部决策上下文交出去,这事儿本身就很难说服 CTO。
MemPalace 选择了和上述三条路都不同的第四条路:本地原样存储 + 语义检索,不做摘要。
二、记忆宫殿:从古罗马到 AI Agent
MemPalace 的核心概念来自"记忆宫殿"(Method of Loci)——一种古罗马时期的记忆术。演说家西塞罗在《论演说者》中详细描述了这种方法:
在脑海中构建一座宫殿,宫殿里的每个房间(Loci)存放不同的记忆片段。当需要回忆时,只需在脑海中"走进"宫殿,按位置取出相应的记忆。
MemPalace 将这个古典概念数字化,并赋予了现代语义检索能力。
2.1 核心架构:Palace → Wing → Room → Drawer
MemPalace 的数据组织是分层的,不是平铺的向量库:
Palace (记忆宫殿)
├── Wing (翅膀,代表人物或项目)
│ ├── Room A (房间,代表主题)
│ │ ├── Drawer 1 (抽屉,原始内容片段)
│ │ └── Drawer 2
│ └── Room B
│ └── Drawer 3
└── Wing B (另一个项目)
└── ...
为什么需要分层?
假设你在做一个电商后端项目,有"数据库选型"、"支付集成"、"缓存策略"三个主题。如果全部平铺在一个向量库里,搜索"为什么选 PostgreSQL"时,可能会返回和数据库完全不相关的内容(比如某次讨论"PostgreSQL 翻译插件"的内容)。
用 Palace 结构,你可以限定只搜"数据库选型"这个 Room,结果精准度大幅提升。
2.2 存储理念:原样存储,不做摘要
这是 MemPalace 和其他记忆系统的最核心差异:
| 系统 | 存储方式 | 信息保真度 | Token 消耗 |
|---|---|---|---|
| Mem0/Zep | LLM 摘要后存储 | 低(依赖摘要质量) | 中等 |
| RAG | 切片 + 摘要 | 中等 | 较高 |
| MemPalace | 原样文本 | 100% | 检索时按需 |
MemPalace 的哲学是:原文即记忆。你说过的话、做过的决策、写过的代码注释,原封不动存进去。检索时拿出来的就是原始片段,不经过任何"翻译"。
这带来一个额外好处:零幻觉风险。RAG 和摘要系统都可能产生"幻觉记忆"——LLM 在摘要时可能添加原文没有的内容。MemPalace 没有这个问题。
2.3 检索性能:96.6% R@5 是怎么来的
MemPalace 在 LongMemEval 基准测试上取得了 96.6% R@5 的成绩。这个数字意味着什么?
R@5(Recall@5):在 500 个测试问题中,当正确答案在前 5 个检索结果里时,就算召回成功。
96.6% 的意思是:随便问一个在记忆里有答案的问题,有 96.6% 的概率正确答案出现在前 5 条结果里。
这个成绩是怎么做到的?关键在于三点:
- 语义向量检索:基于 embedding 模型(如 BGE、Sentence-BERT)做语义匹配
- 时间近邻加权:最近的内容权重更高(开发者更可能参考近期决策)
- 偏好模式学习:从历史检索中学习用户的查询偏好
三、技术实现:pluggable backend 的工程艺术
MemPalace 的代码架构有一个非常值得学习的工程决策:用多实现验证抽象。
3.1 Backend 抽象层
MemPalace 定义了一个完整的存储契约(定义在 mempalace/backends/base.py):
from abc import ABC, abstractmethod
from typing import List, Dict, Any, Optional
class BaseBackend(ABC):
"""记忆存储后端抽象接口"""
@abstractmethod
def add(self, content: str, metadata: Dict[str, Any]) -> str:
"""添加记忆,返回记忆 ID"""
pass
@abstractmethod
def search(self, query: str, top_k: int = 5) -> List[Dict[str, Any]]:
"""语义检索,返回 top_k 条记忆"""
pass
@abstractmethod
def delete(self, memory_id: str) -> None:
"""删除记忆"""
pass
@abstractmethod
def list_wings(self) -> List[str]:
"""列出所有 Wing(项目/人物)"""
pass
@property
def supports_namespace_isolation(self) -> bool:
"""是否支持命名空间隔离(多租户)"""
return False
这个抽象层定义了后端需要实现的全部能力:增删查改 + 命名空间隔离 + 能力声明。
3.2 四种 Backend 实现
大多数开源项目的"可插拔"只是画个接口,实际实现就一两个。MemPalace 不一样——它有四个完整实现:
3.2.1 ChromaDB(默认)
# mempalace/backends/chroma.py(简化版)
import chromadb
from chromadb.config import Settings
class ChromaBackend(BaseBackend):
def __init__(self, persist_dir: str = "./palace_data"):
self.client = chromadb.Client(Settings(
anonymized_telemetry=False,
persist_directory=persist_dir
))
self.collection = self.client.get_or_create_collection(
name="mempalace",
metadata={"hnsw:space": "cosine"}
)
def add(self, content: str, metadata: Dict[str, Any]) -> str:
# 生成 embedding
embedding = self._embed(content)
# 存储
self.collection.add(
embeddings=[embedding],
documents=[content],
metadatas=[metadata],
ids=[self._generate_id()]
)
return memory_id
def search(self, query: str, top_k: int = 5) -> List[Dict[str, Any]]:
query_embedding = self._embed(query)
results = self.collection.query(
query_embeddings=[query_embedding],
n_results=top_k
)
return self._format_results(results)
ChromaDB 是默认选择,特点是无需额外服务、本地持久化、性能足够。
3.2.2 SQLite Exact(精确向量匹配)
# 用于精确验证其他 backend 的正确性
class SQLiteExactBackend(BaseBackend):
"""用 SQLite 存原始向量,精确计算余弦相似度"""
def __init__(self, db_path: str = "./palace.db"):
self.conn = sqlite3.connect(db_path)
self._init_table()
def _cosine_similarity(self, vec1: List[float], vec2: List[float]) -> float:
dot = sum(a * b for a, b in zip(vec1, vec2))
norm1 = math.sqrt(sum(a * a for a in vec1))
norm2 = math.sqrt(sum(a * a for a in vec2))
return dot / (norm1 * norm2) if norm1 and norm2 else 0.0
这个 backend 是 MemPalace 的"正确性基准"——当你不确定 ChromaDB 或 Qdrant 的结果是否准确时,可以用 SQLite Exact 验证。
3.2.3 Qdrant(分布式向量搜索)
# mempalace/backends/qdrant.py(简化版)
from qdrant_client import QdrantClient
from qdrant_client.http import models
class QdrantBackend(BaseBackend):
def __init__(self, url: str = "http://localhost:6333"):
self.client = QdrantClient(url=url)
@property
def supports_namespace_isolation(self) -> bool:
return True # Qdrant 原生支持 collection 隔离
def search(self, query: str, top_k: int = 5) -> List[Dict[str, Any]]:
query_embedding = self._embed(query)
results = self.client.search(
collection_name=self.namespace,
query_vector=query_embedding,
limit=top_k
)
return [self._format_hit(h) for h in results]
Qdrant 适合需要水平扩展的场景——当记忆数据量超过单机承载能力时。
3.2.4 pgvector(Postgres 向量扩展)
-- mempalace 使用的 schema
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE memories (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
content TEXT NOT NULL,
embedding VECTOR(1536),
wing TEXT,
room TEXT,
drawer TEXT,
metadata JSONB,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX ON memories USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);
# mempalace/backends/pgvector.py(简化版)
import asyncpg
class PgVectorBackend(BaseBackend):
def __init__(self, dsn: str):
self.pool = None # 异步连接池
async def search(self, query: str, top_k: int = 5) -> List[Dict[str, Any]]:
if not self.pool:
self.pool = await asyncpg.create_pool(self.dsn)
embedding = self._embed(query)
async with self.pool.acquire() as conn:
rows = await conn.fetch("""
SELECT id, content, metadata,
1 - (embedding <=> $1) as similarity
FROM memories
WHERE wing = $2 -- 命名空间隔离
ORDER BY embedding <=> $1
LIMIT $3
""", embedding, self.namespace, top_k)
return [dict(row) for row in rows]
pgvector 的优势是复用现有 Postgres 基础设施,很多团队已经有 Postgres 集群,不需要额外部署向量数据库。
3.3 为什么多 backend 很重要
这个设计有一个深层的工程哲学:用实现验证抽象。
当你只写一个实现时,你可能会"偷懒"——接口定义了一些方法但实现里没有真正用上,然后代码悄悄出错。MemPalace 的四个 backend 各自用不同的技术栈(内存、SQL、REST、SQL/JSONB)实现了同一个接口,如果接口定义有任何遗漏或不一致,某个 backend 就会暴露问题。
四、MCP 集成:Claude Code 的记忆外挂
MemPalace 最有意思的功能是MCP(Model Context Protocol)集成——让 Claude Code、Cursor 等 AI Agent 直接使用 MemPalace 作为记忆层。
4.1 MCP 是什么
MCP 是 Anthropic 推出的标准协议,允许 AI 模型调用外部工具。简单理解:
Claude Code ← MCP → MemPalace
Claude Code 通过 MCP 协议和 MemPalace 通信,不需要定制化的集成代码。
4.2 29 个 MCP 工具
MemPalace 提供 29 个 MCP 工具,覆盖了记忆操作的方方面面:
{
"mcpServers": {
"mempalace": {
"command": "docker",
"args": ["run", "-i", "--rm", "-v", "mempalace-data:/data", "mempalace"]
}
}
}
主要工具分类:
写入类:
mempalace_add_to_drawer:添加内容到指定抽屉mempalace_create_room:创建新房间mempalace_add_entity:添加实体到知识图谱
读取类:
mempalace_search:语义搜索mempalace_get_room_contents:获取房间所有内容mempalace_list_agents:列出所有已注册的 Agent
管理类:
mempalace_delete_drawer:删除抽屉mempalace_archive_wing:归档整个 Wing
4.3 Claude Code Hooks
MemPalace 提供了 Claude Code 的自动保存钩子:
# .claude/commands/hook-auto-save.py
import subprocess
import sys
def on_post_tool_use(tool_name: str, tool_input: dict, tool_result: dict):
"""
Claude Code 每次工具调用后自动触发
将关键决策保存到 MemPalace
"""
if tool_name in ["Write", "Edit", "Bash"]:
content = f"[Claude Code] Used {tool_name}: {tool_input.get(file_path, N/A)}"
subprocess.run([
"docker", "run", "--rm",
"-v", "mempalace-data:/data",
"mempalace",
"add",
"--content", content,
"--wing", current_project(),
"--room", "claude-decisions"
])
这个钩子的逻辑是:每次 Claude Code 修改文件或执行命令后,自动把操作记录到 MemPalace。这样,即使 session 关闭,下次打开时 Claude Code 依然可以通过 mempalace search 找回"我上次在改什么文件"。
五、知识图谱:超越向量检索的关联记忆
除了语义向量检索,MemPalace 还包含一个时序实体关系图谱,用 SQLite 存储。
5.1 图谱结构
-- 实体表
CREATE TABLE entities (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
type TEXT, -- person, project, concept, etc.
wing TEXT, -- 属于哪个 Wing
valid_from TIMESTAMP,
valid_to TIMESTAMP, -- NULL 表示当前有效
metadata JSONB
);
-- 关系表
CREATE TABLE relations (
id INTEGER PRIMARY KEY,
from_entity INTEGER REFERENCES entities(id),
to_entity INTEGER REFERENCES entities(id),
relation_type TEXT, -- "works_on", "depends_on", "decided_to_use"
valid_from TIMESTAMP,
valid_to TIMESTAMP,
context TEXT -- 原始讨论上下文
);
5.2 使用示例
# 添加实体:团队成员
mempalace entity add "张三" --type person --wing "电商项目"
# 添加关系:某人负责某个模块
mempalace relation add "张三" "works_on" "支付模块"
# 添加关系:某个技术决策
mempalace relation add "PostgreSQL" "decided_to_use" "支付模块" \
--context "因为需要事务支持和 JSONB 字段"
# 查询:张三负责的所有模块
mempalace entity timeline "张三"
这个图谱的价值在于追踪决策链:当你问"为什么选了 PostgreSQL"时,MemPalace 可以告诉你:
因为它被"decided_to_use"支付模块,决策上下文是"因为需要事务支持和 JSONB 字段",做出决策的时间是 2026-06-01。
六、性能优化:实测与调参
6.1 Benchmark 详解
MemPalace 的 benchmark 数据来自 LongMemEval(500 个测试问题):
| 配置 | R@5 | LLM 调用 |
|---|---|---|
| Raw(纯语义检索,无启发式) | 96.6% | 无 |
| Hybrid v4(加关键词+时间加权) | 98.4% | 无 |
| Hybrid v4 + LLM rerank | ≥99% | 任意模型 |
"98.4% 是留出 50 个问题调参、450 个问题测试的 honest generalization figure",这个说法很诚实——不是所有数据一起测然后报告最高分。
6.2 实测:首次 mine 很慢
实测中发现一个问题:大项目首次 mine 耗时长。
原因:每个文件都需要生成 embedding。embedding 模型(如 BGE)本身不慢,但文件数量多时,总时间可观。
优化方案:
# 只索引特定文件类型
mempalace mine ~/project --extensions .py,.js,.ts,.go
# 跳过测试文件(通常不需要记住)
mempalace mine ~/project --exclude "**/*test*.py"
# 并行化(实验性)
mempalace mine ~/project --parallel 8
6.3 中文 embedding 优化
默认 embedding 模型对中文支持有限。如果你的项目有大量中文注释和文档,建议使用中文 embedding 模型:
# 安装中文模型
pip install -U sentence-transformers
export MEMPALACE_EMBEDDING_MODEL="shibing624/text2vec-base-chinese"
# 或者用 MCP 配置
{
"mcpServers": {
"mempalace": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-v", "mempalace-data:/data",
"-e", "MEMPALACE_EMBEDDING_MODEL=shibing624/text2vec-base-chinese",
"mempalace"
]
}
}
}
七、适用场景与局限性
7.1 适合的场景
立刻应该试试的人:
- 重度 Claude Code / Cursor 用户,被 AI 失忆折磨
- 对数据隐私敏感的开发团队(代码不上云)
- 需要在 Agent 中实现长期记忆的 MCP 开发者
- 研究 AI 记忆机制的学术/工程研究者
可以再等等的:
- 需要中文语义优化的用户(需要自行配置 embedding 模型)
- 需要多设备同步的团队(MemPalace 目前是纯单机)
- 习惯开箱即用的用户(需要一定的命令行基础)
7.2 当前局限性
- 中文 embedding 偏弱:默认模型对中文语义理解不如英文
- 首次 mine 慢:大项目需要等待较长时间
- 无多设备同步:数据只存在本地,切换设备需要手动迁移
- 学习曲线:需要理解 Palace → Wing → Room → Drawer 的概念模型
八、总结:记忆系统的新范式
MemPalace 解决的是一个真实且普遍的问题:AI Agent 的"金鱼记忆"。
它的核心贡献不是某个炫酷的算法,而是一个设计哲学:原样存储比摘要更可靠,分层组织比平铺更精准,本地优先比云端更安全。
用记忆宫殿的概念组织 AI 记忆,既是工程上的创新,也是对古典记忆术的数字化致敬。
如果你是 Claude Code 或 Cursor 的重度用户,花 10 分钟装一个 MemPalace,你大概率会后悔——后悔没有早点装。
参考资料
- MemPalace GitHub: https://github.com/MemPalace/mempalace
- MemPalace 官方文档: https://mempalaceofficial.com
- LongMemEval Benchmark: https://github.com/MemPalace/mempalace/blob/main/benchmarks/BENCHMARKS.md
- MCP 协议文档: https://modelcontextprotocol.io