AI Agent 记忆机制深度解析:从短期记忆到长期记忆的工程实践

0 阅读10分钟

引言

在构建 AI Agent 的过程中,我们常常会遇到一个核心问题:如何让 Agent 记住用户、记住对话、记住上下文?

记忆机制是 AI Agent 从"一次性聊天工具"进化为"智能助手"的关键。一个具备良好记忆能力的 Agent,能够理解用户的长期偏好、维护对话的连贯性、甚至在多次会话之间建立知识关联。

本文将深入探讨 AI Agent 记忆机制的设计原理与工程实践,从短期记忆到长期记忆,从理论到代码,帮助你构建更智能的 Agent 系统。


一、为什么记忆对 AI Agent 如此重要?

1.1 没有记忆的 Agent 面临的问题

想象一下这样的场景:

用户:"帮我预订明天去上海的机票。" Agent:"好的,已为您查询到明天去上海的航班。" 用户:"要上午的。" Agent:"请问您要去哪个城市?"

这就是典型的上下文丢失问题。没有记忆机制的 Agent,每次交互都是独立的,无法理解指代关系,也无法维护对话状态。

1.2 记忆带来的价值

具备记忆能力的 Agent 可以实现:

  • 个性化服务:记住用户的偏好、习惯、历史行为
  • 连贯对话:理解上下文,处理指代消解
  • 知识积累:在多次交互中持续学习和改进
  • 情感连接:记住与用户的互动历史,建立信任关系

二、AI Agent 记忆的分类

根据记忆的持续时间、存储方式和用途,我们可以将 AI Agent 的记忆分为以下几类:

┌─────────────────────────────────────────────────────────────┐
│                      AI Agent 记忆架构                        │
├──────────────┬──────────────┬──────────────┬────────────────┤
│   工作记忆    │   短期记忆    │   长期记忆    │    外部记忆     │
│  (Working)   │  (Short-term)│  (Long-term) │  (External)    │
├──────────────┼──────────────┼──────────────┼────────────────┤
│ 当前对话上下文 │ 近期对话历史  │  用户画像    │   知识库       │
│ 临时计算结果  │ 会话状态     │  历史摘要    │   文档存储     │
│ 实时感知数据  │ 多轮意图     │  学习到的模式 │   向量数据库    │
└──────────────┴──────────────┴──────────────┴────────────────┘

2.1 工作记忆(Working Memory)

工作记忆是 Agent 的"大脑缓存",用于存储当前正在处理的信息:

  • 当前对话上下文:正在进行的对话内容
  • 临时计算结果:工具调用的中间结果
  • 实时感知数据:传感器输入、用户行为等

特点:容量有限、访问速度快、生命周期短

2.2 短期记忆(Short-term Memory)

短期记忆存储近期的事件和对话历史:

  • 对话历史:最近 N 轮对话记录
  • 会话状态:当前任务的进度和状态
  • 多轮意图:用户在当前会话中的核心需求

特点:容量中等、按时间衰减、支持上下文理解

2.3 长期记忆(Long-term Memory)

长期记忆存储持久化的用户信息和知识:

  • 用户画像:用户的基本信息、偏好设置
  • 历史摘要:过去对话的压缩摘要
  • 学习到的模式:从交互中提炼的规律

特点:容量大、持久化存储、需要检索机制

2.4 外部记忆(External Memory)

外部记忆是 Agent 可以访问的外部知识源:

  • 知识库:结构化或半结构化的领域知识
  • 文档存储:产品文档、帮助手册等
  • 向量数据库:语义检索的知识库

三、短期记忆的实现:上下文窗口管理

3.1 基于 Token 的滑动窗口

最简单的短期记忆实现方式是维护一个对话历史的滑动窗口:

class ShortTermMemory:
    def __init__(self, max_tokens=4000):
        self.max_tokens = max_tokens
        self.messages = []
    
    def add_message(self, role, content):
        self.messages.append({"role": role, "content": content})
        self._trim_to_fit()
    
    def _trim_to_fit(self):
        """当超出 token 限制时,移除最早的消息"""
        while self._count_tokens() > self.max_tokens:
            if len(self.messages) > 1:
                self.messages.pop(0)  # 移除最早的消息
            else:
                break
    
    def _count_tokens(self):
        # 简化的 token 计算,实际应使用 tiktoken 等库
        return sum(len(m["content"]) for m in self.messages)
    
    def get_context(self):
        return self.messages

