恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
AI Agent记忆体系构建:从短期缓存到长期存储的工程实践
首页
资讯中心
/
AI Agent记忆体系构建:从短期缓存到长期存储的工程实践
AI Agent记忆体系构建:从短期缓存到长期存储的工程实践
发布时间:2026/8/26 2:50:58
1. 从概念到代码为什么我们需要为AI Agent构建记忆体系如果你最近在捣鼓AI Agent不管是基于LangChain、LangGraph还是自己手搓框架大概率会遇到一个头疼的问题这Agent怎么跟金鱼似的聊两句就忘了前面说过啥你让它帮你规划一个项目第一步写得挺好到第三步它可能就把第一步的目标给忘了或者在一个长对话里它完全记不住你十分钟前给它设定的角色和偏好。这背后的核心就是**记忆Memory**的缺失。我们人类能进行复杂的思考和协作离不开记忆系统。短期记忆让我们记住当前的对话上下文和正在处理的任务步骤长期记忆存储了我们的知识、经验和身份认知工作记忆则像大脑里的“草稿纸”负责临时存储和加工信息以完成推理和决策。对于AI Agent而言没有记忆它就只是一个“瞬时反应器”无法形成连贯的“意识流”更谈不上自主性和智能。所以当我们谈论“AI Agent记忆体系建设”时我们不是在做一个花哨的附加功能而是在为Agent注入连续性和身份感的核心基础设施。这直接决定了Agent能否胜任需要多轮交互、状态保持和持续学习的复杂任务比如个人智能助理、游戏NPC、自动化工作流引擎等。基于当前的实践一个工程化的记忆体系通常围绕三个核心维度展开这也是本文要实战拆解的重点短期记忆Short-term Memory处理当前会话的上下文通常有硬性长度限制如LLM的上下文窗口。长期记忆Long-term Memory存储需要持久化、在多次会话间共享的知识、经历和用户偏好。工作记忆Working Memory在单次任务执行周期内临时存储、组织和操作任务相关的中间状态和信息。接下来我将结合具体的代码示例以Python为主带你一步步实现这三类记忆并探讨如何将它们有机整合构建一个真正“有记性”的AI Agent。2. 短期记忆实现在有限上下文窗口内的“对话保鲜术”短期记忆是Agent与用户交互的最前线。它的核心挑战非常明确大语言模型LLM的上下文窗口是有限的如4K、8K、128K、200K Token。你不可能把所有的对话历史都无脑塞进去。因此短期记忆管理的本质是上下文窗口的优化管理。2.1 基础实现ConversationBufferMemory最简单的短期记忆就是缓存整个对话历史。LangChain等框架提供了开箱即用的类。from langchain.memory import ConversationBufferMemory memory ConversationBufferMemory() # 模拟对话 memory.chat_memory.add_user_message(你好我叫小明。) memory.chat_memory.add_ai_message(你好小明有什么可以帮你的) memory.chat_memory.add_user_message(记住我更喜欢喝美式咖啡不加糖。) # 加载记忆变量通常用于构造提示词 context memory.load_memory_variables({}) print(context) # 输出{history: Human: 你好我叫小明。\nAI: 你好小明有什么可以帮你的\nHuman: 记住我更喜欢喝美式咖啡不加糖。}它的工作原理ConversationBufferMemory内部维护了一个列表简单地追加每一轮的人类Human和AIAI消息。当调用load_memory_variables时它将这些消息拼接成一个字符串通常是Human: ...\nAI: ...的格式然后你可以将这个字符串作为history变量插入到发给LLM的最终提示词Prompt中。致命缺陷随着对话轮数增加这个缓存字符串会越来越长最终必然超出LLM的上下文窗口限制导致最早的、可能仍很重要的信息被“挤出去”或者直接触发模型的最大长度错误。2.2 进阶策略ConversationBufferWindowMemory 与 Summarization为了解决长度问题我们有两种主流策略滑动窗口和摘要压缩。策略一滑动窗口ConversationBufferWindowMemory只保留最近K轮对话。from langchain.memory import ConversationBufferWindowMemory # 只保留最近2轮对话1轮用户消息AI消息 window_memory ConversationBufferWindowMemory(k2) # 假设已有5轮对话历史... for i in range(5): window_memory.chat_memory.add_user_message(f用户消息{i}) window_memory.chat_memory.add_ai_message(fAI回复{i}) context window_memory.load_memory_variables({}) print(context[history]) # 输出可能只包含 # Human: 用户消息3 # AI: AI回复3 # Human: 用户消息4 # AI: AI回复4为什么选择滑动窗口实现简单计算开销极低。它基于一个假设最近的对话对当前回复最重要。这对于闲聊、简单QA场景是有效的。但它的代价是主动遗忘如果关键信息如用户姓名、核心任务目标在早期被提及一旦滑出窗口Agent就会彻底遗忘。策略二摘要压缩ConversationSummaryMemory使用另一个LLM或本LLM定期或按需对之前的对话历史进行摘要然后用摘要来代表“过去的记忆”从而大幅节省Token。from langchain.memory import ConversationSummaryMemory from langchain_openai import ChatOpenAI from langchain_core.prompts import PromptTemplate llm ChatOpenAI(modelgpt-3.5-turbo, temperature0) summary_memory ConversationSummaryMemory( llmllm, memory_keychat_history, # 可以自定义摘要提示词 promptPromptTemplate.from_template( 请逐步总结当前对话内容重点保留关于人物、事实、目标和偏好的信息。当前对话\n{new_lines}\n\n现有摘要{summary}\n\n新摘要 ) ) # 添加多轮对话 summary_memory.save_context({input: 我叫李雷来自北京。}, {output: 你好李雷北京今天天气怎么样}) summary_memory.save_context({input: 北京今天晴天20度。对了我养了一只狗叫旺财。}, {output: 听起来很棒旺财是什么品种}) # 查看记忆 current_memory summary_memory.load_memory_variables({}) print(current_memory[chat_history]) # 输出可能是一个摘要文本而非原始对话 # “用户李雷来自北京他提到北京天气晴朗20度并养了一只名叫旺财的狗。”为什么选择摘要压缩它能将长篇对话压缩成精炼的要点理论上可以保存更长时间跨度的关键信息。但这里有三个大坑信息损耗摘要过程必然丢失细节。LLM可能错误总结或遗漏你认为重要的信息比如“旺财是柯基”被简化为“养了一只狗”。成本与延迟每次生成摘要都需要调用一次LLM增加了API成本和响应时间。摘要漂移多次迭代摘要后信息可能失真或偏离原意。实操心得混合策略才是王道在实际项目中我很少单独使用某一种策略。一个更健壮的短期记忆方案通常是“滑动窗口 关键信息提取”或“滑动窗口 条件触发式摘要”。关键信息提取在对话开始时或检测到关键信息如姓名、邮箱、任务编号、偏好设置时使用一个小的LLM调用或规则引擎将这些信息结构化地提取出来存入一个独立的“关键事实表”这个表会始终保留在上下文中不受窗口滑动影响。条件触发式摘要不是每轮都摘要而是当对话历史Token数达到某个阈值如窗口的70%或者检测到话题发生显著切换时才对窗口外的“旧历史”进行一次摘要然后将摘要和窗口内的“新历史”一起作为新的上下文。3. 长期记忆实现为Agent打造一个“外部大脑”如果说短期记忆是Agent的“RAM”那么长期记忆就是它的“硬盘”。它用于存储那些需要跨越不同对话会话Session持久保存的信息。实现长期记忆本质上是为Agent增加了一个外部存储与检索系统。3.1 核心架构向量数据库 检索增强生成RAG这是目前最主流、最有效的长期记忆工程范式。其工作流程可以概括为存储时向量化检索时相似度匹配。信息写入记忆存储当Agent获得需要长期记忆的信息例如用户说“我的项目代号是‘凤凰’截止日期是下周五”将该段文本通过嵌入模型Embedding Model转换为一个高维向量Vector然后将这个向量和原始文本或结构化数据一起存入向量数据库Vector Database。信息读取记忆回想当Agent需要上下文来回答当前问题时例如用户问“我的那个项目现在什么进度了”将当前问题也转换为向量然后在向量数据库中执行相似度搜索Similarity Search找出与问题向量最相关的几条“记忆”即之前存储的文本片段将这些记忆作为附加上下文插入到给LLM的提示词中。# 示例使用Chroma向量数据库和OpenAI Embeddings实现长期记忆 from langchain.vectorstores import Chroma from langchain.embeddings import OpenAIEmbeddings from langchain.schema import Document from langchain_openai import ChatOpenAI from langchain.chains import RetrievalQA # 1. 初始化嵌入模型和向量库 embeddings OpenAIEmbeddings(modeltext-embedding-3-small) vectorstore Chroma(embedding_functionembeddings, persist_directory./chroma_db) # 2. 存储长期记忆模拟 memories [ Document(page_content用户张三的邮箱是 zhangsanexample.com, metadata{type: contact, user: 张三}), Document(page_content项目‘凤凰’的截止日期是2023-10-27, metadata{type: project, project: 凤凰}), Document(page_content张三不喜欢在会议中使用幻灯片偏好白板讨论。, metadata{type: preference, user: 张三}), ] vectorstore.add_documents(memories) # 3. 创建基于记忆检索的链 llm ChatOpenAI(modelgpt-4, temperature0) qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, # 将检索到的文档“塞”进提示词 retrievervectorstore.as_retriever(search_kwargs{k: 2}) # 检索最相关的2条记忆 ) # 4. 查询记忆回想 response qa_chain.run(张三对开会有什么偏好吗) print(response) # LLM会基于检索到的记忆进行回答“张三不喜欢在会议中使用幻灯片偏好白板讨论。”3.2 关键工程细节与避坑指南仅仅跑通上述流程还不够要让长期记忆真正好用必须处理以下几个核心问题1. 记忆的粒度与索引策略是把整段对话存进去还是拆分成单句这直接影响检索精度。粗粒度如整段对话存储简单但检索时可能带回大量无关信息稀释关键内容。细粒度如单句或事实单元检索更精准但需要更复杂的分割逻辑且可能破坏上下文连贯性。我的经验对于事实型记忆邮箱、日期、偏好采用细粒度存储并为其添加丰富的元数据metadata如user,type,date。对于叙事型记忆会议纪要、故事采用中等粒度如一个主题段落并可能同时存储其摘要。2. 记忆的更新与冲突解决长期记忆不是只写不读的日志。信息会变化也会冲突。场景用户先说“我喜欢蓝色”后来又说“我现在更喜欢绿色了”。简单策略总是新增记忆条目。检索时通过时间戳元数据让LLM知道哪条更新。但这会导致数据库膨胀和检索噪声。进阶策略实现记忆的“更新”操作。这可以通过在存储新记忆时先检索相似旧记忆然后进行去重或合并来实现。例如可以设计一个流程新记忆“喜欢绿色”触发对“颜色偏好”类记忆的检索找到旧的“喜欢蓝色”条目然后用新条目覆盖它或将其标记为过期。3. 元数据Metadata的威力元数据是高效管理海量记忆的钥匙。除了基本的user_id,session_id,timestamp你应该根据业务自定义。用途过滤Filtering检索时只找某个用户或某种类型的记忆。retriever vectorstore.as_retriever(filterdict(user张三, typepreference))排序Ranking结合相似度分数和时间戳让更相关、更新的记忆排名靠前。管理基于元数据批量清理或归档旧记忆。实操建议在存储任何记忆前设计一个简单的模式Schema。思考你需要根据什么维度来查找这些记忆这些维度就是你的元数据字段。4. 嵌入模型的选择与“记忆失真”不同的嵌入模型对同一文本产生的向量不同从而影响相似度检索的效果。坑你用模型A存了“苹果公司”用模型B去检索“Apple Inc.”可能因为语义空间不同而匹配失败。解决方案嵌入模型一旦选定在整个记忆生命周期内不要轻易更换。如果必须换需要对整个向量库进行重建Re-index。对于多语言场景考虑使用多语言嵌入模型如text-embedding-3-small本身支持多语言。4. 工作记忆实现任务执行中的“思维草稿纸”工作记忆是Agent在执行单个复杂任务过程中的临时记忆。它不同于短期记忆的“对话历史”而是专注于任务本身的中间状态、子目标、执行步骤和临时结果。你可以把它理解为Agent的“黑板”或“便签纸”。4.1 典型场景与载体工作记忆在以下场景中至关重要多步骤任务规划与执行如“帮我订一张从北京到上海下周五出发价格低于1000元的机票并预订目的地附近评分4.5以上的酒店。”复杂工具使用如使用代码解释器逐步分析数据、编写和调试脚本。基于反馈的迭代如根据用户对生成图片的反馈“颜色再亮一点”调整参数重新生成。在这些场景中工作记忆的载体通常不是简单的字符串而是结构化的状态对象。以LangGraph或AutoGen这类支持多步骤执行的框架为例工作记忆直接体现为整个Agent系统的状态State。4.2 实战用LangGraph的状态管理实现工作记忆LangGraph的核心就是围绕一个可变的State来构建工作流。这个State就是一个完美的工作记忆容器。from typing import TypedDict, Annotated, List from langgraph.graph import StateGraph, END import operator # 1. 定义工作记忆的状态结构 class AgentState(TypedDict): # 用户原始输入 user_request: str # 解析后的任务列表 tasks: List[str] # 当前正在执行的任务索引 current_task_index: int # 每个任务的执行结果 task_results: Annotated[List[str], operator.add] # 使用operator.add来追加结果 # 最终汇总答案 final_answer: str # 2. 创建图和工作记忆状态 graph_builder StateGraph(AgentState) # 3. 定义节点每个节点读取和修改工作记忆 def task_planner(state: AgentState) - AgentState: 节点1解析用户请求拆解任务列表到工作记忆 request state[user_request] # 这里可以调用LLM进行任务规划 # 假设解析出三个任务 state[tasks] [搜索北京-上海机票, 筛选价格1000的航班, 搜索上海酒店并筛选评分] state[current_task_index] 0 state[task_results] [] return state def task_executor(state: AgentState) - AgentState: 节点2执行当前任务将结果存入工作记忆 idx state[current_task_index] current_task state[tasks][idx] # 模拟执行任务实际中可能调用搜索API、工具函数等 if current_task 搜索北京-上海机票: result 找到航班CA1501, CA1855。 elif current_task 筛选价格1000的航班: result CA1501价格950元符合要求。 else: result 找到酒店外滩华尔道夫评分4.7。 # 将结果追加到工作记忆的 task_results 列表中 state[task_results].append(f任务{idx1}『{current_task}』结果{result}) # 移动指针到下一个任务 state[current_task_index] idx 1 return state def check_continue(state: AgentState) - str: 条件边检查工作记忆判断是否所有任务都已完成 if state[current_task_index] len(state[tasks]): return continue_execution # 还有任务继续执行 else: return generate_summary # 任务完成进入汇总 def summary_generator(state: AgentState) - AgentState: 节点3汇总所有任务结果生成最终答案 all_results \n.join(state[task_results]) # 调用LLM基于工作记忆中的过程结果生成最终回复 state[final_answer] f根据您的需求已完成以下步骤\n{all_results}\n推荐您选择CA1501航班和外滩华尔道夫酒店。 return state # 4. 构建图 graph_builder.add_node(plan, task_planner) graph_builder.add_node(execute, task_executor) graph_builder.add_node(summarize, summary_generator) graph_builder.set_entry_point(plan) graph_builder.add_conditional_edges( plan, check_continue, # 根据工作记忆状态决定流向 {continue_execution: execute, generate_summary: summarize} ) graph_builder.add_conditional_edges( execute, check_continue, {continue_execution: execute, generate_summary: summarize} ) graph_builder.add_edge(summarize, END) # 5. 编译并运行图工作记忆在运行中自动传递和更新 graph graph_builder.compile() initial_state AgentState(user_request帮我订一张从北京到上海下周五出发价格低于1000元的机票并预订目的地附近评分4.5以上的酒店。) final_state graph.invoke(initial_state) print(final_state[final_answer])工作记忆的关键点结构化它不是一个文本块而是一个有明确字段如tasks,results的字典或对象方便程序化读写。过程性它记录的是“进行到哪一步了”、“这一步的输入输出是什么”。临时性它通常与一次任务执行绑定任务结束后其核心结果可能被提炼存入长期记忆但详细的中间状态会被清理。5. 记忆体系的融合与协同构建Agent的完整认知循环单独实现三种记忆并不难真正的挑战在于如何让它们协同工作形成一个有机的整体。一个典型的Agent认知循环如下感知/输入用户输入新消息。记忆召回从短期记忆滑动窗口获取最近的对话历史。从长期记忆向量库中以当前用户输入和短期历史为查询条件检索相关的持久化知识、用户档案、过往经历。工作记忆如果当前有正在执行的任务提供任务当前状态和中间结果。决策与推理LLM核心接收一个整合了以上所有记忆的、结构化的提示词进行思考并决定下一步行动直接回复、调用工具、更新任务状态等。记忆更新本轮对话的输入输出被追加到短期记忆缓冲区。如果产生了有价值的、需要持久化的信息如用户确认的最终选择、任务达成的结论将其结构化后存入长期记忆。如果涉及任务执行工作记忆的状态如当前步骤、结果被更新。行动与输出执行LLM决定的行动如调用API、运行代码并将结果返回给用户。融合架构示例草图概念层面class IntegratedAgentMemory: def __init__(self): self.short_term ConversationBufferWindowMemory(k10) self.long_term_store ChromaVectorStore(...) self.working_memory {} # 当前任务状态 def recall(self, query: str, user_id: str) - dict: 综合回忆 # 1. 获取短期上下文 short_context self.short_term.load_memory_variables({}) # 2. 从长期记忆检索 long_memories self.long_term_store.retrieve( queryquery short_context[history], filter{user_id: user_id}, k3 ) # 3. 整合工作记忆如果有 working_context self.working_memory.get(user_id, {}) return { short_term: short_context, long_term: long_memories, working_state: working_context } def update(self, user_input: str, ai_output: str, user_id: str): 更新记忆 # 1. 更新短期记忆 self.short_term.save_context({input: user_input}, {output: ai_output}) # 2. 判断是否需要写入长期记忆基于规则或LLM判断 if self._should_save_to_long_term(user_input, ai_output): self.long_term_store.add_document( contentfUser said: {user_input}. AI responded: {ai_output}, metadata{user_id: user_id, timestamp: now(), type: dialogue} ) # 3. 工作记忆的更新由具体的任务执行图来管理 # ...避坑经验记忆的冲突与优先级当不同来源的记忆信息冲突时例如长期记忆里用户说“喜欢咖啡”但短期记忆里刚说“今天想喝茶”需要制定优先级策略。一个常见的经验法则是短期记忆 工作记忆 长期记忆。即在本次对话中明确表达的信息优先级最高。这可以通过在提示词模板中清晰地分段和标注信息来源来实现例如近期对话历史最高优先级 {short_term_memory} 当前任务状态 {working_memory} 相关背景知识仅供参考 {long_term_memory} 请基于以上信息优先考虑近期对话和当前任务状态进行回复。6. 高级议题与未来展望在搭建好基础记忆体系后你可能会面临更进阶的挑战记忆的抽象与压缩长期记忆库不能无限膨胀。我们需要像人脑一样对记忆进行“消化”和“抽象”。例如可以将一系列具体的对话“周一买了牛奶”、“周三买了鸡蛋”、“周五买了面包”抽象成一条更高阶的记忆“用户每周有在超市采购食品杂货的习惯”。这可以通过定期运行一个后台的LLM摘要或聚类任务来实现。记忆的主动遗忘与价值评估并非所有信息都值得永久记忆。可以设计一个“记忆价值衰减”算法基于访问频率、最近访问时间、与用户核心画像的相关性等维度对记忆条目进行打分定期清理低分记忆。或者允许用户显式地命令Agent“忘记关于XXX的事情”。多模态记忆未来的Agent记忆不会局限于文本。图像、音频、传感器数据都可能成为记忆的一部分。这要求向量数据库能支持多模态嵌入并且记忆的检索和融合机制需要能处理异构数据。记忆与学习的闭环理想的记忆体系应该能让Agent从经验中学习。例如如果Agent调用某个API多次失败它应该能将“在XX条件下调用YY API容易失败”这一经验形成记忆并在未来类似场景中主动规避或尝试备选方案。这涉及到记忆与强化学习、因果推理等更复杂AI技术的结合。构建AI Agent的记忆体系是一个从简单缓存到复杂认知系统的工程旅程。它没有一劳永逸的解决方案需要你根据具体的应用场景、性能要求和资源约束在短期、长期和工作记忆之间找到最佳的平衡点和实现策略。希望这篇从实战出发的拆解能为你设计自己的“有记忆”的智能体提供一个坚实的起点。记住一个好的记忆系统是让你的Agent从“鹦鹉学舌”走向“真正有用”的关键一步。