Agent系列(二)-记忆系统的设计

目录

一、为什么需要记忆系统

二、记忆系统的分层

[2.1 第一层:工作记忆(Working Memory)](#2.1 第一层:工作记忆(Working Memory))

[2.2 第二层:短期记忆(Short-term Memory)](#2.2 第二层:短期记忆(Short-term Memory))

[2.3 第三层:长期记忆(Long-term Memory)](#2.3 第三层:长期记忆(Long-term Memory))

[2.4 第四层:永久记忆(Persistent Memory / Knowledge)](#2.4 第四层:永久记忆(Persistent Memory / Knowledge))

三、记忆分层对比及协同机制

[3.1 四层记忆分层对比](#3.1 四层记忆分层对比)

[3.2 四层记忆的协同机制](#3.2 四层记忆的协同机制)


一、为什么需要记忆系统

  • 持续性:期望实现跨会话保持上下文;
  • 个性化:记住用户偏好和历史;
  • 自我进化:积累经验,提升能力;
  • 效率:减少获取重复信息;

二、记忆系统的分层

Agent的记忆系统分为四层------工作记忆(即时推理)、短期记忆(当前会话)、长期记忆(跨会话积累)、永久记忆(结构化知识)。各层职责明确,协同工作,共同支撑Agent的持续对话和个性化服务能力。

2.1 第一层:工作记忆(Working Memory)

  • 定义: Agent当前推理过程中的即时工作区;
  • 生命周期:当前推理步骤(毫秒级~秒级);
  • 存储位置:进程内存;
  • 容量:极小(几个关键变量)
  • 存储内容:1)当前任务的中间状态;2)思考链(Thought Chain);3)工具调用的输入输出;4)临时计算结果;5)决策过程中的关键判断;
python 复制代码
class WorkingMemory:
    """工作记忆:Agent推理时的即时工作台"""
    
    def __init__(self):
        self.variables = {}      # 变量存储
        self.thought_chain = []  # 思考链
        self.step_context = {}   # 当前步骤上下文
    
    def set_var(self, key, value):
        """设置变量"""
        self.variables[key] = value
    
    def get_var(self, key, default=None):
        """获取变量"""
        return self.variables.get(key, default)
    
    def think(self, thought):
        """记录思考步骤"""
        self.thought_chain.append({
            "thought": thought,
            "step": len(self.thought_chain) + 1
        })
    
    def get_thought_chain_text(self):
        """获取思考链文本"""
        return "\n".join([
            f"[思考{i}] {t['thought']}"
            for i, t in enumerate(self.thought_chain, 1)
        ])
    
    def set_step_context(self, step_name, context):
        """设置当前步骤的上下文"""
        self.step_context[step_name] = context
    
    def get_step_context(self, step_name):
        """获取某步骤的上下文"""
        return self.step_context.get(step_name)
    
    def clear(self):
        """清空工作记忆(新任务开始时)"""
        self.variables = {}
        self.thought_chain = []
        self.step_context = {}

2.2 第二层:短期记忆(Short-term Memory)

  • 定义:当前会话周期内的对话上下文;
  • 生命周期:当前会话(分钟级~小时级);
  • 存储位置:内存 / Redis会话存储;
  • 容量:有限(通常10-20轮对话)
  • 存储内容:1)当前会话的所有对话轮次;2)当前任务的中间结果;3)未完成的后续事项;4)当前会话中建立的临时结论;
  • 过期处理:1)会话结束自动清除;2)重要内容摘要后转入长期记忆;3)超容量时删除最旧的轮次
python 复制代码
class ShortTermMemory:
    """短期记忆:基于轮次的上下文管理"""
    
    def __init__(self, max_turns=10):
        self.max_turns = max_turns
        self.turns = []  # 对话轮次列表
    
    def add_turn(self, user_input, agent_output, metadata=None):
        """添加一轮对话"""
        turn = {
            "user": user_input,
            "agent": agent_output,
            "metadata": metadata or {},
            "timestamp": datetime.now().isoformat()
        }
        self.turns.append(turn)
        
        # 超容量时删除最旧的轮次
        if len(self.turns) > self.max_turns:
            self.turns.pop(0)
    
    def get_full_context(self):
        """获取完整上下文"""
        return "\n".join([
            f"用户: {t['user']}\n助手: {t['agent']}"
            for t in self.turns
        ])
    
    def get_recent_turns(self, n=3):
        """获取最近N轮对话"""
        return self.turns[-n:]
    
    def get_turn_count(self):
        """获取对话轮数"""
        return len(self.turns)
    
    def summarize_to_long_term(self, llm):
        """将会话摘要后存入长期记忆"""
        if len(self.turns) == 0:
            return ""
        
        conversation = self.get_full_context()
        summary = llm.invoke(f"""
请对以下对话进行简短摘要(100字以内):

{conversation}

摘要:
""")
        return summary
    
    def clear(self):
        """清空短期记忆"""
        self.turns = []