3.2 智能摘要策略

当对话历史过长时,直接截断会丢失重要信息。更好的做法是使用摘要机制

class SummarizingMemory:
    def __init__(self, llm_client, max_messages=10):
        self.llm = llm_client
        self.max_messages = max_messages
        self.recent_messages = []
        self.summary = ""
    
    def add_message(self, role, content):
        self.recent_messages.append({"role": role, "content": content})
        
        if len(self.recent_messages) > self.max_messages:
            self._summarize_oldest()
    
    def _summarize_oldest(self):
        """将最早的消息摘要化"""
        to_summarize = self.recent_messages[:5]
        self.recent_messages = self.recent_messages[5:]
        
        summary_prompt = f"""
        请对以下对话进行摘要,保留关键信息:
        {to_summarize}
        
        现有摘要:{self.summary}
        """
        
        self.summary = self.llm.generate(summary_prompt)
    
    def get_context(self):
        """返回:摘要 + 近期消息"""
        context = []
        if self.summary:
            context.append({
                "role": "system", 
                "content": f"历史对话摘要:{self.summary}"
            })
        context.extend(self.recent_messages)
        return context

3.3 关键信息提取

除了摘要,我们还可以提取实体关键事实

class EntityMemory:
    def __init__(self, llm_client):
        self.llm = llm_client
        self.entities = {}  # 存储提取的实体
        self.facts = []     # 存储关键事实
    
    def extract_from_message(self, message):
        """从消息中提取实体和事实"""
        extraction_prompt = f"""
        从以下对话中提取关键信息(JSON格式):
        {message}
        
        请提取:
        1. 提到的实体(人名、地名、组织、产品等)
        2. 关键事实(偏好、需求、约束条件等)
        """
        
        result = self.llm.generate(extraction_prompt)
        extracted = json.loads(result)
        
        # 合并到记忆中
        for entity in extracted.get("entities", []):
            self.entities[entity["name"]] = entity
        
        self.facts.extend(extracted.get("facts", []))
    
    def get_relevant_context(self, query):
        """获取与当前查询相关的实体和事实"""
        relevant = []
        
        # 简单的关键词匹配(实际可用向量检索)
        for name, entity in self.entities.items():
            if any(word in query for word in name.split()):
                relevant.append(f"{name}: {entity.get('description', '')}")
        
        for fact in self.facts:
            if any(word in query for word in fact.split()):
                relevant.append(fact)
        
        return relevant

四、长期记忆的实现:持久化与检索

4.1 用户画像系统

用户画像是长期记忆的核心,通常包含:

@dataclass
class UserProfile:
    user_id: str
    basic_info: Dict  # 基本信息
    preferences: Dict  # 偏好设置
    interaction_history: List  # 交互历史摘要
    learned_patterns: Dict  # 学习到的行为模式
    
class UserProfileManager:
    def __init__(self, storage_backend):
        self.storage = storage_backend
        self.cache = {}
    
    async def get_profile(self, user_id: str) -> UserProfile:
        if user_id not in self.cache:
            data = await self.storage.load(user_id)
            self.cache[user_id] = UserProfile(**data)
        return self.cache[user_id]
    
    async def update_profile(self, user_id: str, updates: Dict):
        profile = await self.get_profile(user_id)
        
        # 更新字段
        for key, value in updates.items():
            if hasattr(profile, key):
                setattr(profile, key, value)
        
        # 持久化
        await self.storage.save(user_id, profile.__dict__)

4.2 基于向量数据库的记忆检索

对于大规模的记忆存储,向量数据库是最佳选择:

class VectorMemory:
    def __init__(self, embedding_model, vector_db):
        self.embedder = embedding_model
        self.db = vector_db
    
    async def add_memory(self, user_id: str, content: str, 
                         memory_type: str = "fact"):
        """添加记忆到向量数据库"""
        # 生成嵌入向量
        embedding = await self.embedder.embed(content)
        
        # 存储到向量数据库
        await self.db.upsert(
            vectors=[{
                "id": f"{user_id}_{uuid.uuid4()}",
                "values": embedding,
                "metadata": {
                    "user_id": user_id,
                    "content": content,
                    "type": memory_type,
                    "timestamp": datetime.now().isoformat()
                }
            }]
        )
    
    async def retrieve_relevant(self, user_id: str, query: str, 
                                 top_k: int = 5) -> List[str]:
        """检索与查询相关的记忆"""
        # 生成查询向量
        query_embedding = await self.embedder.embed(query)
        
        # 向量检索
        results = await self.db.query(
            vector=query_embedding,
            filter={"user_id": user_id},
            top_k=top_k
        )
        
        return [r.metadata["content"] for r in results]

