一、项目概述
1.1 定位与目标
MemPalace 是一个本地优先(Local-first)的AI记忆系统,旨在解决AI对话中"记忆消失"的核心问题。项目名称取自古希腊记忆术"记忆宫殿"(Method of Loci),将古罗马演说家西塞罗使用的记忆方法应用到AI记忆存储领域。
核心理念:
- 存储一切,然后让它可查找 — 不做摘要、不做提取、原文存储
- 零API调用 — 完全本地运行,数据永不离开用户机器
- 结构化索引 — 通过wing(翼)、room(房间)、hall(走廊)等概念组织记忆
1.2 核心功能
| 功能 | 描述 |
|---|---|
| 原文存储 | 将对话历史以原文形式存储在ChromaDB中,不做摘要或提取 |
| 语义搜索 | 支持按wing/room/hall多维度过滤的语义检索 |
| 知识图谱 | SQLite本地知识图谱,支持时序有效性和关系查询 |
| AAAK压缩 | 实验性压缩格式,用于上下文加载 |
| MCP服务 | 29个MCP工具,集成Claude Code等AI助手 |
| 自动保存钩子 | Claude Code的自动保存机制 |
1.3 技术栈
核心存储:
├── ChromaDB(默认向量数据库)
├── SQLite(知识图谱)
└── 可插拔后端接口(BaseCollection抽象)
语言与框架:
├── Python 3.9+
├── uv(包管理器)
├── PyPI分发
└── MCP协议(Model Context Protocol)
嵌入模型:
└── ~300MB(默认模型)
二、架构设计
2.1 整体架构
┌─────────────────────────────────────────────────────────────────┐
│ MemPalace 架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────────┐ ┌──────────────┐ │
│ │ Miners │────▶│ Palace Layer │◀────│ MCP Server │ │
│ │ (数据采集) │ │ (存储抽象层) │ │ (29工具) │ │
│ └─────────────┘ └─────────────────┘ └──────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Backends(可插拔) │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │ │
│ │ │ ChromaDB │ │ (Future) │ │ BaseCollection │ │ │
│ │ │ (默认) │ │ Qdrant │ │ (接口定义) │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Knowledge Graph (SQLite) │ │
│ │ Entities ◀───────▶ Triples (时序关系) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
2.2 核心模块关系
mempalace/
├── backends/
│ ├── base.py # BaseCollection 抽象接口
│ └── chroma.py # ChromaDB 后端实现
├── palace.py # 共享的Palace操作(锁、closet构建)
├── miner.py # 数据采集(项目文件、会话)
├── searcher.py # 混合搜索(向量+BM25)
├── knowledge_graph.py # 知识图谱(实体-关系)
├── mcp_server.py # MCP协议服务(29工具)
├── palace_graph.py # 图遍历(tunnel、tunnels)
├── config.py # 配置管理
└── query_sanitizer.py # 查询清理
2.3 数据流
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 文件/ │───▶│ Miner │───▶│ Chunking │───▶│ Drawer │
│ 对话 │ │ 采集器 │ │ 切分 │ │ 抽屉存储 │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
│
▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 查询 │◀───│ Searcher │◀───│ Metadata │◀───│ ChromaDB │
│ 用户 │ │ 搜索器 │ │ 过滤 │ │ 向量库 │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
三、关键技术
3.1 Palace记忆宫殿结构
这是MemPalace的核心创新——将记忆组织成宫殿结构:
+------------------------------------------------------------+
| WING: Project/Person |
| |
| +----------+ +----------+ |
| | Room A | --hall-- | Room B | |
| +----------+ +----------+ |
| │ |
| v |
| +----------+ +----------+ |
| | Closet | ---> | Drawer | # 原文抽屉 |
| +----------+ +----------+ |
+------------------------------------------------------------+
│
tunnel
│
+------------------------------------------------------------+
| WING: Another Project/Person |
+------------------------------------------------------------+
核心概念详解:
| 概念 | 作用 | 示例 |
|---|---|---|
| Wing | 项目/人员隔离 | wing_orion, wing_kai |
| Room | 主题分类 | auth-migration, graphql-switch |
| Hall | 记忆类型 | hall_facts, hall_events, hall_advice |
| Closet | 摘要索引 | 指向原文的可搜索摘要 |
| Drawer | 原文抽屉 | 原始内容,精确存储 |
| Tunnel | Wing间连接 | 跨项目的同一主题连接 |
3.2 混合搜索算法
searcher.py 实现了向量搜索 + BM25关键词的混合排序:
# 核心混合排序逻辑
def _hybrid_rank(
results: list,
query: str,
vector_weight: float = 0.6,
bm25_weight: float = 0.4,
) -> list:
"""
1. 向量相似度使用绝对cosine相似度:max(0, 1 - distance)
2. BM25使用Okapi-BM25公式,IDF基于候选集计算
3. BM25结果min-max归一化后与向量相似度加权组合
"""
搜索流程:
def search_memories(query, palace_path, wing=None, room=None, n_results=5):
# Step 1: 直接搜索抽屉(底层保证)
drawer_results = drawers_col.query(
query_texts=[query],
n_results=n_results * 3, # 过采样用于重排
...
)
# Step 2: 搜索closet获取排名信号
closet_boost_by_source = {}
# Step 3: 基于closet排名应用boost
CLOSET_RANK_BOOSTS = [0.40, 0.25, 0.15, 0.08, 0.04]
# Step 4: Drawer-grep上下文扩展
# 对于closet-boosted结果,用关键词匹配找到更好的chunk
# Step 5: BM25混合重排
hits = _hybrid_rank(hits, query)
设计亮点:抽屉搜索是地板(floor),永远不会被closet结果隐藏。Closet只是排名信号,不是门控。
3.3 知识图谱实现
knowledge_graph.py 实现了时序实体关系图:
class KnowledgeGraph:
"""
SQLite-backed temporal entity-relationship graph
特点:
- 实体节点 + 类型化关系边
- 时序有效性(valid_from → valid_to)
- 源引用(关联到原始记忆)
"""
def add_triple(self, subject, predicate, obj, valid_from=None, valid_to=None):
"""添加关系三元组"""
def invalidate(self, subject, predicate, obj, ended=None):
"""标记关系失效"""
def query_entity(self, name, as_of=None, direction="outgoing"):
"""查询实体在某时间点的状态"""
数据库模式:
CREATE TABLE entities (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
type TEXT DEFAULT 'unknown',
properties TEXT DEFAULT '{}',
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE triples (
id TEXT PRIMARY KEY,
subject TEXT NOT NULL,
predicate TEXT NOT NULL,
object TEXT NOT NULL,
valid_from TEXT, -- 时序:开始时间
valid_to TEXT, -- 时序:结束时间(NULL=当前有效)
confidence REAL DEFAULT 1.0,
source_closet TEXT, -- 指向原文
source_file TEXT,
extracted_at TEXT DEFAULT CURRENT_TIMESTAMP
);
3.4 可插拔后端架构
backends/base.py 定义了后端接口:
class BaseCollection(ABC):
"""最小集合接口,MemPalace其余部分依赖此接口"""
@abstractmethod
def add(self, *, documents, ids, metadatas=None):
raise NotImplementedError
@abstractmethod
def upsert(self, *, documents, ids, metadatas=None):
raise NotImplementedError
@abstractmethod
def query(self, **kwargs) -> Dict[str, Any]:
raise NotImplementedError
@abstractmethod
def get(self, **kwargs) -> Dict[str, Any]:
raise NotImplementedError
@abstractmethod
def delete(self, **kwargs) -> None:
raise NotImplementedError
@abstractmethod
def count(self) -> int:
raise NotImplementedError
这种设计允许替换ChromaDB为其他向量数据库(如Qdrant、Pinecone),无需修改上层代码。
3.5 并发安全机制
palace.py 实现了跨平台文件锁:
@contextlib.contextmanager
def mine_lock(source_file: str):
"""跨平台文件锁,防止多agent并发写入同一文件"""
lock_path = f".../{hashlib.sha256(source_file.encode()).hexdigest()[:16]}.lock"
if os.name == "nt": # Windows
import msvcrt
msvcrt.locking(lf.fileno(), msvcrt.LK_LOCK, 1)
else: # Unix
import fcntl
fcntl.flock(lf, fcntl.LOCK_EX)
yield
四、核心代码分析
4.1 Miner数据采集
miner.py 的核心是文件路由和chunking:
# 文件路由到房间的优先级
def detect_room(filepath, content, rooms, project_path):
"""
1. 文件夹路径匹配房间名/关键词
2. 文件名匹配房间名
3. 内容关键词评分
4. 默认fallback: "general"
"""
# 文本分块(Drawer创建)
CHUNK_SIZE = 800 # 每块字符数
CHUNK_OVERLAP = 100 # 重叠区域
def chunk_text(content, source_file):
"""按段落边界切分文本,保留语义完整性"""
4.2 Closet构建逻辑
palace.py 中的build_closet_lines:
def build_closet_lines(source_file, drawer_ids, content, wing, room):
"""
从原文中提取可搜索的索引行
格式: topic|entities|→drawer_ids
"""
# 1. 提取实名词(大小写敏感,≥2次出现)
words = re.findall(r"\b[A-Z][a-z]{2,}\b", window)
# 过滤停用词:The, This, When, Where...
# 2. 提取关键短语(动词+上下文)
patterns = [r"(?:built|fixed|wrote|added|pushed|...)\s+[\w\s]{3,40}"]
# 3. 提取Markdown标题
# 4. 提取引用
4.3 MCP Server架构
mcp_server.py 实现了完整的MCP协议:
# 工具注册表
TOOLS = {
# 读取工具
"mempalace_status": {...},
"mempalace_search": {...},
"mempalace_kg_query": {...},
"mempalace_traverse": {...},
# 写入工具
"mempalace_add_drawer": {...},
"mempalace_delete_drawer": {...},
"mempalace_kg_add": {...},
# 导航工具
"mempalace_follow_tunnels": {...},
"mempalace_create_tunnel": {...},
}
五、创新亮点
5.1 vs 其他AI记忆系统
| 特性 | MemPalace | Mem0 | Zep | Supermemory |
|---|---|---|---|---|
| 存储方式 | 原文verbatim | 摘要提取 | 摘要+图 | 混合 |
| 检索模式 | 向量+BM25混合 | 向量 | 向量+图 | 向量 |
| 知识图谱 | SQLite本地 | 云端 | Neo4j云端 | - |
| API依赖 | 无 | 需要 | 需要 | 需要 |
| LongMemEval R@5 | 96.6% | ~85% | ~85% | ~99% |
| 成本 | 免费 | $19-249/mo | $25/mo+ | - |
5.2 核心创新点
- 原文优先策略:不做摘要,存储一切,通过结构化索引让搜索更精准
- Palace记忆宫殿:Wing-Room-Hall-Drawer的多层组织,比扁平索引提升34%召回率
- 混合搜索Floor机制:抽屉搜索是地板,closet只是排名信号,永不隐藏结果
- Drawer-grep上下文:向量搜索可能选错chunk,用关键词在源文件中找到更好的
- AAAK压缩格式:实验性的人类和LLM可读的压缩语言
- 时序知识图谱:SQLite实现,支持时间旅行查询
5.3 基准测试表现
LongMemEval R@5 (500题):
├── Raw模式(纯向量): 96.6% ★ 无API调用
├── Hybrid v4 (held-out): 98.4% ★ 可复现
└── Hybrid + LLM rerank: ≥99% (使用Haiku等轻量模型)
LoCoMo R@10 (1986题):
├── Raw模式: 60.3%
└── Hybrid v5: 88.9%
ConvoMem (250项): 92.9%
MemBench (8500项): 80.3%
六、实践应用
6.1 快速开始
# 安装
pip install mempalace
# 初始化
mempalace init ~/projects/myapp
# 采集数据
mempalace mine ~/projects/myapp # 项目文件
mempalace mine ~/chats/ --mode convos # 对话导出
# 搜索
mempalace search "why did we switch to GraphQL"
# Claude Code集成
claude mcp add mempalace -- python -m mempalace.mcp_server
6.2 Python API使用
from mempalace.searcher import search_memories
from mempalace.knowledge_graph import KnowledgeGraph
# 语义搜索
results = search_memories(
"auth decisions",
palace_path="~/.mempalace/palace"
)
# 知识图谱查询
kg = KnowledgeGraph()
kg.add_triple("Kai", "works_on", "Orion", valid_from="2025-06-01")
# 查询实体的历史状态
facts = kg.query_entity("Maya", as_of="2026-01-20")
# 时间线
timeline = kg.timeline("Orion")
6.3 扩展方向建议
- 支持更多后端:实现Pinecone、Qdrant等后端适配器
- LLM重排优化:当前是可选步骤,可以集成更轻量的重排模型
- AAAK改进:当前实验性质,可研究更好的压缩算法
- 多模态支持:扩展到图像、音频记忆
- 协作功能:多人共享的分布式Palace
七、总结与思考
7.1 学习收获
- 架构设计:可插拔后端、多层抽象、接口驱动的设计值得学习
- 搜索工程:混合搜索的floor机制、drawer-grep上下文扩展是精妙的工程决策
- 本地优先:完全不依赖外部API的设计在隐私敏感场景很有价值
- 时序数据:知识图谱的时序有效性设计优雅而实用
7.2 可借鉴之处
| 场景 | 借鉴点 |
|---|---|
| 构建AI应用记忆层 | Palace结构的多层组织 |
| 设计向量搜索系统 | 混合搜索 + floor机制 |
| 实现知识图谱 | SQLite + 时序有效性 |
| MCP工具开发 | 完整的工具注册和参数白名单 |
| 审计日志 | WAL机制保护数据安全 |
7.3 潜在改进方向
- Benchmarks透明化:文档中已承认早期宣传数据有误,这种诚实态度值得肯定
- AAAK实验状态:README中明确标注了实验性质,避免误导用户
- 安全考虑:WAL脱敏、文件锁、权限控制等安全措施完整
相关链接
- 项目地址:https://github.com/MemPalace/mempalace
- 官方文档:https://mempalaceofficial.com/
- PyPI:https://pypi.org/project/mempalace/
本笔记基于 v3.3.0 版本分析,代码细节可能随版本更新而变化。