/ AI Agent  记忆管理  LangChain  向量数据库  Redis  对话系统  智能体  Python 

AI Agent 记忆管理实战:让你的智能体真正记住用户上下文


封面

为什么 AI Agent 需要记忆管理?

大语言模型本质上是无状态的——每次调用都是全新的开始,它不记得上一轮对话说了什么,也不知道用户的偏好和历史操作。这对于简单的问答场景还好,但当我们构建真正的 AI Agent 时,这个问题就变得致命了。

想象一下:你告诉 Agent "我是一名 Python 开发者,不喜欢冗长的说明,直接给代码",下一轮对话它又开始啰嗦地解释基础概念——这种体验会让用户彻底失去耐心。

记忆管理解决的核心问题包括:

  • 上下文连续性:跨会话记住用户信息和偏好

  • 知识积累:Agent 能从历史交互中学习

  • 个性化响应:根据用户画像调整回复风格

  • 任务追踪:记住长期任务的进度和状态

记忆的三种类型:短期、长期与情节记忆

借鉴人类认知科学的分类,AI Agent 的记忆通常分为三种类型,每种类型对应不同的存储策略和使用场景。

短期记忆(Working Memory)

短期记忆对应当前会话的上下文窗口。最简单的实现就是把对话历史全部塞进 prompt,但这会很快撞上 token 限制。

from langchain.memory import ConversationBufferWindowMemory

# 只保留最近 10 轮对话
memory = ConversationBufferWindowMemory(
    k=10,
    return_messages=True,
    memory_key="chat_history"
)

# 或者使用摘要记忆,自动压缩历史
from langchain.memory import ConversationSummaryBufferMemory
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4o-mini")
summary_memory = ConversationSummaryBufferMemory(
    llm=llm,
    max_token_limit=2000,  # 超过则自动摘要
    return_messages=True
)

ConversationSummaryBufferMemory 是处理长对话的利器:它保留最近的原始消息,同时把更早的历史压缩成摘要,兼顾了细节保留和 token 节省。

长期记忆(Long-term Memory)

长期记忆需要持久化存储,跨会话保留。常见方案是使用向量数据库存储记忆片段,查询时通过语义相似度检索相关记忆。

from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.memory import VectorStoreRetrieverMemory

embeddings = OpenAIEmbeddings()
vectorstore = Chroma(
    collection_name="agent_memory",
    embedding_function=embeddings,
    persist_directory="./memory_db"
)

retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
vector_memory = VectorStoreRetrieverMemory(
    retriever=retriever,
    memory_key="relevant_history"
)

# 保存记忆
vector_memory.save_context(
    {"input": "我在做一个电商推荐系统"},
    {"output": "好的,我来帮你设计推荐算法"}
)

# 查询相关记忆
relevant = vector_memory.load_memory_variables(
    {"prompt": "推荐系统进展如何了?"}
)
print(relevant["relevant_history"])

情节记忆(Episodic Memory)

情节记忆记录具体的事件和经历,比用户的操作日志、重要决策节点等。可以用结构化数据库(如 PostgreSQL)存储,支持按时间、类型等维度检索。

实战:用 Redis + LangChain 实现跨会话记忆

下面我们来构建一个完整的跨会话记忆方案,使用 Redis 存储会话历史,支持多用户隔离。

环境准备

pip install langchain langchain-openai langchain-community redis
docker run -d -p 6379:6379 redis:7-alpine

实现代码

import redis
import json
from datetime import datetime
from langchain_openai import ChatOpenAI
from langchain.memory import ConversationBufferWindowMemory
from langchain.schema import HumanMessage, AIMessage

class PersistentAgentMemory:
    """支持跨会话持久化的 Agent 记忆管理器"""
    
    def __init__(self, user_id: str, redis_url: str = "redis://localhost:6379"):
        self.user_id = user_id
        self.redis_client = redis.from_url(redis_url)
        self.session_key = f"agent:memory:{user_id}"
        self.profile_key = f"agent:profile:{user_id}"
        
    def load_history(self, limit: int = 20) -> list:
        """加载最近的对话历史"""
        messages = self.redis_client.lrange(self.session_key, -limit*2, -1)
        history = []
        for msg in messages:
            data = json.loads(msg)
            if data["role"] == "human":
                history.append(HumanMessage(content=data["content"]))
            else:
                history.append(AIMessage(content=data["content"]))
        return history
    
    def save_message(self, role: str, content: str):
        """保存单条消息"""
        message = {
            "role": role,
            "content": content,
            "timestamp": datetime.now().isoformat()
        }
        self.redis_client.rpush(self.session_key, json.dumps(message, ensure_ascii=False))
        # 只保留最近 200 条
        self.redis_client.ltrim(self.session_key, -200, -1)
        
    def update_user_profile(self, key: str, value: str):
        """更新用户画像"""
        self.redis_client.hset(self.profile_key, key, value)
        
    def get_user_profile(self) -> dict:
        """获取用户画像"""
        profile = self.redis_client.hgetall(self.profile_key)
        return {k.decode(): v.decode() for k, v in profile.items()}


def create_agent_with_memory(user_id: str):
    """创建带记忆的 Agent"""
    memory_manager = PersistentAgentMemory(user_id)
    llm = ChatOpenAI(model="gpt-4o", temperature=0.7)
    
    def chat(user_input: str) -> str:
        # 加载历史
        history = memory_manager.load_history(limit=10)
        profile = memory_manager.get_user_profile()
        
        # 构建系统提示
        profile_str = "\n".join([f"- {k}: {v}" for k, v in profile.items()])
        system_prompt = f"""你是一个有记忆的 AI 助手。
        
用户画像:
{profile_str if profile_str else "暂无"}

请根据对话历史和用户画像提供个性化的回复。"""
        
        # 组装消息
        messages = [{"role": "system", "content": system_prompt}]
        for msg in history:
            if isinstance(msg, HumanMessage):
                messages.append({"role": "user", "content": msg.content})
            else:
                messages.append({"role": "assistant", "content": msg.content})
        messages.append({"role": "user", "content": user_input})
        
        # 调用 LLM
        response = llm.invoke(messages)
        answer = response.content
        
        # 持久化
        memory_manager.save_message("human", user_input)
        memory_manager.save_message("assistant", answer)
        
        return answer
    
    return chat