2.3 第三层:长期记忆(Long-term Memory)

  • 定义: 跨会话积累的重要信息和经验
  • 生命周期:会话之间持续(天级~月级)
  • 存储位置:向量数据库(Pinecone/Milvus/Weaviate)
  • 容量:大(可存储多年数据)
  • 存储内容:1)重要会话的摘要;2)用户偏好和习惯;3)达成的重要结论和决策;4)解决方案和经验积累;5)问题和应对的处理方式;
  • 检索方式:1)向量相似度检索(语义检索);2)关键词检索(BM25);3)时间衰减(越近的记忆权重越高)
python 复制代码
class LongTermMemory:
    """长期记忆:基于向量数据库的跨会话记忆"""
    
    def __init__(self, vector_store, user_id):
        self.vector_store = vector_store
        self.user_id = user_id
    
    def store(self, content, memory_type="general", importance=1.0):
        """
        存储记忆到长期记忆
        
        Args:
            content: 记忆内容文本
            memory_type: 记忆类型(preference/decision/experience等)
            importance: 重要程度(0-1),用于后续清理时参考
        """
        vector = self.embed(content)
        
        self.vector_store.insert({
            "id": f"{self.user_id}_{uuid.uuid4()}",
            "values": vector,
            "text": content,
            "metadata": {
                "user_id": self.user_id,
                "type": memory_type,
                "importance": importance,
                "created_at": datetime.now().isoformat()
            }
        })
    
    def retrieve(self, query, top_k=5, memory_types=None):
        """
        从长期记忆中检索相关内容
        
        Args:
            query: 查询文本
            top_k: 返回数量
            memory_types: 只检索特定类型的记忆
        """
        query_vector = self.embed(query)
        
        # 构建过滤条件
        filter_cond = {"user_id": self.user_id}
        if memory_types:
            filter_cond["type"] = {"$in": memory_types}
        
        results = self.vector_store.query(
            vector=query_vector,
            top_k=top_k,
            filter=filter_cond,
            include_metadata=True
        )
        
        # 应用时间衰减
        return self.apply_time_decay(results)
    
    def apply_time_decay(self, results):
        """应用时间衰减:越新的记忆权重越高"""
        now = datetime.now()
        scored_results = []
        
        for r in results:
            created_at = datetime.fromisoformat(r["metadata"]["created_at"])
            age_days = (now - created_at).days
            
            # 指数衰减,半衰期30天
            decay = math.exp(-age_days / 30)
            final_score = r["score"] * decay
            
            scored_results.append({
                "content": r["text"],
                "original_score": r["score"],
                "decay_score": decay,
                "final_score": final_score,
                "metadata": r["metadata"]
            })
        
        # 按最终分数排序
        scored_results.sort(key=lambda x: x["final_score"], reverse=True)
        return scored_results
    
    def get_user_preferences(self):
        """获取用户偏好(专门检索偏好类记忆)"""
        return self.retrieve("用户偏好", memory_types=["preference"], top_k=10)
    
    def get_relevant_experiences(self, problem):
        """获取相关经验(用于解决新问题)"""
        return self.retrieve(problem, memory_types=["experience"], top_k=5)

2.4 第四层:永久记忆(Persistent Memory / Knowledge)

  • 定义: 持久化的结构化知识,包括用户画像、系统配置、专业知识;
  • 生命周期:永久(直到显式删除);
  • 存储位置:结构化数据库(PostgreSQL/MongoDB);
  • 容量:理论无限(需有效管理);
  • 存储内容:1)用户画像(用户基本信息、偏好设置、会员等级、标签、账户状态);2)领域知识(产品知识库、业务流程规范、常见问题解答、专业领域知识);3)Agent经验(成功的解决方案模式、失败的教训;优化记录)