4.3 记忆的重要性评分

不是所有记忆都同等重要,我们需要机制来评估和筛选:

class ScoredMemory:
    def __init__(self, llm_client):
        self.llm = llm_client
    
    async def calculate_importance(self, content: str, context: Dict) -> float:
        """计算记忆的重要性分数"""
        scoring_prompt = f"""
        评估以下信息的重要性(0-10分):
        
        信息内容:{content}
        上下文:{context}
        
        评分标准:
        - 10分:核心信息、长期偏好、重要信息
        - 7-9分:近期重要事件、明确的用户需求
        - 4-6分:一般性信息、临时性内容
        - 1-3分:闲聊、无关紧要的细节
        
        只返回数字分数。
        """
        
        score_text = await self.llm.generate(scoring_prompt)
        try:
            return float(score_text.strip())
        except:
            return 5.0  # 默认中等重要性
    
    async def should_remember(self, content: str, 
                              threshold: float = 6.0) -> bool:
        """判断是否应该记住这条信息"""
        score = await self.calculate_importance(content, {})
        return score >= threshold

五、记忆系统的架构设计

5.1 分层记忆架构

一个完整的记忆系统应该采用分层设计:

┌─────────────────────────────────────────────────────────────┐
│                        Agent 核心层                          │
│                    (决策与行动执行)                           │
└────────────────────┬────────────────────────────────────────┘
                     │
┌────────────────────▼────────────────────────────────────────┐
│                      记忆管理层                              │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐  │
│  │  工作记忆    │  │  短期记忆    │  │     长期记忆         │  │
│  │  (内存)     │  │  (Redis)    │  │   (向量DB + SQL)     │  │
│  └─────────────┘  └─────────────┘  └─────────────────────┘  │
└────────────────────┬────────────────────────────────────────┘
                     │
        ┌────────────┼────────────┐
        ▼            ▼            ▼
   ┌─────────┐  ┌─────────┐  ┌─────────┐
   │ 对话历史 │  │ 用户画像 │  │ 知识库  │
   └─────────┘  └─────────┘  └─────────┘

5.2 记忆检索流程

当 Agent 需要记忆时,应该遵循以下检索流程:

class MemoryManager:
    def __init__(self):
        self.working_memory = WorkingMemory()
        self.short_term = ShortTermMemory()
        self.long_term = LongTermMemory()
        self.vector_memory = VectorMemory()
    
    async def retrieve_context(self, user_id: str, 
                               current_query: str) -> Dict:
        """检索完整的上下文信息"""
        context = {
            "working": [],
            "short_term": [],
            "long_term": [],
            "relevant_memories": []
        }
        
        # 1. 获取工作记忆(最高优先级)
        context["working"] = self.working_memory.get_all()
        
        # 2. 获取短期记忆
        context["short_term"] = self.short_term.get_recent(n=10)
        
        # 3. 获取用户画像
        context["user_profile"] = await self.long_term.get_profile(user_id)
        
        # 4. 向量检索相关记忆
        context["relevant_memories"] = await self.vector_memory.retrieve_relevant(
            user_id, current_query, top_k=5
        )
        
        # 5. 组装最终上下文(按优先级排序)
        return self._assemble_context(context)
    
    def _assemble_context(self, context: Dict) -> str:
        """将各类记忆组装成 LLM 可用的上下文"""
        parts = []
        
        # 用户画像
        if context.get("user_profile"):
            parts.append(f"用户画像:{context['user_profile']}")
        
        # 相关历史记忆
        if context.get("relevant_memories"):
            parts.append("相关历史信息:")
            for mem in context["relevant_memories"]:
                parts.append(f"- {mem}")
        
        # 近期对话
        if context.get("short_term"):
            parts.append("近期对话:")
            for msg in context["short_term"]:
                parts.append(f"{msg['role']}: {msg['content']}")
        
        return "\n".join(parts)

5.3 记忆的更新与遗忘

记忆系统需要支持动态更新和合理的遗忘机制:

