MemPalace 深度实战:37K Star 的 AI 记忆宫殿如何用 2000 年古老智慧重新定义 Agent 持久化记忆
引言:当金鱼大脑的 AI 遇上 2000 年的记忆术
你有没有经历过这种崩溃时刻:昨天刚告诉 Claude 你喜欢用 TypeScript,今天它又开始给你生成 JavaScript 代码;你费尽口舌解释了一个复杂的业务逻辑,下次对话它照问不误;你甚至开始怀疑,是不是每次都要从零开始训练一个"懂你"的 AI?
这不是 AI 不够聪明,而是 AI 没有"记忆"。大语言模型(LLM)本质上是一个"金鱼大脑"——每次对话都是全新的开始,上下文窗口一旦关闭,一切归零。这个问题在 2025 年底变得愈发尖锐:随着 AI Agent 的爆发,开发者们发现,一个没有持久记忆的 Agent,就像一个永远活在当下的人,无法积累经验、无法学习偏好、无法真正成为你的"助手"。
2026 年 4 月,一个名为 MemPalace(记忆宫殿)的开源项目横空出世,在 GitHub 上线几小时内就狂揽近 2 万 Star,目前已有 37.9K Star。它的核心理念出人意料地简单:用一个 2000 年前的认知技术——记忆宫殿(Method of Loci),来解决 AI 的记忆难题。
更令人惊讶的是,这个项目的联合开发者之一,是好莱坞女星米拉·乔沃维奇(Milla Jovovich)——《生化危机》系列电影的女主角。她不仅是动作片女王,更是一位资深程序员和 AI 研究者。她与工程师本·西格曼(Ben Sigman)共同开发的 MemPalace,正在重新定义 AI Agent 的记忆架构。
本文将深入剖析 MemPalace 的设计哲学、技术架构、代码实现,以及它与 EverOS、MemOS、Mem0 等同类方案的差异,带你全面理解这场 AI 记忆革命。
一、AI Agent 记忆问题的本质
1.1 从 Chatbot 到 Agent:记忆成为刚需
2023 年之前,大多数人使用 AI 的方式还是"Chatbot"模式:一问一答,对话结束即终止。上下文窗口的限制(4K、8K token)虽然恼人,但不是致命问题。
但 2024-2025 年,AI Agent 模式爆发了。Agent 不是简单的对话工具,而是能自主执行任务、调用工具、进行多步推理的智能体。它需要:
- 跨会话记忆:记住你上周告诉它的项目架构决策
- 偏好学习:知道你偏好函数式编程还是面向对象
- 错误避免:不再重复犯过的错误
- 知识积累:随着使用时间增长,越来越"懂你"
这些需求,LLM 原生无法满足。模型权重是固定的,上下文窗口是临时的,一旦对话关闭,所有信息丢失。
1.2 传统解决方案的困境
方案一:增大上下文窗口
Claude 3.5 支持 200K token 上下文,Gemini 2.0 支持 100 万 token。这看似解决了问题,但带来新挑战:
# 假设每次对话平均 2000 token
# 一年使用 300 次,累计 600,000 token
# 每次请求都要把这 600K token 塞进上下文
# 问题 1: 成本爆炸
# Claude 3.5 Sonnet: $3/M input tokens
# 每次请求成本: 600K * $3/M = $1.8
# 一年成本: 300 * $1.8 = $540
# 问题 2: 延迟增加
# 600K token 的预处理时间约 10-30 秒
# 问题 3: 噪声干扰
# 无关的历史信息可能干扰当前推理
上下文窗口不是记忆,是"工作台"。把所有历史塞进工作台,不仅低效,而且混乱。
方案二:RAG(检索增强生成)
RAG 是当前主流方案:把对话历史存入向量数据库,每次查询时检索相关片段。
from chromadb import Client
from sentence_transformers import SentenceTransformer
# 传统 RAG 流程
embedding_model = SentenceTransformer('all-MiniLM-L6-v2')
chroma = Client()
collection = chroma.create_collection("chat_history")
def save_memory(user_id, message, response):
# 将对话存入向量数据库
text = f"User: {message}\nAssistant: {response}"
embedding = embedding_model.encode(text)
collection.add(
documents=[text],
embeddings=[embedding.tolist()],
metadatas=[{"user_id": user_id}],
ids=[f"{user_id}_{len(collection.get()['ids'])}"]
)
def query_memory(user_id, query):
# 检索相关历史
query_embedding = embedding_model.encode(query)
results = collection.query(
query_embeddings=[query_embedding.tolist()],
n_results=5,
where={"user_id": user_id}
)
return results['documents'][0]
RAG 解决了"存储"问题,但缺乏"组织"。所有记忆平铺在向量空间里,没有层次结构,没有关联关系,没有遗忘机制。
方案三:Fine-tuning(微调)
微调模型来记住特定知识,看似完美:
# 理论上可行,但实际问题重重
# 问题 1: 灾难性遗忘
# 新知识会覆盖旧知识
# 问题 2: 更新成本高
# 每次新增知识都要重新微调
# 问题 3: 不支持个性化
# 无法为每个用户单独微调
微调适合"静态知识"(如医疗诊断规则),不适合"动态记忆"(如用户偏好)。
1.3 记忆的真正含义
当我们说"AI 需要记忆"时,究竟需要什么?让我们看看人类记忆系统的启发:
| 记忆类型 | 描述 | AI 对应 |
|---|---|---|
| 感觉记忆 | 极短时(<1秒),感官信息暂存 | 当前上下文窗口 |
| 工作记忆 | 短时(几十秒),当前任务处理 | 有限上下文窗口 |
| 情景记忆 | 个人经历、事件序列 | 用户交互历史 |
| 语义记忆 | 事实、概念、知识 | 模型权重 + RAG |
| 程序记忆 | 技能、习惯、偏好 | 难以建模 |
当前的 AI 系统只有"感觉记忆"(上下文窗口)和"语义记忆"(模型权重),缺乏真正意义上的"情景记忆"和"程序记忆"。MemPalace 正是试图填补这个空白。
二、MemPalace 的设计哲学:记忆宫殿的现代转译
2.1 古老智慧:Method of Loci
"记忆宫殿"(Method of Loci)是古希腊演说家发明的一种记忆术。核心思想是:
- 空间编码:将要记住的内容"放置"在熟悉的建筑空间里
- 位置定位:通过回忆空间布局,提取对应的记忆
- 故事关联:用夸张、生动的想象连接空间和内容
例如,要记住一篇演讲稿,你可以想象自己的家:
- 门口放"开场白"
- 客厅沙发放"第一个论点"
- 厨房冰箱放"第二个论点"
- 卧室床头放"结论"
演讲时,在脑海中"走过"这个家,每个位置触发对应内容。
这套技术之所以有效,是因为人类大脑对"空间"的处理能力远超"抽象信息"。海马体——负责记忆的关键脑区——同时也是空间导航中枢。空间与记忆在神经层面深度绑定。
2.2 MemPalace 的架构映射
MemPalace 创造性地将这套古老智慧转译为 AI 记忆架构:
┌─────────────────────────────────────────────────────────────┐
│ 记忆宫殿 (Palace) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 翼廊 (Wing) │ │
│ │ 人: "张三" │ │
│ │ 项目: "电商平台" │ │
│ │ │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ 房间 (Room) │ │ 房间 (Room) │ │ │
│ │ │ 话题: "架构设计" │ │ 话题: "性能优化" │ │ │
│ │ │ │ │ │ │ │
│ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │ │ │
│ │ │ │ 抽屉(Drawer)│ │ │ │ 抽屉(Drawer)│ │ │ │
│ │ │ │ "为什么选择 │ │ │ │ "Redis 缓存 │ │ │ │
│ │ │ │ 微服务架构" │ │ │ │ 策略优化" │ │ │ │
│ │ │ └─────────────┘ │ │ └─────────────┘ │ │ │
│ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │ │ │
│ │ │ │ 抽屉(Drawer)│ │ │ │ 抽屉(Drawer)│ │ │ │
│ │ │ │ "API 网关 │ │ │ │ "数据库连接 │ │ │ │
│ │ │ │ 选型决策" │ │ │ │ 池配置" │ │ │ │
│ │ │ └─────────────┘ │ │ └─────────────┘ │ │ │
│ │ └─────────────────┘ └─────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
三层结构解析:
翼廊(Wing):最高层级,对应"人"或"项目"
- 每个用户有独立的翼廊
- 每个项目也可以有独立翼廊
- 实现多租户隔离
房间(Room):中间层级,对应"话题"或"主题"
- 同一项目下不同技术领域
- 同一人的不同关注点
- 提供语义分区
抽屉(Drawer):最细粒度,存储原始记忆片段
- 具体的对话内容
- 决策记录
- 错误日志
- 代码片段
2.3 为什么这套架构有效?
优势一:层次化检索,减少噪声
传统 RAG 是"扁平检索":所有记忆混在一起,检索时可能拉出无关内容。
MemPalace 是"层次化检索":先定位翼廊(用户/项目),再定位房间(话题),最后打开抽屉(具体内容)。
# 传统 RAG 检索
def traditional_search(query, user_id):
# 在所有记忆中搜索
# 可能返回其他项目、其他话题的内容
results = vector_db.search(query, filter={"user_id": user_id})
return results
# MemPalace 检索
def mempalace_search(query, user_id, project_id, topic):
# Step 1: 定位翼廊
wing = palace.get_wing(user_id=user_id, project=project_id)
# Step 2: 定位房间
room = wing.get_room(topic=topic)
# Step 3: 在抽屉中检索
results = room.search_drawers(query)
return results
层次化检索大幅提高了检索精度,减少了无关记忆的干扰。
优势二:自然遗忘机制
人类记忆会自然遗忘——不常用的记忆逐渐模糊。MemPalace 模拟了这个机制:
class Drawer:
def __init__(self, content):
self.content = content
self.access_count = 0
self.last_access = time.time()
self.importance_score = 0.5
def access(self):
self.access_count += 1
self.last_access = time.time()
# 重要性随访问次数增加
self.importance_score = min(1.0, self.importance_score + 0.1)
def decay(self):
# 时间衰减
days_since_access = (time.time() - self.last_access) / 86400
decay_factor = math.exp(-0.1 * days_since_access)
self.importance_score *= decay_factor
# 低于阈值,移入"冷存储"
if self.importance_score < 0.1:
self.archive()
class Room:
def maintenance(self):
# 定期清理低重要性抽屉
for drawer in self.drawers:
drawer.decay()
self.drawers = [d for d in self.drawers if d.importance_score >= 0.1]
优势三:上下文压缩
不是所有记忆都需要完整保留。MemPalace 支持"摘要压缩":
def compress_room(room):
"""将房间内的多个抽屉压缩为摘要"""
all_content = "\n".join([d.content for d in room.drawers])
# 使用 LLM 生成摘要
summary = llm.generate(f"""
请总结以下对话片段的核心要点:
{all_content}
输出格式:
- 关键决策:...
- 重要偏好:...
- 待解决问题:...
""")
# 创建摘要抽屉
summary_drawer = Drawer(content=summary, is_summary=True)
room.drawers = [summary_drawer] # 原始抽屉归档
三、MemPalace 技术架构深度解析
3.1 整体架构
MemPalace 采用"本地优先"(Local-First)架构,核心组件包括:
┌──────────────────────────────────────────────────────────────┐
│ 客户端层 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Claude Code │ │ Cursor │ │ 任意 LLM │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
│ └─────────────────┼─────────────────┘ │
│ │ │
│ MCP Protocol │
│ │ │
├───────────────────────────┼───────────────────────────────────┤
│ MemPalace Server │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Memory Engine │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Wing Mgr │ │ Room Mgr │ │ Drawer Mgr │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Storage Layer │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ SQLite │ │ Vector DB │ │ File Store │ │ │
│ │ │ (元数据) │ │ (嵌入向量) │ │ (原始文件) │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
3.2 MCP 协议集成
MCP(Model Context Protocol)是 Anthropic 推出的模型上下文协议,允许外部工具与 LLM 进行标准化交互。MemPalace 通过 MCP 协议接入 Claude、Cursor 等工具。
# MemPalace MCP Server 实现
from mcp.server import Server
from mcp.types import Tool, TextContent
class MemPalaceMCPServer(Server):
def __init__(self):
super().__init__("mempalace")
self.palace = MemoryPalace.load()
@server.tool()
async def save_memory(
self,
wing: str, # 翼廊(用户/项目)
room: str, # 房间(话题)
content: str, # 记忆内容
metadata: dict = None
) -> str:
"""保存记忆到宫殿"""
drawer = self.palace.add_memory(
wing=wing,
room=room,
content=content,
metadata=metadata or {}
)
return f"记忆已保存到 {wing}/{room},抽屉ID: {drawer.id}"
@server.tool()
async def recall_memory(
self,
wing: str,
room: str = None,
query: str = None,
limit: int = 5
) -> list:
"""从宫殿检索记忆"""
if room:
# 定向检索特定房间
memories = self.palace.search_room(wing, room, query, limit)
else:
# 全宫殿搜索
memories = self.palace.search_all(wing, query, limit)
return memories
@server.tool()
async def list_rooms(self, wing: str) -> list:
"""列出翼廊中的所有房间"""
return self.palace.list_rooms(wing)
@server.tool()
async def compress_memories(
self,
wing: str,
room: str,
strategy: str = "summarize"
) -> str:
"""压缩房间内的记忆"""
result = self.palace.compress_room(wing, room, strategy)
return f"已压缩 {result['count']} 条记忆"
3.3 核心数据结构
from dataclasses import dataclass, field
from datetime import datetime
from typing import Optional, List, Dict
import uuid
import json
@dataclass
class Drawer:
"""抽屉:最小记忆单元"""
id: str = field(default_factory=lambda: str(uuid.uuid4()))
content: str = ""
embedding: Optional[List[float]] = None
metadata: Dict = field(default_factory=dict)
created_at: datetime = field(default_factory=datetime.now)
updated_at: datetime = field(default_factory=datetime.now)
access_count: int = 0
importance_score: float = 0.5
is_archived: bool = False
is_summary: bool = False
def to_dict(self):
return {
"id": self.id,
"content": self.content,
"metadata": self.metadata,
"created_at": self.created_at.isoformat(),
"access_count": self.access_count,
"importance_score": self.importance_score,
"is_archived": self.is_archived,
"is_summary": self.is_summary
}
@dataclass
class Room:
"""房间:话题/主题容器"""
id: str = field(default_factory=lambda: str(uuid.uuid4()))
name: str = ""
description: str = ""
drawers: List[Drawer] = field(default_factory=list)
created_at: datetime = field(default_factory=datetime.now)
def add_drawer(self, content: str, metadata: dict = None) -> Drawer:
drawer = Drawer(
content=content,
metadata=metadata or {}
)
self.drawers.append(drawer)
return drawer
def search(self, query_embedding: List[float], top_k: int = 5) -> List[Drawer]:
"""在房间内检索"""
# 计算相似度
similarities = []
for drawer in self.drawers:
if drawer.embedding and not drawer.is_archived:
sim = cosine_similarity(query_embedding, drawer.embedding)
similarities.append((drawer, sim))
# 排序返回 top_k
similarities.sort(key=lambda x: x[1], reverse=True)
return [d for d, s in similarities[:top_k]]
def compress(self, llm_client) -> Drawer:
"""压缩房间内容为摘要"""
all_content = "\n\n---\n\n".join([
f"[{d.created_at}] {d.content}"
for d in self.drawers if not d.is_summary
])
summary = llm_client.generate(f"""
请将以下对话记录压缩为结构化摘要:
{all_content}
输出格式:
## 关键决策
- ...
## 用户偏好
- ...
## 待解决问题
- ...
## 重要上下文
- ...
""")
# 创建摘要抽屉
summary_drawer = Drawer(
content=summary,
is_summary=True,
importance_score=0.8 # 摘要重要性较高
)
# 归档原始抽屉
for d in self.drawers:
if not d.is_summary:
d.is_archived = True
self.drawers.append(summary_drawer)
return summary_drawer
@dataclass
class Wing:
"""翼廊:用户/项目容器"""
id: str = field(default_factory=lambda: str(uuid.uuid4()))
name: str = ""
owner: str = "" # 用户ID
project: str = "" # 项目名称
rooms: Dict[str, Room] = field(default_factory=dict)
created_at: datetime = field(default_factory=datetime.now)
def get_or_create_room(self, room_name: str) -> Room:
if room_name not in self.rooms:
self.rooms[room_name] = Room(name=room_name)
return self.rooms[room_name]
def list_rooms(self) -> List[str]:
return list(self.rooms.keys())
def maintenance(self):
"""定期维护:衰减低频抽屉"""
for room in self.rooms.values():
for drawer in room.drawers:
# 时间衰减
days_since_access = (datetime.now() - drawer.updated_at).days
decay = math.exp(-0.05 * days_since_access)
drawer.importance_score *= decay
# 归档低重要性抽屉
if drawer.importance_score < 0.1:
drawer.is_archived = True
class MemoryPalace:
"""记忆宫殿:顶层容器"""
def __init__(self, storage_path: str = "./mempalace"):
self.storage_path = storage_path
self.wings: Dict[str, Wing] = {}
self.embedding_model = None # 嵌入模型
self.vector_db = None # 向量数据库
self._load()
def add_memory(
self,
wing: str,
room: str,
content: str,
metadata: dict = None
) -> Drawer:
"""添加新记忆"""
# 获取或创建翼廊
if wing not in self.wings:
self.wings[wing] = Wing(name=wing)
# 获取或创建房间
room_obj = self.wings[wing].get_or_create_room(room)
# 创建抽屉
drawer = room_obj.add_drawer(content, metadata)
# 生成嵌入向量
drawer.embedding = self.embedding_model.encode(content)
# 存入向量数据库
self.vector_db.add(
id=drawer.id,
embedding=drawer.embedding,
metadata={
"wing": wing,
"room": room,
**(metadata or {})
}
)
self._save()
return drawer
def search(
self,
wing: str,
query: str,
room: str = None,
top_k: int = 5
) -> List[dict]:
"""搜索记忆"""
query_embedding = self.embedding_model.encode(query)
filters = {"wing": wing}
if room:
filters["room"] = room
results = self.vector_db.search(
query_embedding,
top_k=top_k,
filters=filters
)
# 访问计数增加
for r in results:
drawer_id = r["id"]
self._increment_access_count(drawer_id)
return results
def _increment_access_count(self, drawer_id: str):
"""增加访问计数"""
for wing in self.wings.values():
for room in wing.rooms.values():
for drawer in room.drawers:
if drawer.id == drawer_id:
drawer.access_count += 1
drawer.importance_score = min(1.0, drawer.importance_score + 0.1)
drawer.updated_at = datetime.now()
return
def _save(self):
"""持久化到磁盘"""
data = {
"wings": {
name: {
"id": w.id,
"name": w.name,
"owner": w.owner,
"project": w.project,
"rooms": {
rname: {
"id": r.id,
"name": r.name,
"drawers": [d.to_dict() for d in r.drawers]
}
for rname, r in w.rooms.items()
}
}
for name, w in self.wings.items()
}
}
with open(f"{self.storage_path}/palace.json", "w") as f:
json.dump(data, f, indent=2)
def _load(self):
"""从磁盘加载"""
try:
with open(f"{self.storage_path}/palace.json", "r") as f:
data = json.load(f)
# 反序列化...
except FileNotFoundError:
pass # 新宫殿
3.4 嵌入向量与检索策略
MemPalace 支持多种嵌入模型和检索策略:
from sentence_transformers import SentenceTransformer
import numpy as np
from typing import List, Tuple
class EmbeddingEngine:
"""嵌入向量引擎"""
def __init__(self, model_name: str = "all-MiniLM-L6-v2"):
self.model = SentenceTransformer(model_name)
self.dimension = 384 # MiniLM 维度
def encode(self, text: str) -> List[float]:
"""编码文本为向量"""
return self.model.encode(text).tolist()
def encode_batch(self, texts: List[str]) -> List[List[float]]:
"""批量编码"""
return self.model.encode(texts).tolist()
class HybridRetriever:
"""混合检索器:向量 + 关键词"""
def __init__(self, vector_db, keyword_index):
self.vector_db = vector_db
self.keyword_index = keyword_index
def search(
self,
query: str,
query_embedding: List[float],
top_k: int = 10,
alpha: float = 0.7 # 向量检索权重
) -> List[Tuple[str, float]]:
"""混合检索"""
# 向量检索
vector_results = self.vector_db.search(query_embedding, top_k=top_k*2)
vector_scores = {r["id"]: r["score"] for r in vector_results}
# 关键词检索
keyword_results = self.keyword_index.search(query, top_k=top_k*2)
keyword_scores = {r["id"]: r["score"] for r in keyword_results}
# 融合分数
all_ids = set(vector_scores.keys()) | set(keyword_scores.keys())
final_scores = []
for id in all_ids:
v_score = vector_scores.get(id, 0)
k_score = keyword_scores.get(id, 0)
final_score = alpha * v_score + (1 - alpha) * k_score
final_scores.append((id, final_score))
# 排序
final_scores.sort(key=lambda x: x[1], reverse=True)
return final_scores[:top_k]
def cosine_similarity(a: List[float], b: List[float]) -> float:
"""余弦相似度"""
a_arr = np.array(a)
b_arr = np.array(b)
return np.dot(a_arr, b_arr) / (np.linalg.norm(a_arr) * np.linalg.norm(b_arr))
四、实战:将 MemPalace 集成到 Claude Code
4.1 安装配置
# 安装 MemPalace
pip install mempalace
# 或使用 pipx(推荐,隔离环境)
pipx install mempalace
# 初始化宫殿
mempalace init --path ~/.mempalace
# 配置 Claude Code MCP
# 编辑 ~/.claude/config.json
4.2 Claude Code MCP 配置
{
"mcpServers": {
"mempalace": {
"command": "mempalace",
"args": ["serve", "--path", "~/.mempalace"],
"env": {
"MEMPALACE_EMBEDDING_MODEL": "all-MiniLM-L6-v2",
"MEMPALACE_MAX_DRAWERS_PER_ROOM": "1000",
"MEMPALACE_COMPRESSION_THRESHOLD": "100"
}
}
}
}
4.3 使用示例
在 Claude Code 中,你现在可以直接使用 MemPalace 的记忆功能:
# 保存记忆
> /mcp mempalace save_memory \
--wing "张三/电商平台" \
--room "架构设计" \
--content "决定采用微服务架构,使用 Spring Cloud 作为服务网格,Nacos 作为注册中心,Gateway 作为 API 网关。主要考虑是团队对 Java 生态熟悉,且有成熟的运维经验。"
# 检索记忆
> /mcp mempalace recall_memory \
--wing "张三/电商平台" \
--room "架构设计" \
--query "为什么选择微服务架构?"
# 列出房间
> /mcp mempalace list_rooms --wing "张三/电商平台"
4.4 自动记忆保存
更强大的用法是让 Claude Code 自动保存重要决策:
# 在 Claude Code 的 skills 中添加自动记忆逻辑
def after_code_generation(code: str, context: dict):
"""代码生成后自动保存决策记忆"""
# 提取关键决策
decisions = extract_decisions(code, context)
for decision in decisions:
mempalace.save_memory(
wing=f"{context['user']}/{context['project']}",
room=decision['topic'],
content=decision['content'],
metadata={
"timestamp": datetime.now().isoformat(),
"file": context['file'],
"commit": context.get('commit_hash')
}
)
def extract_decisions(code: str, context: dict) -> list:
"""从代码和上下文中提取关键决策"""
decisions = []
# 分析代码注释中的 TODO、FIXME、NOTE
# 分析 git commit message
# 分析对话历史中的关键决策点
# 示例:提取架构决策
if "微服务" in code or "microservice" in code.lower():
decisions.append({
"topic": "架构设计",
"content": f"在 {context['file']} 中采用了微服务相关代码"
})
return decisions
五、MemPalace vs 其他记忆方案对比
5.1 主流方案对比表
| 特性 | MemPalace | EverOS | MemOS | Mem0 | Letta |
|---|---|---|---|---|---|
| 开发者 | Mira & Ben Sigman | EverMind (盛大孵化) | MemTensor | Mem0 AI | Letta AI |
| 架构模式 | 记忆宫殿(Wing/Room/Drawer) | 记忆层(Memory Layer) | 记忆操作系统 | 简单向量存储 | Agent 原生记忆 |
| 本地优先 | ✅ 完全本地 | ❌ 云端为主 | ✅ 支持本地 | ❌ 云端服务 | ✅ 本地 |
| MCP 协议 | ✅ 原生支持 | ⚠️ 需适配 | ✅ 支持 | ✅ 支持 | ✅ 支持 |
| 遗忘机制 | ✅ 重要性衰减 | ✅ 自动归档 | ✅ 分级存储 | ❌ 无 | ✅ 核心记忆 |
| 多模态 | ❌ 仅文本 | ✅ 图像/音频 | ✅ 多模态 | ✅ 多模态 | ⚠️ 有限 |
| 开源协议 | MIT | Apache 2.0 | Apache 2.0 | MIT | Apache 2.0 |
| Star 数 | 37.9K | 8.2K | 5.6K | 24.3K | 18.7K |
5.2 架构哲学对比
MemPalace:空间隐喻驱动
# MemPalace: 用空间隐喻组织记忆
palace = MemoryPalace()
wing = palace.get_wing("用户A/项目B")
room = wing.get_room("架构设计")
drawer = room.get_drawer("决策记录#123")
优点:符合人类认知模式,层次清晰
缺点:需要预先定义层次结构
EverOS:记忆层抽象
# EverOS: 记忆作为独立层
from everos import MemoryLayer
memory = MemoryLayer(api_key="...")
memory.remember(
agent_id="agent_001",
content="用户偏好简洁代码",
memory_type="preference"
)
优点:Agent 无需关心存储细节
缺点:层次感弱,检索可能发散
MemOS:操作系统级别
# MemOS: 记忆作为系统资源
from memos import MemoryOS
mem_os = MemoryOS()
mem_os.allocate(
agent_id="agent_001",
memory_quota="100MB",
retention_policy="30d"
)
优点:企业级管理,支持资源配额
缺点:架构复杂,个人使用过重
5.3 选择建议
| 场景 | 推荐方案 |
|---|---|
| 个人开发者,本地优先 | MemPalace |
| 企业多 Agent 协作 | EverOS 或 MemOS |
| 快速集成,不想关心架构 | Mem0 |
| Agent 原生记忆研究 | Letta |
六、性能优化与最佳实践
6.1 嵌入向量优化
# 使用量化减少存储
import numpy as np
def quantize_embedding(embedding: List[float], bits: int = 8) -> bytes:
"""将浮点向量量化为定点"""
arr = np.array(embedding, dtype=np.float32)
# 归一化到 [0, 2^bits-1]
arr_min, arr_max = arr.min(), arr.max()
normalized = (arr - arr_min) / (arr_max - arr_min) * (2**bits - 1)
# 转换为 uint8
quantized = normalized.astype(np.uint8)
return quantized.tobytes()
def dequantize_embedding(data: bytes, bits: int = 8,
original_min: float, original_max: float) -> List[float]:
"""反量化"""
quantized = np.frombuffer(data, dtype=np.uint8)
normalized = quantized / (2**bits - 1)
return (normalized * (original_max - original_min) + original_min).tolist()
# 存储大小对比
# 原始 float32: 384 维 * 4 bytes = 1536 bytes
# 量化 uint8: 384 维 * 1 byte = 384 bytes
# 节省 75% 存储
6.2 检索性能优化
# 使用 HNSW 索引加速检索
import hnswlib
class FastVectorIndex:
def __init__(self, dimension: int = 384, max_elements: int = 100000):
self.index = hnswlib.Index(space='cosine', dim=dimension)
self.index.init_index(max_elements=max_elements, ef_construction=200, M=16)
self.id_map = {} # drawer_id -> index_id
self.reverse_map = {} # index_id -> drawer_id
def add(self, drawer_id: str, embedding: List[float]):
idx = len(self.id_map)
self.index.add_items([embedding], [idx])
self.id_map[drawer_id] = idx
self.reverse_map[idx] = drawer_id
def search(self, query_embedding: List[float], top_k: int = 10) -> List[str]:
labels, distances = self.index.knn_query(query_embedding, k=top_k)
return [self.reverse_map[l] for l in labels[0]]
# HNSW 检索性能
# 100 万向量,检索延迟 < 1ms
# 而暴力检索约 100ms
6.3 内存管理
class MemoryManager:
"""内存管理:LRU + 重要性"""
def __init__(self, max_memory_mb: int = 500):
self.max_memory = max_memory_mb * 1024 * 1024
self.current_memory = 0
self.cache = {} # drawer_id -> drawer object
self.lru_queue = []
def get(self, drawer_id: str) -> Optional[Drawer]:
if drawer_id in self.cache:
# LRU 更新
self.lru_queue.remove(drawer_id)
self.lru_queue.append(drawer_id)
return self.cache[drawer_id]
return None
def put(self, drawer: Drawer):
# 计算内存占用
drawer_size = len(json.dumps(drawer.to_dict()).encode())
# 检查是否超限
while self.current_memory + drawer_size > self.max_memory:
# 淘汰 LRU + 低重要性
self._evict_one()
# 加入缓存
self.cache[drawer.id] = drawer
self.lru_queue.append(drawer.id)
self.current_memory += drawer_size
def _evict_one(self):
if not self.lru_queue:
return
# 找到重要性最低的
min_importance = float('inf')
evict_id = None
for did in self.lru_queue[:100]: # 只检查前 100 个
if self.cache[did].importance_score < min_importance:
min_importance = self.cache[did].importance_score
evict_id = did
if evict_id:
drawer = self.cache.pop(evict_id)
self.lru_queue.remove(evict_id)
self.current_memory -= len(json.dumps(drawer.to_dict()).encode())
6.4 最佳实践清单
定期维护
- 每周运行一次
mempalace maintenance - 归档低重要性抽屉
- 压缩高频访问的房间
- 每周运行一次
合理分层
- Wing 层:用户 + 项目(一级隔离)
- Room 层:话题/领域(二级分类)
- 避免过度细分(Room 数量 < 50)
嵌入模型选择
- 英文为主:
all-MiniLM-L6-v2(384 维,快速) - 中文为主:
shibing624/text2vec-base-chinese(768 维) - 多语言:
sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2
- 英文为主:
压缩策略
- 抽屉数 > 100:自动摘要
- 抽屉数 > 500:分层压缩
- 摘要保留原始抽屉的 ID 引用
七、未来展望:AI 记忆的终极形态
7.1 记忆即人格
当 AI 拥有持久记忆,它就拥有了"人格"的雏形。记忆不仅是信息的存储,更是经验的积累、偏好的形成、习惯的养成。
# 未来愿景:记忆塑造人格
class AgentPersonality:
def __init__(self, palace: MemoryPalace):
self.palace = palace
def get_communication_style(self, user_id: str) -> dict:
"""基于历史记忆推断沟通风格"""
preferences = self.palace.search(
wing=user_id,
query="沟通偏好",
room="用户偏好"
)
# 从记忆中学习:用户喜欢简洁还是详细
# 用户喜欢正式还是随意
# 用户偏好中文还是英文
return {
"verbosity": "concise" if "简洁" in preferences else "detailed",
"tone": "casual" if "随意" in preferences else "formal",
"language": "zh-CN"
}
def avoid_past_mistakes(self, user_id: str, task: str) -> List[str]:
"""避免重复过去的错误"""
mistakes = self.palace.search(
wing=user_id,
query=f"错误 {task}",
room="错误记录"
)
return [m["content"] for m in mistakes]
7.2 多 Agent 共享记忆
多个 Agent 协作时,共享记忆是关键:
# 团队记忆共享
class SharedMemory:
def __init__(self, palace: MemoryPalace):
self.palace = palace
self.shared_wings = {} # 共享的翼廊
def share_wing(self, wing_id: str, agent_ids: List[str]):
"""将翼廊共享给多个 Agent"""
self.shared_wings[wing_id] = agent_ids
def agent_can_access(self, agent_id: str, wing_id: str) -> bool:
"""检查 Agent 是否有权访问"""
return agent_id in self.shared_wings.get(wing_id, [])
def collaborative_recall(self, wing_id: str, query: str) -> dict:
"""协作检索:整合多个 Agent 的记忆"""
# 检索所有 Agent 在该翼廊的记忆
# 按重要性排序
# 去重合并
pass
7.3 记忆的可解释性
AI 记忆需要可审计、可解释:
class ExplainableMemory:
def explain_recall(self, query: str, results: List[dict]) -> str:
"""解释为什么检索到这些记忆"""
explanations = []
for r in results:
# 为什么这条记忆相关?
# 什么时候存储的?
# 之前的上下文是什么?
explanations.append(f"""
记忆 '{r['id']}' 相关性: {r['score']:.2f}
- 存储时间: {r['created_at']}
- 所属房间: {r['room']}
- 访问次数: {r['access_count']}
- 重要性: {r['importance_score']}
""")
return "\n".join(explanations)
八、总结
MemPalace 不仅仅是一个记忆存储工具,它代表了一种全新的 AI 记忆范式:
- 空间隐喻:用 2000 年前的记忆宫殿智慧,解决现代 AI 的记忆难题
- 层次结构:Wing/Room/Drawer 三层架构,让记忆有组织、有层次
- 自然遗忘:模拟人类记忆衰减,避免"信息过载"
- 本地优先:隐私至上,数据完全由用户掌控
- MCP 原生:与 Claude Code、Cursor 等工具无缝集成
在 AI Agent 爆发的 2026 年,记忆已成为 Agent 的第四大核心组件(仅次于推理、规划、工具使用)。MemPalace 的出现,为所有 Agent 提供了一套开箱即用的记忆解决方案。
无论你是个人开发者,想要让你的 AI 助手"记住你";还是企业团队,需要为多个 Agent 构建共享记忆;MemPalace 都值得一试。
正如米拉·乔沃维奇所说:"记忆是身份的基础。没有记忆的 AI,就像一个永远活在当下的人。而有了记忆宫殿,AI 终于可以真正地'成长'。"
附录:快速开始
# 1. 安装
pipx install mempalace
# 2. 初始化
mempalace init --path ~/.mempalace
# 3. 启动 MCP 服务
mempalace serve
# 4. 在 Claude Code 中配置
# 编辑 ~/.claude/config.json,添加 MCP server
# 5. 开始使用
# 在 Claude Code 中直接使用记忆功能
GitHub 仓库:https://github.com/milla-jovovich/mempalace
官方文档:https://mempalace.dev/docs
社区讨论:https://github.com/milla-jovovich/mempalace/discussions