python 复制代码
class PersistentMemory:
    """永久记忆:结构化的持久化存储"""
    
    def __init__(self, db):
        self.db = db  # 数据库连接
    
    # ============ 用户画像 ============
    
    def get_user_profile(self, user_id):
        """获取用户画像"""
        user = self.db.users.find_one({"user_id": user_id})
        if user:
            return {
                "basic_info": user.get("basic_info", {}),
                "preferences": user.get("preferences", {}),
                "tags": user.get("tags", []),
                "membership_level": user.get("membership_level", "普通"),
                "created_at": user.get("created_at"),
                "updated_at": user.get("updated_at")
            }
        return self._create_empty_profile(user_id)
    
    def update_user_profile(self, user_id, updates):
        """更新用户画像"""
        self.db.users.update_one(
            {"user_id": user_id},
            {
                "$set": {
                    **updates,
                    "updated_at": datetime.now().isoformat()
                }
            },
            upsert=True
        )
    
    def add_user_tag(self, user_id, tag):
        """添加用户标签"""
        self.db.users.update_one(
            {"user_id": user_id},
            {
                "$addToSet": {"tags": tag},
                "$set": {"updated_at": datetime.now().isoformat()}
            }
        )
    
    # ============ 知识库 ============
    
    def save_knowledge(self, category, question, answer, metadata=None):
        """保存知识条目"""
        self.db.knowledge.insert_one({
            "category": category,
            "question": question,
            "answer": answer,
            "metadata": metadata or {},
            "created_at": datetime.now().isoformat(),
            "usage_count": 0,
            "last_used": None
        })
    
    def search_knowledge(self, query, category=None, top_k=5):
        """搜索知识库"""
        filter_cond = {}
        if category:
            filter_cond["category"] = category
        
        # 简单实现:基于关键词匹配
        results = self.db.knowledge.find({
            "$or": [
                {"question": {"$regex": query}},
                {"answer": {"$regex": query}}
            ],
            **filter_cond
        }).limit(top_k)
        
        return list(results)
    
    # ============ Agent经验 ============
    
    def save_agent_experience(self, agent_id, experience):
        """保存Agent经验"""
        self.db.agent_experiences.insert_one({
            "agent_id": agent_id,
            "experience": experience,
            "created_at": datetime.now().isoformat()
        })
    
    def get_agent_experiences(self, agent_id, limit=20):
        """获取Agent经验"""
        experiences = self.db.agent_experiences.find(
            {"agent_id": agent_id}
        ).sort("created_at", -1).limit(limit)
        
        return list(experiences)

三、记忆分层对比及协同机制

3.1 四层记忆分层对比

维度 工作记忆 短期记忆 长期记忆 永久记忆
生命周期 单次推理 当前会话 跨会话 永久
存储位置 进程内存 内存/Redis 向量数据库 结构化DB
容量 极小 小(10-20轮) 无限
访问频率 最高
检索方式 直接访问 顺序遍历 向量检索 条件查询
过期策略 随任务清除 会话结束/摘要 时间衰减 手动删除
类比 工作台 短期记忆 长期记忆 知识库
数据特征 即时状态 对话记录 经验积累 结构化画像

3.2 四层记忆的协同机制

  • 四层记忆协同目标:让Agent在每次对话时都能获取"完整的上下文";
  • 协同原则
    • 热数据优先(当前任务状态 > 会话上下文 > 历史经验);
    • 按需下沉(重要信息逐层沉淀,不重要信息及时清理);
    • 容量平衡(各层有容量限制,通过压缩/清理维持平衡);
    • 统一输出(最终整合为LLM可直接使用的prompt);
  • 四层记忆写入流程
    • 每一轮推理后,立即写入Working Memory;
    • 轮次结束时写入(对话记录),立即写入Short-term Memory;
    • 会话结束/重要交互时写入Long-term Memory;
    • 识别到明确偏好/决策时写入Persistent Memory;
  • 四层记忆读取流程:每一轮对话,依次获取工作记忆、短期记忆、中期记忆、长期记忆,最终构建统一prompt,给到LLM

最后,我们以一个「订机票场景记忆协同」的案例,来说明一下四层记忆的协同机制:

python 复制代码
┌─────────────────────────────────────────────────────────────┐
│                    订机票场景记忆协同                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  【第一轮对话】                                              │
│  ┌──────────────────────────────────────────────────────┐  │
│  │  用户: "我想订明天去北京的机票"                       │  │
│  └──────────────────────────────────────────────────────┘  │
│                        ↓                                    │
│  写入流程:                                                  │
│  • Working: task=订机票, destination=北京, date=明天      │
│  • Short: [用户: "我想订明天去北京的机票"]                  │
│  • Long: 不写入(非重要交互)                               │
│  • Persistent: 不写入(非偏好/决策)                       │
│                        ↓                                    │
│  读取流程:                                                  │
│  • Working: 提供当前任务状态                                │
│  • Short: 空(第一次对话)                                 │
│  • Long: 检索相关历史(可能找到之前的订票经验)           │
│  • Persistent: 获取用户画像                                │
│                        ↓                                    │
│  Context整合:                                               │
│  "用户VIP会员,之前偏好国航,不坐红眼航班,常用出发地..."  │
│                        ↓                                    │
│  LLM回复 + 写入Short                                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                                                             │
│  【第二轮对话】                                              │
│  ┌──────────────────────────────────────────────────────┐  │
│  │  用户: "对,帮我看看国航的"                           │  │
│  └──────────────────────────────────────────────────────┘  │
│                        ↓                                    │
│  写入流程:                                                  │
│  • Working: airline=国航(更新状态)                       │
│  • Short: 添加第二轮对话                                   │
│  • Long: 不写入                                            │
│  • Persistent: 不写入                                     │
│                        ↓                                    │
│  读取流程:                                                  │
│  • Working: 提供当前任务状态(订机票、国航)               │
│  • Short: 提供第一轮对话上下文                            │
│  • Long: 检索国航相关的历史经验                           │
│  • Persistent: 获取用户画像中的偏好                       │
│                        ↓                                    │
│  Context整合:                                              │
│  "当前:订机票,国航,明天北京                            │
│   会话:用户想订明天去北京的机票                           │
│   偏好:用户是VIP,偏好国航,不坐红眼航班"                 │
│                        ↓                                    │
│  LLM回复 + 写入Short                                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                                                             │
│  【第三轮对话:用户确认偏好】                                │
│  ┌──────────────────────────────────────────────────────┐  │
│  │  用户: "我喜欢靠窗的位置,记得存一下"                 │  │
│  └──────────────────────────────────────────────────────┘  │
│                        ↓                                    │
│  写入流程:                                                  │
│  • Working: seat_preference=靠窗                           │
│  • Short: 添加第三轮对话                                   │
│  • Long: 存储偏好经验("喜欢靠窗位置")                    │
│  • Persistent: ★ 写入用户画像(重要偏好!)               │
│  │        更新 persistent storage:                       │
│  │        preferences.seat = "靠窗"                      │
│                        ↓                                    │
│  读取流程:                                                  │
│  • Working: 当前状态                                      │
│  • Short: 完整会话                                        │
│  • Long: 检索相关偏好历史                                 │
│  • Persistent: ★ 获取完整用户画像                        │
│  │        包括刚才保存的"靠窗"偏好                       │
│                        ↓                                    │
│  Context整合:                                              │
│  "用户VIP,偏好国航,不坐红眼航班,喜欢靠窗位置,          │
│   常用出发地...(完整画像)"                               │
│                        ↓                                    │
│  LLM回复 + 写入各层记忆                                    │
│                                                             │
└─────────────────────────────────────────────────────────────┘
相关推荐
方也_arkling1 小时前
【Java-Day02】语法篇:变量/数据类型/标识符/运算符/类型转换
java·开发语言
RSTJ_16251 小时前
PYTHON+AI LLM DAY SIXTY-ONE
开发语言·python
zfoo-framework1 小时前
理解kotlin limitedParallelism(1)与Actor模型
android·开发语言·kotlin
.千余1 小时前
【C++】C++类与对象3:const成员函数与取地址运算符重载,权限管理的艺术
开发语言·c++
影寂ldy1 小时前
C# 类和对象
开发语言·c#
丷丩1 小时前
MapLibre GL JS第25课:添加栅格瓦片源
开发语言·javascript·gis·mapbox·maplibre gl js
TickDB1 小时前
智谱GLM-4 接金融数据:工具描述多写三个字,模型少犯一类错
人工智能·python·websocket·行情数据 api·行情 api
测试_AI_一辰1 小时前
AI模型评测不只看准确率-CV与Agent评测指标体系梳理
人工智能·机器学习·计算机视觉
用户0332126663671 小时前
使用 Python 在 Excel 中查找并高亮显示
python