class AdaptiveMemory:
    def __init__(self):
        self.access_counts = {}  # 访问计数
        self.last_accessed = {}  # 最后访问时间
        self.creation_time = {}  # 创建时间
    
    async def access(self, memory_id: str):
        """记录记忆访问"""
        self.access_counts[memory_id] = self.access_counts.get(memory_id, 0) + 1
        self.last_accessed[memory_id] = datetime.now()
    
    async def should_forget(self, memory_id: str) -> bool:
        """判断是否应该遗忘这条记忆"""
        # 基于访问频率和时间的遗忘策略
        access_count = self.access_counts.get(memory_id, 0)
        last_access = self.last_accessed.get(memory_id, datetime.now())
        age = datetime.now() - self.creation_time.get(memory_id, datetime.now())
        
        # 高频访问的记忆不轻易遗忘
        if access_count > 10:
            return False
        
        # 很久没访问的低频记忆可以遗忘
        if age.days > 90 and access_count < 3:
            return True
        
        return False
    
    async def consolidate_memories(self):
        """记忆巩固:合并相似记忆,遗忘不重要记忆"""
        # 1. 找出应该遗忘的记忆
        to_forget = []
        for memory_id in self.access_counts:
            if await self.should_forget(memory_id):
                to_forget.append(memory_id)
        
        # 2. 执行遗忘
        for memory_id in to_forget:
            await self._delete_memory(memory_id)
        
        # 3. 合并相似记忆
        await self._merge_similar_memories()

六、实战案例:构建一个具备记忆的客服 Agent

让我们通过一个完整的例子来演示如何构建具备记忆能力的 Agent:

import openai
from typing import List, Dict
import json

class MemoryEnabledAgent:
    def __init__(self, api_key: str):
        self.client = openai.AsyncOpenAI(api_key=api_key)
        self.memory_manager = MemoryManager()
    
    async def chat(self, user_id: str, message: str) -> str:
        # 1. 检索上下文
        context = await self.memory_manager.retrieve_context(
            user_id, message
        )
        
        # 2. 构建系统提示
        system_prompt = f"""你是一个智能客服助手。请基于以下上下文回答用户问题:

{context}

请保持友好、专业的态度,如果需要更多信息请主动询问。"""
        
        # 3. 调用 LLM
        response = await self.client.chat.completions.create(
            model="gpt-4",
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": message}
            ]
        )
        
        reply = response.choices[0].message.content
        
        # 4. 更新记忆
        await self.memory_manager.add_interaction(
            user_id=user_id,
            user_message=message,
            assistant_reply=reply
        )
        
        return reply

# 使用示例
async def main():
    agent = MemoryEnabledAgent(api_key="your-api-key")
    user_id = "user_123"
    
    # 第一轮对话
    reply1 = await agent.chat(user_id, "我想退货")
    print(f"Agent: {reply1}")
    
    # 第二轮对话(Agent 应该记得用户想退货)
    reply2 = await agent.chat(user_id, "订单号是 12345")
    print(f"Agent: {reply2}")
    
    # 第三轮对话(Agent 应该记得之前的上下文)
    reply3 = await agent.chat(user_id, "什么时候能到账?")
    print(f"Agent: {reply3}")

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())

七、性能优化与最佳实践

7.1 Token 优化

记忆会占用大量 Token,需要优化:

  • 摘要压缩:长对话定期摘要
  • 信息筛选:只保留相关记忆
  • 分层检索:先粗筛再精筛

7.2 延迟优化

记忆检索不应阻塞响应:

  • 异步加载:后台预加载用户画像
  • 缓存策略:热点数据内存缓存
  • 并行检索:多种记忆并行查询

7.3 隐私与安全

记忆涉及敏感信息:

  • 数据脱敏:PII 信息加密存储
  • 访问控制:用户只能访问自己的记忆
  • 过期策略:敏感信息定期清理

八、未来展望

AI Agent 的记忆机制仍在快速发展中,值得关注的方向包括:

  1. 神经符号记忆:结合神经网络和符号推理
  2. 终身学习:Agent 持续学习和自我改进
  3. 多模态记忆:整合文本、图像、音频等多种模态
  4. 联邦记忆:分布式记忆共享与隐私保护

结语

记忆是 AI Agent 从"工具"进化为"伙伴"的关键。通过合理设计工作记忆、短期记忆和长期记忆的分层架构,我们可以构建出真正理解用户、持续学习、不断进化的智能 Agent。

希望本文能为你的 AI Agent 开发之旅提供有价值的参考。如果你有任何问题或想法,欢迎在评论区交流讨论。


参考资源:


本文首发于稀土掘金,转载请注明出处。