MemPalace 深度实战:当《生化危机》女主给 Claude Code 装上「记忆宫殿」——本地优先 AI 记忆系统的 96.6% 召回率之谜(2026完全指南)
作者注:2026年4月,一个让整个 AI 开发者社区惊讶的消息传来——《生化危机》中饰演 Alice 的好莱坞女演员 Milla Jovovich 联合开发了开源 AI 记忆系统 MemPalace,并在 LongMemEval 基准测试中跑出了 96.6% R@5 的超高分数。更令人震惊的是:这个成绩是在零 API 调用、纯本地运行的情况下取得的。本文深度解析 MemPalace 的架构设计、技术原理、代码实战,以及它如何彻底改变了 AI Agent 记忆系统的设计范式。
目录
- AI 记忆危机:为什么你的 Agent 总是「转头就忘」?
- MemPalace 起源:当好莱坞女演员遇见 Claude Code
- 设计哲学的三大支柱:Store Everything, Then Make It Findable
- 架构深剖:记忆宫殿隐喻与七层数据模型
- 四层记忆栈 L0-L3:从 170 tokens 到 19.5M tokens 的智能加载
- ChromaDB 原生存储与 AAAK 无损压缩技术
- 矛盾检测与时间有效性知识图谱
- MCP 集成实战:给 Claude Code 装上长期记忆
- 性能基准深度对比:96.6% 是怎么炼成的
- 生产级部署:从零到运行的完整 SOP
- 与其他记忆系统对比:MemPalace vs mem0 vs OpenClaw
- 源码解析:关键模块与扩展点
- 未来展望:AI 记忆系统的下一步在哪里
- 总结:为什么 MemPalace 代表了 AI 记忆的新范式
1. AI 记忆危机:为什么你的 Agent 总是「转头就忘」?
1.1 痛点:无状态 LLM 的本质缺陷
大模型本身是无状态的。每一次 API 调用都是一次全新的会话,除非你手动把历史消息全部塞回上下文窗口。这个方法有两个致命问题:
问题一:上下文窗口有限
以 Claude 3.5 Sonnet 为例,上下文窗口是 200K tokens。听起来很大?但如果你做一个长期项目:
第1天:讨论了项目架构(5K tokens)
第2天:实现了用户模块(8K tokens)
第3天:调试了并发问题(12K tokens)
第4天:优化了数据库查询(6K tokens)
...
第N天:你已经积累了多少上下文?
200K 窗口听起来大,但项目进行两周后,早期的决策背景就不得不被截断。AI 不知道你为什么做了某个技术选型,只能看到代码结果。
问题二:Token 成本爆炸
即使窗口够大,每次都把 200K tokens 传给 API 也是烧钱行为。以 Claude 3.5 Sonnet 定价:
- 输入:$3 / 1M tokens
- 输出:$15 / 1M tokens
一次对话 200K tokens 输入 = $0.60。一天对话 20 次 = $12。一个月 = $360。
这只是单个开发者。如果你的团队有 10 个人都在用,每月成本就是 $3600。
1.2 现有方案的困境
目前主流的 AI 记忆系统有几种思路,但各有局限:
方案A:摘要式记忆(Summarization-based)
代表项目:LangChain Memory、早期 mem0
原理:AI 自己决定什么重要,把对话压缩成摘要存储。
致命缺陷:
- AI 的「重要性判断」不可靠。今天你觉得不重要的细节,明天可能就是关键线索
- 摘要过程本身就有信息损失。你无法从摘要还原出原始决策的完整上下文
- 压缩率不可控。复杂技术讨论的摘要可能丢失关键代码细节
方案B:向量检索式记忆(Vector Retrieval)
代表项目:mem0、Zep
原理:把对话切成片段,转成向量存入向量数据库,需要时语义检索最相关的片段。
致命缺陷:
- 检索精度依赖嵌入模型质量。跨语言、跨领域场景容易漏检
- 原始对话被切分后,上下文连贯性丢失
- 大多数方案仍然在做「筛选-存储」,只是筛选方式从 AI 判断变成了向量相似度
方案C:全量上下文注入(Full Context Injection)
代表项目:OpenClaw Memory
原理:把一切存下来,需要时全部加载。
致命缺陷:
- 不筛选但也不结构化,加载时要么全加载(撑爆上下文),要么靠 AI 判断加载什么(又回到方案A的问题)
- 没有层次化的记忆组织,检索靠关键词/向量,效率低下
1.3 MemPalace 的颠覆性思路
MemPalace 提出了一个反直觉的主张:
不要筛选,全部存。然后靠结构化的「记忆宫殿」让它能分层次被检索到。
这句话的背后是三个核心决策:
- 原始逐字存储(Raw Verbatim Storage):不摘要、不提取、不压缩语义,把完整对话原文存入 ChromaDB
- 记忆宫殿结构(Memory Palace Structure):用 Wing/Hall/Room/Closet/Drawer 的层级结构组织记忆,模拟人类的空间记忆模式
- 四层记忆栈(L0-L3):根据任务需求,智能加载不同详细程度的记忆——从 170 tokens 的索引到 19.5M tokens 的完整原始数据
这个结果在 LongMemEval 基准测试中取得了 96.6% R@5 的成绩——目前本地运行、零 API 调用的系统中最高分。
2. MemPalace 起源:当好莱坞女演员遇见 Claude Code
2.1 Milla Jovovich 是谁?
如果你玩过《生化危机》游戏或看过电影,Alice 这个角色就是 Milla Jovovich 饰演的。她还在《第五元素》、《惊爆点》等电影中有经典演出。
但很少有人知道,Milla 对技术有浓厚兴趣。她不是在「挂名」——根据 GitHub 提交记录和访谈,她亲自参与了 MemPalace 的产品设计、用户体验决策和部分代码审查。
2.2 用 Claude Code 构建 MemPalace
MemPalace 的开发过程本身就是 AI 辅助编程的典型案例。根据项目文档和访谈:
- Ben Sigman(技术联合创始人)负责核心架构和代码
- Milla Jovovich 负责产品方向、设计决策
- Claude Code 是主要开发工具——大量代码是 Ben 和 Milla 用 Claude Code Pair Programming 的方式完成的
项目 README 中有一句话:
"Built with Anthropic's Claude Code. Milla wrote some of the prompts that wrote some of the code."
这种「人类设计 + AI 实现」的合作模式,本身就是 2026 年 AI 辅助开发的新范式。
2.3 为什么叫「MemPalace」?
名字来源于古希腊的「记忆宫殿法」(Method of Loci)——一种通过将信息与空间位置关联的记忆技巧。
古罗马演说家西塞罗就能在不用笔记的情况下,靠回忆宴会厅中每把椅子的位置来背诵整篇演讲。
MemPalace 把这种空间记忆原理搬到了 AI 世界:
- 「宫殿」= 整个记忆系统
- 「翼」(Wing) = 按人物/项目划分的区域
- 「厅」(Hall) = 按记忆类型划分的子区域
- 「房间」(Room) = 具体的话题/想法
- 「壁橱」(Closet) 和「抽屉」(Drawer) = 摘要指针和原始文件
- 「隧道」(Tunnel) = 跨项目的主题连接
这不是花哨的隐喻——而是整个数据模型的核心组织结构。
3. 设计哲学的三大支柱
3.1 支柱一:记忆宫殿隐喻(Method of Loci)
传统向量数据库检索像在一个巨大的仓库里翻箱子——你知道要找什么,但不知道它在哪。
MemPalace 的做法是:给每个记忆一个「空间位置」。
Palace
├── Wing: 项目A
│ ├── Hall: 技术决策
│ │ ├── Room: 为什么选 PostgreSQL 而不是 MySQL
│ │ │ ├── Closet: 摘要(200 tokens)
│ │ │ └── Drawer: 完整对话原文(15K tokens)
│ │ └── Room: 微服务拆分边界
│ └── Hall: 代码片段
├── Wing: 项目B
└── Wing: 个人偏好
└── Hall: 编程习惯
└── Room: 为什么喜欢 Rust 的 Result 类型
当你问「我们为什么选 PostgreSQL?」,MemPalace 不是去向量数据库里搜相似度最高的片段,而是:
- 确定你在问「项目A」→ 进入 Wing:项目A
- 识别这是「技术决策」→ 进入 Hall:技术决策
- 匹配到具体话题 → 进入 Room:为什么选 PostgreSQL
- 根据当前上下文窗口预算,决定加载 Closet(摘要)还是 Drawer(原文)
这种层级检索比纯向量相似度检索更精确,因为它结合了语义相似度和结构化导航。
3.2 支柱二:本地优先、零 API Key
MemPalace 的所有计算都在本地运行:
- 向量数据库:ChromaDB(本地嵌入式运行)
- 嵌入模型:默认用
all-MiniLM-L6-v2(本地运行,~80MB) - 记忆管理:纯 Python 实现,无外部服务依赖
好处:
- 隐私:你的对话、代码、技术决策永远不会离开你的机器
- 成本:零 API 调用 = 零 Token 费用
- 延迟:本地检索延迟 <50ms,不受网络影响
- 离线:飞机上也能用
代价:
- 嵌入质量受限于本地模型(但对大多数技术记忆任务,
all-MiniLM-L6-v2已经够用) - 需要本地磁盘存储(但原始对话文本的存储开销远小于你想象的——见第6章 AAAK 压缩)
3.3 支柱三:原始存储(Raw Verbatim Storage)
这是 MemPalace 最反直觉、也最有效的设计决策。
传统做法(以 mem0 为例):
# 存储时
conversation = [
{"role": "user", "content": "我们项目的数据库选型讨论..."},
{"role": "assistant", "content": "建议用 PostgreSQL,因为..."}
]
summary = llm.summarize(conversation) # AI 提取「重要信息」
vector_db.store(summary)
# 检索时
query = "为什么选 PostgreSQL?"
results = vector_db.search(query) # 返回摘要
问题:如果 AI 摘要时认为「选型讨论过程」不重要,只保留了「最终结论:选 PostgreSQL」,那你就丢失了选型的推理过程。三周后当你问「我们能不能换成 MySQL?」,AI 不知道当初为什么排除了 MySQL。
MemPalace 做法:
# 存储时
conversation = [
{"role": "user", "content": "我们项目的数据库选型讨论..."},
{"role": "assistant", "content": "建议用 PostgreSQL,因为..."}
]
# 完整存储,一个字不删
chroma_db.store(
document=conversation, # 原始完整对话
metadata={
"wing": "项目A",
"hall": "技术决策",
"room": "数据库选型",
"timestamp": "2026-06-01T10:30:00Z",
# ... 其他结构化字段
}
)
# 检索时
query = "为什么选 PostgreSQL?"
# 第一步:层级导航到 Wing->Hall->Room
# 第二步:在 Room 内语义检索最相关的原始对话片段
# 第三步:根据上下文预算,决定返回 Closet(摘要)还是 Drawer(原文)
为什么原始存储反而效果更好?
因为 LLM 的「重要性判断」是不可靠的。你不知道未来哪个细节会变关键。
MemPalace 的策略是:存什么都别丢,让未来的检索去决定什么重要。
这也是它在 LongMemEval 上取得 96.6% R@5 的核心原因——检索时你有完整的原始对话可以参考,而不是 AI 的二手摘要。
4. 架构深剖:记忆宫殿隐喻与七层数据模型
4.1 数据模型全景
MemPalace 的数据模型由七层结构组成,从粗到细依次是:
┌─────────────────────────────────────────────────────────────┐
│ Palace(宫殿) │
│ 整个记忆系统的顶层容器,对应一个用户 │
└──────────────────────┬──────────────────────────────────────┘
│
┌──────────────┼──────────────┐
│ │ │
┌───────▼──────┐┌─────▼──────┐┌─────▼──────┐
│ Wing(翼) ││ Wing(翼) ││ Wing(翼) │
│ 按人物/项目 ││ 按人物/项目 ││ 按人物/项目 │
└───────┬──────┘└─────┬──────┘└─────┬──────┘
│ │ │
┌────▼────┐ ┌───▼────┐ ┌───▼────┐
│ Hall │ │ Hall │ │ Hall │
│(厅) │ │(厅) │ │(厅) │
│按记忆 │ │按记忆 │ │按记忆 │
│类型划分 │ │类型划分 │ │类型划分 │
└────┬────┘ └───┬────┘ └───┬────┘
│ │ │
┌────▼────┐ ┌───▼────┐ ┌───▼────┐
│ Room │ │ Room │ │ Room │
│(房间) │ │(房间) │ │(房间) │
│具体话题 │ │具体话题 │ │具体话题 │
└────┬────┘ └───┬────┘ └───┬────┘
│ │ │
┌────▼────┐ ┌───▼────┐ ┌───▼────┐
│ Closet │ │ Closet │ │ Closet │
│(壁橱) │ │(壁橱) │ │(壁橱) │
│摘要指针 │ │摘要指针 │ │摘要指针 │
└────┬────┘ └───┬────┘ └───┬────┘
│ │ │
┌────▼────┐ ┌───▼────┐ ┌───▼────┐
│ Drawer │ │ Drawer │ │ Drawer │
│(抽屉) │ │(抽屉) │ │(抽屉) │
│原始文件 │ │原始文件 │ │原始文件 │
└─────────┘ └─────────┘ └─────────┘
此外还有两个跨层级结构:
- Tunnel(隧道):连接不同 Wing 中相同话题的 Room,实现跨项目记忆关联
- Index(索引):全局倒排索引,支持关键词+语义混合检索
4.2 Wing(翼):第一层容器
定义:Wing 是记忆的最高层组织单位,通常按「人物」或「项目」划分。
示例:
# 自动创建的 Wing
wing_personal = Wing(name="Personal", type="person")
wing_project_A = Wing(name="Project-A", type="project")
wing_project_B = Wing(name="Project-B", type="project")
设计考量:
Wing 的划分决定了记忆的隔离粒度。如果你在做多个项目,每个项目应该有独立的 Wing——这样当 AI 在项目A的上下文中时,不会误加载项目B的无关记忆。
4.3 Hall(厅):按「记忆类型」横切
定义:在每个 Wing 内部,Hall 按记忆的类型做二次划分。
预定义的 Hall 类型:
HALL_TYPES = [
"technical_decisions", # 技术决策
"code_snippets", # 代码片段
"debugging_logs", # 调试记录
"architecture_design", # 架构设计
"personal_preferences", # 个人偏好
"meeting_notes", # 会议记录
"research_notes", # 调研笔记
# ... 可扩展
]
为什么需要 Hall?
因为不同类型的记忆,检索模式不同:
- 「技术决策」类记忆:检索时需要完整的推理过程
- 「代码片段」类记忆:检索时只需要代码本身,不需要完整对话
- 「个人偏好」类记忆:检索时优先级高,应该常驻 L0 层
Hall 的划分让 MemPalace 可以对不同类型的记忆应用不同的检索策略和加载优先级。
4.4 Room(房间):具体话题
定义:Room 是记忆的基本单元,对应一个具体的话题或想法。
示例:
room = Room(
name="为什么选 PostgreSQL 而不是 MySQL",
created_at="2026-06-01T10:30:00Z",
last_accessed="2026-06-25T15:20:00Z",
access_count=7,
tags=["database", "postgresql", "tech-stack"],
participants=["user", "claude"],
summary="讨论了 PostgreSQL 和 MySQL 的对比,最终决定用 PostgreSQL 因为其 JSONB 支持和并发性能",
# ... 其他元数据
)
Room 的自动创建逻辑:
MemPalace 不是让你手动创建 Room——它通过 AI 分析对话自动决定是创建新 Room 还是归入现有 Room。
核心算法伪代码:
def get_or_create_room(wing, hall, conversation_turn):
# 1. 提取当前对话的主题关键词
topics = extract_topics(conversation_turn)
# 2. 在 Hall 内搜索最相似的现有 Room
similar_rooms = []
for room in hall.rooms:
similarity = compute_similarity(topics, room.tags)
if similarity > THRESHOLD:
similar_rooms.append((room, similarity))
# 3. 如果找到足够相似的 Room,归入该 Room
if similar_rooms:
best_room = max(similar_rooms, key=lambda x: x[1])
return best_room[0]
# 4. 否则创建新 Room
new_room = Room(
name=generate_room_name(conversation_turn),
tags=topics,
# ...
)
hall.add_room(new_room)
return new_room
4.5 Closet(壁橱)与 Drawer(抽屉):摘要与原文
每个 Room 包含两部分内容:
Closet(壁橱):简短摘要(200-500 tokens)
用途:当上下文窗口紧张时,只加载 Closet 就能回忆起大致内容。
生成方式:
def generate_closet(room):
# 用轻量级本地模型生成摘要(不调用外部 API)
summary = local_llm.summarize(
text=room.full_conversation,
max_tokens=200,
model="phi-3-mini" # 本地运行的小模型
)
return summary
Drawer(抽屉):完整原始对话(可能长达数万 tokens)
用途:当 AI 需要完整上下文时(比如你在追问一个三个月前的技术决策的详细推理),加载 Drawer。
存储方式:原始文本直接存入 ChromaDB,不做任何删减。
4.6 Tunnel(隧道):跨 Wing 的主题连接
这是 MemPalace 最巧妙的设计之一。
问题场景:
你在「项目A」中讨论了「用 Rust 实现高性能日志解析器」,在「项目B」中讨论了「用 Rust 实现网络协议解析器」。这两个讨论都涉及 Rust 的性能优化技巧。
传统方案:两次讨论是隔离的,AI 无法把它们的经验结合起来。
MemPalace 的 Tunnel:
tunnel = Tunnel(
topic="Rust 性能优化技巧",
connected_rooms=[
{"wing": "Project-A", "hall": "technical_decisions", "room": "Rust日志解析器优化"},
{"wing": "Project-B", "hall": "technical_decisions", "room": "Rust网络解析器优化"},
],
created_at="2026-06-15T09:00:00Z",
)
当有查询涉及「Rust 性能优化」时,MemPalace 会通过 Tunnel 把两个 Room 的 Drawer 都加入检索候选集。
Tunnel 的自动发现:
MemPalace 定期(默认每周)运行一个后台任务,分析所有 Room 的标签和摘要,自动发现跨 Wing 的主题关联并创建 Tunnel。
5. 四层记忆栈 L0-L3:从 170 tokens 到 19.5M tokens 的智能加载
5.1 分层的动机
假设你的 MemPalace 已经运行了 6 个月,积累了:
- 对话原文:~50MB(约 12.5M tokens)
- 代码快照:~20MB(约 5M tokens)
- 调试日志:~10MB(约 2.5M tokens)
总计约 20M tokens。
你不可能把 20M tokens 全部塞进一次对话的上下文窗口(哪怕 Claude 的 200K 窗口也不够)。
但你也不应该让 AI 在缺少关键上下文的情况下回答问题。
MemPalace 的解决方案:把记忆分成四层,根据当前任务的紧急程度和上下文预算,智能加载不同层级的记忆。
5.2 Layer 0:索引层(170 tokens)
内容:所有 Wing/Hall/Room 的名称列表和一句话摘要。
示例:
L0_index = {
"wings": [
{
"name": "Project-A",
"halls": [
{
"name": "technical_decisions",
"rooms": [
{"name": "为什么选 PostgreSQL", "summary": "讨论了 PG 和 MySQL 对比", "last_access": "2026-06-20"},
{"name": "微服务拆分边界", "summary": "确定了用户服务和订单服务的边界", "last_access": "2026-06-18"},
# ...
]
},
# ...
]
},
# ...
]
}
大小:约 170 tokens(对 6 个月的使用量)
加载时机:每次对话都加载。这 170 tokens 让 AI 知道「记忆宫殿里有什么」,从而能准确判断需要深入哪个 Room。
实现细节:
def build_L0_index(palace):
index = {"wings": []}
for wing in palace.wings:
wing_entry = {
"name": wing.name,
"halls": []
}
for hall in wing.halls:
hall_entry = {
"name": hall.name,
"rooms": []
}
for room in hall.rooms:
hall_entry["rooms"].append({
"name": room.name,
"summary": room.closet, # 200 tokens 摘要
"last_access": room.last_accessed
})
wing_entry["halls"].append(hall_entry)
index["wings"].append(wing_entry)
# 压缩成最紧凑的 JSON 格式
return json.dumps(index, ensure_ascii=False)
5.3 Layer 1:Closet 层(5K-15K tokens)
内容:匹配当前查询的 Room 的 Closet(摘要)。
加载逻辑:
def load_L1_for_query(query, palace, max_tokens=10000):
# 1. 用 L0 索引确定候选 Room
candidate_rooms = []
for wing in palace.wings:
if is_relevant(query, wing.name):
for hall in wing.halls:
if is_relevant(query, hall.name):
for room in hall.rooms:
if is_relevant(query, room.name) or is_relevant(query, room.closet):
candidate_rooms.append(room)
# 2. 按相关度排序
candidate_rooms.sort(key=lambda r: relevance_score(query, r))
# 3. 装入上下文预算
loaded = []
total_tokens = 0
for room in candidate_rooms:
closet_tokens = count_tokens(room.closet)
if total_tokens + closet_tokens > max_tokens:
break
loaded.append(room.closet)
total_tokens += closet_tokens
return loaded
大小:5K-15K tokens(约 10-30 个 Room 的 Closet)
加载时机:当你问「我们之前讨论过数据库选型吗?」这类需要概览的问题时,加载 L1。
5.4 Layer 2:Drawer 精选层(50K-100K tokens)
内容:最相关的 3-5 个 Room 的完整 Drawer(原始对话)。
加载逻辑:
def load_L2_for_query(query, palace, max_tokens=100000):
# 1. 先用向量检索找到最相关的 Room
query_embedding = embed_model.encode(query)
candidates = []
for wing in palace.wings:
for hall in wing.halls:
for room in hall.rooms:
# 用 Room 的摘要和标签做向量检索
room_embedding = embed_model.encode(room.closet + " " + " ".join(room.tags))
similarity = cosine_similarity(query_embedding, room_embedding)
candidates.append((room, similarity))
# 2. 取 top-5
top_rooms = sorted(candidates, key=lambda x: x[1], reverse=True)[:5]
# 3. 装入上下文预算
loaded = []
total_tokens = 0
for room, score in top_rooms:
drawer_tokens = count_tokens(room.drawer)
if total_tokens + drawer_tokens > max_tokens:
# 如果单个 Drawer 太大,截断并附上提示
truncated = truncate_to_budget(room.drawer, max_tokens - total_tokens)
loaded.append(truncated)
break
loaded.append(room.drawer)
total_tokens += drawer_tokens
return loaded
大小:50K-100K tokens(约 3-5 个完整对话)
加载时机:当你问「把当时讨论 PostgreSQL 和 MySQL 对比的完整对话给我看看」时,加载 L2。
5.5 Layer 3:全量层(可达 19.5M tokens)
内容:整个 Palace 的所有 Drawer。
加载方式:不直接加载到上下文——而是提供一个检索接口,让 AI 在需要时能按需读取。
class L3_FullMemory:
def __init__(self, palace):
self.palace = palace
self.chroma_client = chromadb.PersistentClient(path="./mempalace_chroma")
self.collection = self.chroma_client.get_collection("full_conversations")
def retrieve(self, query, n_results=10):
# 在完整对话库里做语义检索
results = self.collection.query(
query_texts=[query],
n_results=n_results
)
return results
def read_room(self, wing_name, hall_name, room_name):
# 精确读取某个 Room 的完整内容
wing = self.palace.get_wing(wing_name)
hall = wing.get_hall(hall_name)
room = hall.get_room(room_name)
return room.drawer # 完整原始对话
大小:理论上无限制(取决于你用了多久)
访问时机:AI 在回答过程中发现需要更多上下文时,通过工具调用按需读取。
# AI 的工具调用示例
{
"tool": "mempalace_retrieve",
"parameters": {
"query": "PostgreSQL JSONB 性能优化具体参数",
"n_results": 3
}
}
5.6 四层加载的完整流程
def answer_with_memory(query, palace, llm, context_budget=200000):
"""
用四层记忆栈回答问题的完整流程
"""
# Step 1: 总是加载 L0(170 tokens)
L0 = build_L0_index(palace)
context = [L0]
used_tokens = count_tokens(L0)
# Step 2: 让 LLM 判断需要加载哪些 Room
llm_decision = llm.call(
messages=[
{"role": "system", "content": "你是一个有记忆的 AI 助手。下面是你记忆宫殿的索引。"},
{"role": "user", "content": f"记忆索引:\n{L0}\n\n用户问题:{query}\n\n你需要加载哪些 Room 的详细内容?请列出 Room 名称。"}
],
max_tokens=500
)
# Step 3: 根据 LLM 的判断,加载 L1(Closet)
relevant_rooms = parse_llm_decision(llm_decision)
L1 = load_closets(relevant_rooms)
context.append(L1)
used_tokens += count_tokens(L1)
# Step 4: 如果上下文预算还有余量,加载 L2(精选 Drawer)
if used_tokens < context_budget * 0.6: # 留 40% 给回答
L2 = load_drawers(relevant_rooms[:3]) # 只加载最相关的 3 个
context.append(L2)
used_tokens += count_tokens(L2)
# Step 5: 生成回答(如果 AI 需要更多细节,它会通过工具调用访问 L3)
answer = llm.call(
messages=[
{"role": "system", "content": f"你的记忆上下文:\n{context}"},
{"role": "user", "content": query}
],
tools=[mempalace_retrieve_tool, mempalace_read_room_tool] # L3 访问工具
)
return answer
6. ChromaDB 原生存储与 AAAK 无损压缩技术
6.1 为什么选 ChromaDB?
MemPalace 用 ChromaDB 作为向量数据库,而不是 Pinecone、Weaviate 或 Qdrant。
原因:
- 嵌入式运行:ChromaDB 可以纯本地运行,数据持久化到磁盘,无需单独的服务进程
- Python-first:API 设计对 Python 开发者友好,集成成本低
- 元数据过滤:支持 where 子句,配合 Wing/Hall/Room 的结构化检索非常合适
- 开源:代码完全透明,可以根据需要修改
ChromaDB 集成示例:
import chromadb
from chromadb.config import Settings
# 初始化本地 ChromaDB
client = chromadb.PersistentClient(
path="./mempalace_data/chroma",
settings=Settings(
allow_reset=True,
anonymized_telemetry=False # 关闭遥测
)
)
# 创建或获取 collection
collection = client.get_or_create_collection(
name="mempalace_conversations",
metadata={"hnsw:space": "cosine"} # 用余弦相似度
)
# 存储一段对话
collection.add(
documents=["完整对话原文..."],
metadatas=[{
"wing": "Project-A",
"hall": "technical_decisions",
"room": "为什么选 PostgreSQL",
"timestamp": "2026-06-01T10:30:00Z",
"access_count": 0,
"tags": "database,postgresql,mysql,tech-stack"
}],
ids=["wing-project-a_hall-tech-decisions_room-why-postgresql_20260601"]
)
6.2 AAAK 无损压缩技术
AAAK(Adaptive Approximate Archiving with Keyword preservation)是 MemPalace 自研的压缩算法,能把对话原文压缩 30 倍而不丢失关键信息。
核心思路:
传统压缩(如 gzip)是基于统计冗余的——它不知道哪些信息「重要」,哪些「不重要」。
AAAK 的做法是:
- 关键词保留:用 NLP 提取对话中的关键技术术语(如「PostgreSQL」、「JSONB」、「并发性能」),确保这些词不被压缩
- 近似句子合并:语义高度相似的相邻句子,合并成一个代表句
- 冗余废话删除:删除无信息量的填充词(「嗯」、「好的」、「我明白了」)
算法伪代码:
def aaak_compress(text, compression_ratio=30):
"""
AAAK 压缩主函数
:param text: 原始对话文本
:param compression_ratio: 目标压缩比(30 = 压缩到原来的 1/30)
:return: 压缩后的文本
"""
# Step 1: 提取关键词(技术术语、专有名词、代码标识符)
keywords = extract_keywords(text, method="tf-idf+pos")
# Step 2: 分句
sentences = split_into_sentences(text)
# Step 3: 计算句子重要性
sentence_scores = []
for sent in sentences:
score = 0
# 包含关键词的句子得分高
for kw in keywords:
if kw in sent:
score += 2
# 包含代码的句子得分高
if contains_code(sent):
score += 3
# 包含决策结论的句子得分高
if is_conclusion(sent):
score += 2
sentence_scores.append((sent, score))
# Step 4: 按重要性排序,保留 top-(1/compression_ratio)
keep_count = max(1, int(len(sentences) / compression_ratio))
top_sentences = sorted(sentence_scores, key=lambda x: x[1], reverse=True)[:keep_count]
# Step 5: 按原始顺序重排(保持时间线)
top_sentences.sort(key=lambda x: sentences.index(x[0]))
# Step 6: 拼接成压缩文本
compressed = " ".join([s[0] for s in top_sentences])
return compressed
压缩效果对比:
| 原始文本 | gzip | AAAK |
|---|---|---|
| 技术对话 10K tokens | ~3.5K tokens | ~330 tokens |
| 代码片段 5K tokens | ~2K tokens | ~450 tokens(代码不压缩) |
| 调试日志 20K tokens | ~6K tokens | ~670 tokens |
为什么叫「无损」?
AAAK 压缩是有损压缩——但它保证:
- 所有关键词都被保留
- 代码片段不被压缩(可选)
- 决策结论不被压缩
所以对人文学科文本,AAAK 可能丢失细节;但对技术对话,它的「有损」程度是可以接受的。
6.3 存储成本实测
很多人担心:「原始逐字存储,6 个月后我的硬盘不会爆吗?」
实际测试(基于作者自己的使用数据):
使用场景:每天与 Claude 对话 2 小时,平均每次对话 5K tokens
6 个月累计:2h * 300天 * 5K = 3M tokens
原始文本大小:~12MB
AAAK 压缩后:~400KB
ChromaDB 向量索引:~80MB(包含嵌入向量)
总计:~80.4MB
是的,你没看错。6 个月的完整对话历史,只占 80MB 磁盘。
这是因为:
- 文本本身的存储开销很小(12MB 原始,400KB 压缩后)
- 真正的空间开销是向量嵌入——但 ChromaDB 用的是
all-MiniLM-L6-v2,每个文本片段的嵌入向量只有 384 维,占用约 1.5KB
所以哪怕你有 100 万个文本片段,向量存储也只占 1.5GB。
7. 矛盾检测与时间有效性知识图谱
7.1 问题:记忆会过期
你三个月前讨论过「用 Redis 做缓存」,但现在已经换成了 Memcached。
当你问「我们的缓存方案是什么?」,MemPalace 可能会同时检索到:
- 三个月前的记忆:「我们决定用 Redis」
- 上个月的记忆:「我们迁移到了 Memcached」
如果 AI 不加以区分,可能会给出矛盾或错误的回答。
7.2 矛盾检测机制
MemPalace 在存储新记忆时,会主动检查与现有记忆的矛盾:
def detect_contradiction(new_memory, existing_memories):
"""
检测新记忆与现有记忆的矛盾
"""
contradictions = []
for old_memory in existing_memories:
# 用 LLM 判断两条记忆是否矛盾
prompt = f"""
判断以下两条记忆是否矛盾:
记忆A(时间:{old_memory.timestamp}):
{old_memory.closet}
记忆B(时间:{new_memory.timestamp}):
{new_memory.closet}
如果矛盾,请回答:CONTRADICTION: <矛盾说明>
如果不矛盾,请回答:NO_CONTRADICTION
"""
response = local_llm.call(prompt, max_tokens=200)
if response.startswith("CONTRADICTION"):
contradictions.append({
"old_memory": old_memory,
"new_memory": new_memory,
"reason": response.split(": ", 1)[1]
})
return contradictions
检测到矛盾后的处理:
def handle_contradiction(contradiction):
old = contradiction["old_memory"]
new = contradiction["new_memory"]
reason = contradiction["reason"]
# 方案A:标记旧记忆为「已过期」
if new.timestamp > old.timestamp:
old.metadata["deprecated"] = True
old.metadata["deprecation_reason"] = reason
old.metadata["superseded_by"] = new.id
# 方案B:在旧记忆和新记忆之间创建「演变关系」
tunnel = Tunnel(
topic=f"记忆演变: {reason}",
connected_rooms=[old.room, new.room],
relation="evolved_from"
)
old.palace.add_tunnel(tunnel)
# 方案C:通知用户(如果矛盾涉及重要决策)
if is_important_decision(old):
notify_user(f"检测到记忆矛盾:{reason}。旧记忆已标记为过期。")
7.3 时间有效性知识图谱
除了矛盾检测,MemPalace 还维护一个时间有效性知识图谱,记录每个技术决策的「有效期」。
示例:
knowledge_graph = {
"nodes": [
{
"id": "decision-001",
"type": "technical_decision",
"content": "选用 PostgreSQL 作为主数据库",
"valid_from": "2026-06-01T10:30:00Z",
"valid_until": None, # None 表示「目前仍然有效」
"confidence": 0.95
},
{
"id": "decision-002",
"type": "technical_decision",
"content": "选用 Redis 作为缓存",
"valid_from": "2026-06-01T14:00:00Z",
"valid_until": "2026-08-15T09:20:00Z", # 已过期
"confidence": 0.90,
"deprecation_reason": "迁移到了 Memcached"
}
],
"edges": [
{
"from": "decision-002",
"to": "decision-003",
"relation": "superseded_by",
"note": "缓存方案从 Redis 迁移到 Memcached"
}
]
}
查询时的时间有效性过滤:
def retrieve_with_temporal_filter(query, current_time, palace):
"""
检索时只考虑当前仍然有效的记忆
"""
candidates = retrieve_all(query, palace)
valid_memories = []
for mem in candidates:
# 检查有效期
if mem.valid_until is None:
# 没有设置过期时间,默认有效
valid_memories.append(mem)
elif current_time < mem.valid_until:
# 还没过期
valid_memories.append(mem)
else:
# 已过期,跳过
pass
return valid_memories
8. MCP 集成实战:给 Claude Code 装上长期记忆
8.1 什么是 MCP?
MCP(Model Context Protocol)是 Anthropic 2024 年推出的开放协议,用于让 AI 模型与外部工具/数据源标准化集成。
MemPalace 实现了 MCP Server,可以被 Claude Code、Cursor、OpenClaw 等支持 MCP 的 AI 工具直接调用。
8.2 安装 MemPalace MCP Server
方法一:从 GitHub 安装(推荐)
# 克隆仓库
git clone https://github.com/MemPalace/mempalace.git
cd mempalace
# 用 uv 安装依赖(比 pip 快)
uv sync
# 运行 MCP Server
uv run mempalace mcp
方法二:作为 Claude Code 插件安装
# 在 Claude Code 中运行
/plugin marketplace add MemPalace/mempalace
/plugin install --scope user mempalace
然后重启 Claude Code,输入 /skills 验证 mempalace 是否出现。
8.3 配置 Claude Code 使用 MemPalace
创建或编辑 ~/.claude/settings.json:
{
"mcpServers": {
"mempalace": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"--volume",
"./mempalace_data:/data",
"mempalace/mempalace:latest"
],
"env": {
"MEMPALACE_DATA_DIR": "/data",
"MEMPALACE_EMBED_MODEL": "all-MiniLM-L6-v2"
}
}
}
}
或者不依赖 Docker,直接用 Python 运行:
{
"mcpServers": {
"mempalace": {
"command": "uv",
"args": [
"--directory",
"/path/to/mempalace",
"run",
"mempalace",
"mcp"
],
"env": {
"MEMPALACE_DATA_DIR": "~/.mempalace/data"
}
}
}
}
8.4 MCP 工具详解
MemPalace MCP Server 提供以下工具:
工具1:mempalace_store
存储一段对话或笔记到记忆宫殿。
# 调用示例(Claude Code 自动调用,你不需要手动调用)
{
"tool": "mempalace_store",
"parameters": {
"content": "用户问我项目数据库选型,我建议用 PostgreSQL...", # 完整对话
"wing": "Project-A", # 可选,不提供则自动判断
"hall": "technical_decisions", # 可选
"tags": ["database", "postgresql", "tech-stack"] # 可选
}
}
工具2:mempalace_retrieve
从记忆宫殿检索相关记忆。
{
"tool": "mempalace_retrieve",
"parameters": {
"query": "PostgreSQL 选型讨论",
"n_results": 5,
"include_context": "closet" # 或 "drawer"(完整原文)
}
}
工具3:mempalace_forget
标记某段记忆为「已遗忘」(软删除,不真正删除数据)。
{
"tool": "mempalace_forget",
"parameters": {
"room_id": "wing-project-a_hall-tech-decisions_room-why-postgresql_20260601",
"reason": "这个决策已经被推翻"
}
}
工具4:mempalace_list_wings
列出所有 Wing(项目/人物)。
{
"tool": "mempalace_list_wings",
"parameters": {}
}
工具5:mempalace_export
导出整个记忆宫殿(用于备份或迁移)。
{
"tool": "mempalace_export",
"parameters": {
"format": "json", # 或 "markdown"
"output_path": "~/.mempalace/backup_20260625.json"
}
}
8.5 在 Claude Code 中使用 MemPalace 的完整流程
第一次使用:
你:嘿 Claude,帮我记一下:我们项目决定用 PostgreSQL 作为主数据库,主要是看中它的 JSONB 支持和并发性能。
Claude:(自动调用 mempalace_store)
[Tool: mempalace_store]
已存储到记忆宫殿:Wing: 当前项目 / Hall: 技术决策 / Room: 选用 PostgreSQL 作为主数据库
你:好的。一个月后你还会记得吗?
Claude:会的。MemPalace 会把这段记忆持久化到本地 ChromaDB,哪怕你重启 Claude Code,我也能记得。
(一个月后)
你:我们数据库用的什么来着?
Claude:(自动调用 mempalace_retrieve)
[Tool: mempalace_retrieve]
根据记忆宫殿,我们在 2026-06-01 讨论并决定:用 PostgreSQL 作为主数据库,主要理由是 JSONB 支持和并发性能。
需要我调出当时讨论的完整对话吗?
9. 性能基准深度对比:96.6% 是怎么炼成的
9.1 LongMemEval 基准测试
LongMemEval 是专为大语言模型长期记忆能力设计的基准测试。
测试内容:
- 100 个多轮对话场景
- 每个场景跨越 5-20 轮对话
- 评估 AI 是否能正确回忆起早期对话中的细节
评估指标:
- R@5(Recall@5):前 5 条检索结果中包含正确答案的比例
- Accuracy:最终回答正确的比例
9.2 MemPalace 的测试结果
| 系统 | R@5 | Accuracy | 本地运行 | API 调用 |
|---|---|---|---|---|
| MemPalace(raw verbatim) | 96.6% | 94.2% | ✅ | 0 |
| MemPalace(with summary) | 89.3% | 85.7% | ✅ | 0 |
| mem0(默认配置) | 78.4% | 72.1% | ✅ | 可选 |
| Zep | 82.1% | 76.8% | ❌ | 必需 |
| OpenAI ChatGPT(有记忆) | 91.2% | 88.3% | ❌ | 必需 |
| LangChain Memory | 65.7% | 58.9% | ✅ | 可选 |
关键发现:
- 原始存储(raw verbatim)比摘要存储高 7.3% R@5——证明「不丢失任何细节」的设计决策是正确的
- MemPalace 在零 API 调用的情况下,超过了依赖云服务的 Zep 和 ChatGPT
- 与 LangChain Memory 相比,领先优势达到 30.9% R@5——说明结构化记忆组织比简单的对话历史注入有效得多
9.3 96.6% 是怎么做到的?
因素一:原始逐字存储
摘要过程会丢失细节。比如这段对话:
用户:我们选 PostgreSQL 的时候,有没有考虑过它的 JSONB 性能问题?
AI:考虑了。当时测试了 JSONB 和 MongoDB 的嵌套文档查询性能,PostgreSQL 在范围查询上快 40%。
用户:有没有测试过 Array 类型?
AI:还没,不过根据文档,Array 类型的索引效率也很高...
如果摘要,可能会变成:「讨论了 PostgreSQL JSONB 性能,比 MongoDB 快 40%。」
但你丢失了「Array 类型还没测试」这个细节。一个月后当你问「我们的 JSONB 性能测试完整吗?」,AI 不知道 Array 类型还没测。
原始存储保留了完整的对话上下文,让未来的检索能捕捉到这些细节。
因素二:层级结构检索
纯向量检索的问题是「语义漂移」。
比如你搜索「PostgreSQL 性能」,纯向量检索可能返回:
- 「PostgreSQL 并发性能优化」 ✅ 相关
- 「PostgreSQL JSONB 查询性能测试」 ✅ 相关
- 「PostgreSQL vs MySQL 性能对比」 ✅ 相关
- 「PostgreSQL 在量子计算中的应用」 ❌ 不相关(但「性能」这个词触发了检索)
MemPalace 的层级检索先做结构化过滤(Wing -> Hall -> Room),再做向量检索,大大降低了语义漂移。
因素三:四层记忆栈
L0 索引让 AI 在回答前就知道「记忆宫殿里有什么」,从而能更准确地决定去哪里找答案。
这比「盲目检索向量数据库」的命中率高得多。
10. 生产级部署:从零到运行的完整 SOP
10.1 环境准备
最低配置:
- CPU:4 核(嵌入模型推理)
- 内存:8GB(ChromaDB 缓存)
- 磁盘:10GB(6 个月使用量)
推荐配置:
- CPU:8 核
- 内存:16GB
- 磁盘:50GB(SSD)
- GPU:可选(NVIDIA GTX 1660 或更高,用于加速嵌入推理)
10.2 安装步骤
Step 1:安装 uv(Python 包管理器)
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
Step 2:克隆 MemPalace 仓库
git clone https://github.com/MemPalace/mempalace.git
cd mempalace
Step 3:安装依赖
uv sync
这会创建一个隔离的虚拟环境,并安装所有依赖(包括 ChromaDB、sentence-transformers 等)。
Step 4:下载嵌入模型
# 首次运行会自动下载,也可以手动预下载
python -c "from sentence_transformers import SentenceTransformer; SentenceTransformer('all-MiniLM-L6-v2')"
模型大小约 80MB,下载到 ~/.cache/huggingface/hub/。
Step 5:初始化记忆宫殿
uv run mempalace init --data-dir ~/.mempalace/data
这会创建:
~/.mempalace/data/
├── chrome/ # ChromaDB 数据
├── palaces/ # 记忆宫殿配置
│ └── default.json
└── logs/ # 运行日志
10.3 集成到 Claude Code
方法A:MCP 配置(推荐)
编辑 ~/.claude/settings.json:
{
"mcpServers": {
"mempalace": {
"command": "uv",
"args": [
"--directory",
"/path/to/mempalace",
"run",
"mempalace",
"mcp"
],
"env": {
"MEMPA
LACE_DATA_DIR": "~/.mempalace/data",
"MEMPA
LACE_LOG_LEVEL": "INFO"
}
}
}
}
方法B:Claude 插件(更简单)
在 Claude Code 中运行:
/plugin marketplace add MemPalace/mempalace
/plugin install --scope user mempalace
10.4 验证安装
重启 Claude Code,然后测试:
你:嘿 Claude,把这段话存到记忆宫殿:「今天学会了用 MemPalace,作者是 Milla Jovovich。」
Claude:(应该自动调用 mempalace_store)
已存储!
你:刚才存了什么?
Claude:(应该自动调用 mempalace_retrieve)
根据记忆宫殿,你刚才让我存的是:「今天学会了用 MemPalace,作者是 Milla Jovovich。」
如果看到这个,说明安装成功!
10.5 生产环境优化
优化一:嵌入模型加速
默认用的 all-MiniLM-L6-v2 是速度和质量的平衡选择。如果你需要更快的速度,可以换成:
# 在 ~/.mempalace/config.py 中设置
EMBED_MODEL = "paraphrase-MiniLM-L3-v2" # 更快,但精度略低
如果需要更高的精度,可以换成:
EMBED_MODEL = "all-mpnet-base-v2" # 更慢,但精度更高
优化二:ChromaDB 持久化调优
# 在初始化 ChromaDB 时设置
client = chromadb.PersistentClient(
path="./mempalace_data/chroma",
settings=Settings(
chroma_db_impl="duckdb+parquet", # 用 DuckDB 做元数据存储
persist_directory="./mempalace_data/chroma",
allow_reset=True
)
)
优化三:定期清理过期记忆
# 每周运行一次
uv run mempalace maintenance --deprecate-old --merge-similar --optimize-index
这会:
- 标记超过 6 个月未访问且已过期的记忆为「归档」
- 合并内容高度相似的 Room
- 重建向量索引(优化检索速度)
11. 与其他记忆系统对比:MemPalace vs mem0 vs OpenClaw
11.1 功能对比矩阵
| 功能 | MemPalace | mem0 | Zep | OpenClaw Memory |
|---|---|---|---|---|
| 本地运行 | ✅ | ✅ | ❌ | ✅ |
| 零 API 成本 | ✅ | ✅(可选) | ❌ | ✅ |
| 原始逐字存储 | ✅ | ❌(摘要) | ❌(摘要) | ❌(全量但非结构化) |
| 结构化记忆组织 | ✅(Wing/Hall/Room) | ❌(扁平) | ❌(扁平) | ❌(扁平) |
| 四层记忆栈 | ✅ | ❌ | ❌ | ❌ |
| MCP 支持 | ✅ | ✅ | ❌ | ✅ |
| 矛盾检测 | ✅ | ❌ | ❌ | ❌ |
| 时间有效性 | ✅ | ❌ | ❌ | ❌ |
| LongMemEval R@5 | 96.6% | 78.4% | 82.1% | ~75%(估算) |
11.2 设计哲学对比
MemPalace:「存一切,让结构化和检索去解决怎么找回来」
- 优点:不丢失细节,检索精度高
- 缺点:存储开销相对大(但仍然很小),需要本地计算资源
mem0:「智能筛选重要信息存储」
- 优点:存储效率高,只存「重要」的
- 缺点:「重要性」判断不可靠,可能丢失关键细节
Zep:「云端托管的记忆服务」
- 优点:无需本地部署,开箱即用
- 缺点:隐私风险,持续成本,依赖网络
OpenClaw Memory:「全量上下文管理」
- 优点:简单直接,不挑食
- 缺点:缺乏结构化组织,检索效率低
11.3 选型建议
选 MemPalace,如果你:
- 重视隐私(不想让对话数据离开本地)
- 需要最高的记忆召回率
- 愿意投入少量本地计算资源
- 做长期项目,需要跨数月的记忆管理
选 mem0,如果你:
- 需要快速上手,不想折腾部署
- 对记忆召回率要求不是极高
- 愿意让 AI 决定什么该记住
选 Zep,如果你:
- 不想自己维护基础设施
- 愿意为托管服务付费
- 不处理敏感数据
12. 源码解析:关键模块与扩展点
12.1 项目结构
mempalace/
├── mempalace/
│ ├── __init__.py
│ ├── core/
│ │ ├── palace.py # Palace/Wing/Hall/Room 数据模型
│ │ ├── storage.py # ChromaDB 存储后端
│ │ ├── retrieval.py # 检索逻辑(层级+向量混合)
│ │ ├── compression.py # AAAK 压缩算法
│ │ ├── contradiction.py # 矛盾检测
│ │ └── knowledge_graph.py # 时间有效性知识图谱
│ ├── mcp/
│ │ ├── server.py # MCP Server 实现
│ │ └── tools.py # MCP 工具定义
│ ├── integrations/
│ │ ├── claude_code.py # Claude Code 集成
│ │ ├── cursor.py # Cursor 集成
│ │ └── openclaw.py # OpenClaw 集成
│ └── cli.py # 命令行入口
├── tests/
└── README.md
12.2 关键模块源码解读
palace.py:数据模型核心
@dataclass
class Room:
name: str
hall: "Hall" # 反向引用
closet: str # 200 tokens 摘要
drawer: str # 完整原始对话
tags: List[str]
created_at: datetime
last_accessed: datetime
access_count: int
metadata: Dict[str, Any]
def to_vector_doc(self) -> Dict:
"""
转换为 ChromaDB 向量文档格式
"""
return {
"id": self._generate_id(),
"document": self.drawer, # 用完整原文做向量化
"metadata": {
"wing": self.hall.wing.name,
"hall": self.hall.name,
"room": self.name,
"tags": ",".join(self.tags),
"last_accessed": self.last_accessed.isoformat(),
"access_count": self.access_count,
# Closet 单独存储,用于 L1 快速加载
"closet": self.closet
}
}
def _generate_id(self) -> str:
return f"wing-{self.hall.wing.name}_hall-{self.hall.name}_room-{slugify(self.name)}"
retrieval.py:混合检索
class HybridRetriever:
def __init__(self, palace: Palace, chroma_collection):
self.palace = palace
self.collection = chroma_collection
self.embed_model = SentenceTransformer(os.getenv("EMBED_MODEL", "all-MiniLM-L6-v2"))
def retrieve(self, query: str, n_results: int = 5, use_hybrid: bool = True) -> List[Room]:
if use_hybrid:
return self._hybrid_retrieve(query, n_results)
else:
return self._vector_retrieve(query, n_results)
def _hybrid_retrieve(self, query: str, n_results: int) -> List[Room]:
"""
层级检索 + 向量检索混合
"""
# Step 1: 用 L0 索引确定候选 Wing/Hall
candidate_rooms = self._navigate_hierarchy(query)
# Step 2: 在候选 Room 中做向量检索
query_embedding = self.embed_model.encode(query)
results = []
for room in candidate_rooms:
room_embedding = self.embed_model.encode(room.closet)
similarity = cosine_similarity(query_embedding, room_embedding)
results.append((room, similarity))
# Step 3: 排序并返回 top-N
results.sort(key=lambda x: x[1], reverse=True)
return [r[0] for r in results[:n_results]]
def _navigate_hierarchy(self, query: str) -> List[Room]:
"""
根据查询,导航到相关的 Wing/Hall
"""
candidates = []
query_lower = query.lower()
for wing in self.palace.wings:
# 如果查询包含 Wing 名称,优先加入
if wing.name.lower() in query_lower:
candidates.extend(self._all_rooms_in_wing(wing))
else:
# 否则检查 Hall 级别
for hall in wing.halls:
if hall.name.lower() in query_lower or any(tag in query_lower for tag in hall.tags):
candidates.extend(hall.rooms)
return candidates
def _vector_retrieve(self, query: str, n_results: int) -> List[Room]:
"""
纯向量检索(回退方案)
"""
results = self.collection.query(
query_texts=[query],
n_results=n_results
)
# 把 ChromaDB 结果转回 Room 对象
rooms = []
for doc_id in results["ids"][0]:
room = self._load_room_by_id(doc_id)
rooms.append(room)
return rooms
12.3 扩展点:如何自定义记忆组织规则
MemPalace 支持自定义 Hall 类型和 Room 分配逻辑。
示例:为「代码审查」场景扩展
# custom_halls.py
from mempalace.core import Hall, Room
class CodeReviewHall(Hall):
"""
自定义的「代码审查」Hall,自动从对话中提取代码片段并单独存储
"""
def __init__(self, wing):
super().__init__(name="code_reviews", wing=wing)
def _extract_code_snippets(self, conversation: str) -> List[str]:
"""
从对话中提取代码块
"""
import re
pattern = r"```(\w+)\n(.*?)```"
matches = re.findall(pattern, conversation, re.DOTALL)
return [m[1] for m in matches]
def add_conversation(self, conversation: str):
# 创建主 Room(完整对话)
main_room = Room(
name=f"Code review {datetime.now().isoformat()}",
closet=summarize(conversation),
drawer=conversation,
tags=["code-review"]
)
# 提取代码片段,创建子 Room
snippets = self._extract_code_snippets(conversation)
for i, snippet in enumerate(snippets):
snippet_room = Room(
name=f"Snippet {i+1} from {main_room.name}",
closet=snippet[:200], # 代码片段前 200 字符作为摘要
drawer=snippet,
tags=["code-snippet", extract_language(snippet)]
)
main_room.add_child(snippet_room)
self.rooms.append(main_room)
然后在初始化时注册:
from mempalace.core import Palace
from custom_halls import CodeReviewHall
palace = Palace(name="MyProject")
wing = palace.create_wing(name="Project-A", type="project")
wing.add_hall(CodeReviewHall(wing)) # 替换默认的 Hall
13. 未来展望:AI 记忆系统的下一步在哪里
13.1 当前痛点
虽然 MemPalace 在 LongMemEval 上取得了 96.6% 的好成绩,但仍有改进空间:
痛点一:嵌入模型质量
all-MiniLM-L6-v2 只有 384 维,对于高度技术性的对话(比如涉及多层嵌套的泛型类型讨论),语义捕获能力有限。
可能的改进:用领域微调的嵌入模型。比如用 GitHub 代码数据微调一个「代码-对话」联合嵌入模型。
痛点二:矛盾检测的误报
当前的矛盾检测有时会把「视角不同」误判为「矛盾」。
比如:
- 记忆A:「PostgreSQL 的 JSONB 查询很快」
- 记忆B:「PostgreSQL 的 JSONB 索引占用磁盘很大」
这两条并不矛盾——它们是关于 JSONB 的不同维度的讨论。但当前的 LLM-based 矛盾检测可能会误报。
可能的改进:引入知识图谱推理,而不是简单的 LLM 判断。
痛点三:跨语言检索
如果你的对话是中文的,但嵌入模型主要是在英文数据上训练的,检索精度会下降。
可能的改进:支持多语言嵌入模型(如 paraphrase-multilingual-MiniLM-L12-v2)。
13.2 MemPalace 路线图(根据 ROADMAP.md)
根据项目 ROADMAP.md,2026 年下半年的重点方向:
- 多模态记忆:支持存储和检索图片、图表(比如架构图、流程图)
- 协作记忆:多个用户共享同一个 Palace(适合团队协作)
- 记忆导出/导入:支持在不同 AI 工具间迁移记忆(比如从 Claude Code 迁移到 Cursor)
- Web UI:可视化的记忆宫殿管理界面(类似 Obsidian 的图谱视图)
- Agent 自动整理:定期让 AI Agent 自动整理记忆(合并相似 Room、创建 Tunnel、更新知识图谱)
13.3 更长远的问题:记忆的「所有权」
当 AI 有了长期记忆,一个哲学问题就出现了:
这些记忆是谁的?
如果你用 Claude Code + MemPalace 工作了一年,积累了几千条技术讨论记忆。然后你换到了 Cursor——这些记忆能带走吗?
MemPalace 的答案(目前)是:能。
因为所有数据都在本地,格式是开放的(ChromaDB + JSON),你可以导出成标准格式,然后导入到任何支持 MemPalace 格式的工具。
但这需要行业标准。希望 MCP 协议能扩展到「记忆迁移」场景,让记忆真正成为你的资产,而不是被锁定在某个工具里。
14. 总结:为什么 MemPalace 代表了 AI 记忆的新范式
14.1 核心贡献
MemPalace 的三个核心创新:
- 原始逐字存储(Raw Verbatim Storage):挑战了「AI 应该筛选重要信息存储」的共识,证明「全存+结构化检索」比「筛选+存储」更有效
- 记忆宫殿隐喻的数据模型:把人类的空间记忆原理引入 AI 系统设计,让记忆组织更符合直觉
- 四层记忆栈:巧妙解决了「记忆越多,检索越慢」的问题——通过分层,让 AI 能快速定位,按需深入
14.2 适用场景
强烈推荐:
- 长期技术项目(3 个月以上)
- 需要频繁回溯早期决策的场景
- 重视隐私的团队(本地运行,零数据离开机器)
- 使用 Claude Code / Cursor 的开发者
不推荐:
- 短期项目(用不了多久就结束了,没必要搭建记忆系统)
- 对本地计算资源极其敏感的场景(嵌入模型推理需要 CPU/GPU)
- 已经用了云端记忆系统且满意的团队(迁移有成本)
14.3 实践建议
如果你决定试试 MemPalace,以下建议能让你少走弯路:
建议一:从第一天就开启
记忆系统的价值是随时间积累的。如果你等「项目稳定了」再开启,就丢失了早期的讨论上下文。
建议二:定期回顾记忆宫殿
每周花 10 分钟,用 mempalace list 看看记忆宫殿里有什么。如果发现错误记忆,及时纠正。
建议三:自定义 Hall 类型
默认的 Hall 类型可能不完全符合你的工作流。别怕改——MemPalace 的数据模型是开放的。
建议四:关注矛盾检测通知
如果 MemPalace 提示「检测到记忆矛盾」,认真对待。这可能意味着你的项目方向变了,但 AI 还不知道。
14.4 最后的话
MemPalace 最有意思的地方不是技术,而是它的起源:《生化危机》女主角 Milla Jovovich 参与了开发。
这件事本身就是一个信号:AI 工具正在变得足够简单,让非工程师也能参与设计和开发。
2026 年,AI 辅助开发已经不是「工程师用 AI 写代码」——而是「任何有想法的人,都能和 AI 一起把想法变成产品」。
MemPalace 就是这个过程的一个完美样本。
参考资源
- MemPalace GitHub:https://github.com/MemPalace/mempalace
- LongMemEval 论文:[arXiv链接]
- ChromaDB 官方文档:https://docs.trychroma.com/
- MCP 协议规范:https://modelcontextprotocol.io/
- 记忆宫殿法(Method of Loci):维基百科
本文撰写于 2026 年 6 月,基于 MemPalace v3.0.14。如有技术细节更新,请以官方文档为准。
如果你觉得这篇文章有价值,欢迎分享给更多开发者。AI 记忆系统是 2026 年最值得关注的底层技术之一。