编程 MemPalace 深度实战:37K Star 的 AI 记忆宫殿如何用 2000 年古老智慧重新定义 Agent 持久化记忆

2026-05-05 13:34:51 +0800 CST views 4

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)是古希腊演说家发明的一种记忆术。核心思想是:

  1. 空间编码:将要记住的内容"放置"在熟悉的建筑空间里
  2. 位置定位:通过回忆空间布局,提取对应的记忆
  3. 故事关联:用夸张、生动的想象连接空间和内容

例如,要记住一篇演讲稿,你可以想象自己的家:

  • 门口放"开场白"
  • 客厅沙发放"第一个论点"
  • 厨房冰箱放"第二个论点"
  • 卧室床头放"结论"

演讲时,在脑海中"走过"这个家,每个位置触发对应内容。

这套技术之所以有效,是因为人类大脑对"空间"的处理能力远超"抽象信息"。海马体——负责记忆的关键脑区——同时也是空间导航中枢。空间与记忆在神经层面深度绑定。

2.2 MemPalace 的架构映射

MemPalace 创造性地将这套古老智慧转译为 AI 记忆架构:

┌─────────────────────────────────────────────────────────────┐
│                      记忆宫殿 (Palace)                        │
│  ┌─────────────────────────────────────────────────────┐    │
│  │                     翼廊 (Wing)                       │    │
│  │   人: "张三"                                          │    │
│  │   项目: "电商平台"                                     │    │
│  │                                                       │    │
│  │  ┌─────────────────┐  ┌─────────────────┐            │    │
│  │  │   房间 (Room)    │  │   房间 (Room)    │            │    │
│  │  │  话题: "架构设计" │  │  话题: "性能优化" │            │    │
│  │  │                 │  │                 │            │    │
│  │  │ ┌─────────────┐ │  │ ┌─────────────┐ │            │    │
│  │  │ │ 抽屉(Drawer)│ │  │ │ 抽屉(Drawer)│ │            │    │
│  │  │ │ "为什么选择  │ │  │ │ "Redis 缓存 │ │            │    │
│  │  │ │  微服务架构" │ │  │ │  策略优化"  │ │            │    │
│  │  │ └─────────────┘ │  │ └─────────────┘ │            │    │
│  │  │ ┌─────────────┐ │  │ ┌─────────────┐ │            │    │
│  │  │ │ 抽屉(Drawer)│ │  │ │ 抽屉(Drawer)│ │            │    │
│  │  │ │ "API 网关   │ │  │ │ "数据库连接 │ │            │    │
│  │  │ │  选型决策"  │ │  │ │  池配置"    │ │            │    │
│  │  │ └─────────────┘ │  │ └─────────────┘ │            │    │
│  │  └─────────────────┘  └─────────────────┘            │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘

三层结构解析

  1. 翼廊(Wing):最高层级,对应"人"或"项目"

    • 每个用户有独立的翼廊
    • 每个项目也可以有独立翼廊
    • 实现多租户隔离
  2. 房间(Room):中间层级,对应"话题"或"主题"

    • 同一项目下不同技术领域
    • 同一人的不同关注点
    • 提供语义分区
  3. 抽屉(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 主流方案对比表

特性MemPalaceEverOSMemOSMem0Letta
开发者Mira & Ben SigmanEverMind (盛大孵化)MemTensorMem0 AILetta AI
架构模式记忆宫殿(Wing/Room/Drawer)记忆层(Memory Layer)记忆操作系统简单向量存储Agent 原生记忆
本地优先✅ 完全本地❌ 云端为主✅ 支持本地❌ 云端服务✅ 本地
MCP 协议✅ 原生支持⚠️ 需适配✅ 支持✅ 支持✅ 支持
遗忘机制✅ 重要性衰减✅ 自动归档✅ 分级存储❌ 无✅ 核心记忆
多模态❌ 仅文本✅ 图像/音频✅ 多模态✅ 多模态⚠️ 有限
开源协议MITApache 2.0Apache 2.0MITApache 2.0
Star 数37.9K8.2K5.6K24.3K18.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 最佳实践清单

  1. 定期维护

    • 每周运行一次 mempalace maintenance
    • 归档低重要性抽屉
    • 压缩高频访问的房间
  2. 合理分层

    • Wing 层:用户 + 项目(一级隔离)
    • Room 层:话题/领域(二级分类)
    • 避免过度细分(Room 数量 < 50)
  3. 嵌入模型选择

    • 英文为主:all-MiniLM-L6-v2(384 维,快速)
    • 中文为主:shibing624/text2vec-base-chinese(768 维)
    • 多语言:sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2
  4. 压缩策略

    • 抽屉数 > 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 记忆范式:

  1. 空间隐喻:用 2000 年前的记忆宫殿智慧,解决现代 AI 的记忆难题
  2. 层次结构:Wing/Room/Drawer 三层架构,让记忆有组织、有层次
  3. 自然遗忘:模拟人类记忆衰减,避免"信息过载"
  4. 本地优先:隐私至上,数据完全由用户掌控
  5. 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

复制全文 生成海报 AI Agent 记忆系统 MemPalace MCP 开源项目

推荐文章

Elasticsearch 的索引操作
2024-11-19 03:41:41 +0800 CST
一个数字时钟的HTML
2024-11-19 07:46:53 +0800 CST
全栈利器 H3 框架来了!
2025-07-07 17:48:01 +0800 CST
PHP 允许跨域的终极解决办法
2024-11-19 08:12:52 +0800 CST
服务器购买推荐
2024-11-18 23:48:02 +0800 CST
MySQL用命令行复制表的方法
2024-11-17 05:03:46 +0800 CST
程序员茄子在线接单