# 使用示例
agent = create_agent_with_memory("user_001")
print(agent("你好,我叫小明,是一个 Python 后端开发者"))
print(agent("给我推荐一个适合我的异步框架"))  # 会记住"Python后端开发者"

进阶:用向量检索实现语义记忆检索

对于需要从大量历史记忆中精准召回的场景,向量检索是必不可少的。以下是一个完整的语义记忆系统:

from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.schema import Document
import numpy as np

class SemanticMemoryStore:
    """基于向量检索的语义记忆存储"""
    
    def __init__(self, user_id: str):
        self.user_id = user_id
        self.embeddings = OpenAIEmbeddings()
        self.index_path = f"./vector_store/{user_id}"
        
        try:
            self.vectorstore = FAISS.load_local(
                self.index_path, 
                self.embeddings,
                allow_dangerous_deserialization=True
            )
            print(f"加载已有记忆索引,用户:{user_id}")
        except:
            # 首次使用,创建空索引
            self.vectorstore = None
            
    def add_memory(self, content: str, metadata: dict = None):
        """添加新记忆"""
        doc = Document(
            page_content=content,
            metadata=metadata or {"timestamp": datetime.now().isoformat()}
        )
        if self.vectorstore is None:
            self.vectorstore = FAISS.from_documents([doc], self.embeddings)
        else:
            self.vectorstore.add_documents([doc])
        self.vectorstore.save_local(self.index_path)
        
    def search_memory(self, query: str, top_k: int = 5) -> list[str]:
        """语义检索相关记忆"""
        if self.vectorstore is None:
            return []
        results = self.vectorstore.similarity_search_with_score(query, k=top_k)
        # 过滤相似度太低的结果(FAISS使用L2距离,越小越相似)
        return [doc.page_content for doc, score in results if score < 1.5]


# 使用示例
store = SemanticMemoryStore("user_001")
store.add_memory("用户喜欢简洁的代码风格,不喜欢过度封装")
store.add_memory("用户正在开发一个基于 FastAPI 的微服务项目")
store.add_memory("用户使用 PostgreSQL 作为主数据库")

# 语义检索
memories = store.search_memory("数据库选型建议")
print("相关记忆:", memories)
# 输出:["用户使用 PostgreSQL 作为主数据库", ...]

记忆压缩与遗忘机制

无限积累的记忆会带来存储和检索性能问题,同时也可能引入过时信息的干扰。借鉴人类记忆的遗忘曲线,我们需要为 Agent 设计记忆的老化和压缩机制。

  • 时间衰减:按时间戳给记忆打分,越久远的记忆权重越低

  • 访问频率加权:被检索到的次数越多,说明越重要,应该保留

  • 定期摘要压缩:用 LLM 把多条细粒度记忆合并成高层次摘要

  • 矛盾检测:新记忆与旧记忆冲突时,更新而非简单叠加

async def compress_old_memories(user_id: str, days_threshold: int = 30):
    """压缩 30 天前的旧记忆"""
    store = SemanticMemoryStore(user_id)
    llm = ChatOpenAI(model="gpt-4o-mini")
    
    # 获取旧记忆(实际需要按时间过滤)
    old_memories = store.search_memory("", top_k=50)  # 获取全部
    
    if len(old_memories) < 10:
        return  # 记忆太少不需要压缩
    
    # 用 LLM 提炼关键信息
    prompt = f"""以下是用户的历史记忆片段,请提炼出最关键的用户特征和偏好,输出5条精华摘要:

{chr(10).join(old_memories[:20])}

请输出5条精华,每条不超过50字:"""
    
    result = await llm.ainvoke(prompt)
    summaries = result.content.strip().split("\n")
    
    # 删除旧记忆,保存压缩后的摘要
    for summary in summaries:
        store.add_memory(
            summary.strip(), 
            metadata={"type": "compressed_summary", "timestamp": datetime.now().isoformat()}
        )
    
    print(f"记忆压缩完成,{len(old_memories)} 条 → {len(summaries)} 条")

部署建议与踩坑总结

在生产环境中落地 AI Agent 记忆系统,有几个关键问题需要特别注意:

  • 隐私合规:记忆中可能含有用户的敏感信息,必须加密存储,并支持用户的"遗忘权"(一键清除所有记忆)

  • 记忆污染:如果 Agent 记住了错误信息(用户说错了、或数据异常),需要提供纠错机制,而不是把错误越记越深

  • 多端同步:用户可能在 PC、手机多端使用,记忆需要实时同步,用 Redis Pub/Sub 或消息队列解决

  • 冷启动问题:新用户没有任何历史记忆,要设计合理的引导对话,快速建立初始画像

  • Embedding 费用控制:向量化每条记忆都需要调用 Embedding API,建议批量处理或使用本地模型(如 text2vec-chinese)降低成本

记忆管理是 AI Agent 从"好用"到"好用且懂我"的关键一跃。随着 MemGPT、Mem0 等专门面向 Agent 记忆的框架日趋成熟,这个领域还有很大的探索空间。欢迎在评论区分享你的实践经验!

发布评论

热门评论区: