ARTICLE DETAIL

资讯详情

深耕网站SEO优化与搜索引擎排名提升的一线实战洞察。

构建AI Agent记忆系统:从短期记忆到长期知识库的工程实践

构建AI Agent记忆系统:从短期记忆到长期知识库的工程实践 1. 项目概述为什么AI Agent需要一个“记忆宫殿”最近在折腾AI Agent项目时我发现一个核心痛点很多Agent表现得像个“金鱼”对话一长就忘了前面说过什么更别提在跨会话中积累经验和知识了。这直接限制了Agent的连续决策能力和个性化服务水平。于是我决定系统性地解决这个问题动手搭建一个分层的记忆体系。这不仅仅是简单地把对话历史存进数据库而是要模拟人类认知中的短期、长期和工作记忆让Agent真正“记住”并“思考”。简单来说这个项目就是为AI Agent构建一个类人的记忆系统。短期记忆负责处理当前会话的上下文是Agent的“工作台”长期记忆则像一个无限扩展的知识库存储跨会话的经验、用户偏好和领域事实而工作记忆是两者的桥梁负责在解决特定任务时从长期记忆中快速检索、筛选相关信息并加载到短期记忆中进行推理。这套体系能让Agent在复杂、多轮的交互中保持连贯性并随着时间推移变得越来越“懂你”。无论你是想开发一个贴心的个人助理还是一个能处理复杂流程的自动化Agent一个健壮的记忆体系都是其走向“智能”的基石。2. 记忆体系架构设计与核心思路2.1 从认知心理学到工程实现三层记忆模型在设计之初我参考了人类的记忆模型但并非照搬而是做了工程化的抽象和简化。核心是三层结构短期记忆 (Short-term Memory)对应LLM的上下文窗口。它的容量有限比如128K tokens但访问速度极快。在工程上它就是当前会话的“对话历史”或“思维链”。我将其实现为一个有容量限制的队列FIFO当新信息加入时最旧的信息会被挤出或总结压缩。关键在于这里存储的是原始的、高保真的交互序列是Agent进行下一步推理的直接依据。长期记忆 (Long-term Memory)这是一个持久化存储系统容量理论上无限。它不存储完整的对话流水账而是存储从交互中提取的“记忆片段”。这些片段可以是事实性知识用户明确提供的个人信息如“我叫张三”、“我住在北京”。偏好与习惯用户表现出的行为模式如“喜欢用Markdown格式回复”、“每次都会询问天气”。事件与经验总结对过去重要对话或任务执行结果的摘要如“上周成功帮用户预订了去上海的机票用户偏好靠窗座位”。嵌入向量将上述文本信息通过Embedding模型如text-embedding-3-small转换为向量用于后续的语义检索。工作记忆 (Working Memory)这是最体现“智能”的一层。它不是一块独立的存储区而是一个动态的、任务驱动的处理流程。当Agent接收到一个新任务或查询时工作记忆机制启动检索 (Retrieval)根据当前任务和短期记忆中的上下文生成一个或多个查询向量去长期记忆的向量数据库中进行相似性搜索。筛选与融合 (Filtering Fusion)检索到的记忆片段可能很多、很杂。工作记忆需要调用LLM对这些片段进行相关性排序、去重甚至总结只保留对当前任务最关键的信息。加载 (Loading)将筛选后的关键记忆片段与当前的短期记忆对话历史组合共同构成LLM此次推理的完整上下文提示Prompt。注意这个模型是逻辑上的划分在物理实现上短期记忆通常保存在内存或Redis中长期记忆则使用数据库如SQLite/PostgreSQL和向量数据库如Chroma, Pinecone, Weaviate工作记忆是一系列编排好的函数调用。2.2 技术栈选型与考量搭建这个体系我选择了以下技术栈并解释一下为什么核心框架LangChain/LangGraphLangChain提供了丰富的Memory类抽象如ConversationBufferWindowMemory用于短期记忆VectorStoreRetrieverMemory用于长期记忆能快速搭建原型。它的Chain和Agent概念非常适合编排工作记忆的流程。LangGraph当流程变得复杂需要循环、分支等更精细的控制时例如检索不到满意结果时自动调整查询词LangGraph的图状态机模型比单纯的Chain更强大。它天然适合维护一个共享的“状态”State这个状态可以完美承载我们的短期记忆和从长期记忆加载的内容。向量数据库与嵌入模型Chroma OpenAI EmbeddingsChroma轻量级、开源、易于集成特别适合本地开发和中小型项目。它提供了简单的API进行向量的存储和相似性搜索。OpenAItext-embedding-3-small在效果、速度和成本间取得了很好的平衡。对于记忆检索这种任务不需要像ada-002那么高的维度small版本在大多数情况下已足够准确且更经济。备选方案如果追求极致性能或需要托管服务可以考虑Pinecone或Weaviate。如果要求完全本地化可以用BAAI/bge-small-zh-v1.5这类开源模型搭配Chroma。传统数据库SQLite用于存储长期记忆中的结构化元数据例如记忆片段的ID、原始文本、类型事实/偏好/事件、关联的用户ID、时间戳、访问频率等。SQLite简单零依赖适合初期。生产环境可换为PostgreSQL。大语言模型GPT-4/GPT-3.5-Turbo记忆提取与总结当对话进行到一定阶段需要将短期记忆中的信息沉淀到长期记忆时需要调用LLM来识别关键信息、总结事件。GPT-4在这类理解与生成任务上更可靠。工作记忆的筛选与融合对检索结果进行精炼也需要LLM的判断力。核心推理最终的Agent动作生成当然也由LLM完成。这个选型是基于“快速实现、兼顾效果与复杂度”的考量。对于想深入研究的开发者完全可以替换其中任何一个组件。3. 核心模块实现细节与实操要点3.1 短期记忆的实现不只是聊天记录短期记忆的实现关键在于容量管理和信息保真。你不能让无关紧要的寒暄挤占了关键指令的空间。我采用了一种“滚动窗口智能摘要”的混合策略固定长度滚动窗口使用一个双端队列deque保存最近的N轮对话例如10轮。这是最快的信息来源。溢出摘要机制当对话轮数超过N或者累计的token数接近模型上下文窗口上限如80%时触发摘要流程。将队列中最早或最不关键的几轮对话取出。调用LLM生成一个简洁的段落来总结这几轮对话的核心事实和结论忽略问候语等无关细节。将这个摘要作为一个特殊的“系统消息”或“历史摘要消息”插入到当前对话历史的前部。这样重要的信息得以保留只是形式从原始对话变成了精炼的摘要。# 伪代码示例短期记忆管理类 class ShortTermMemory: def __init__(self, window_size10, llm_clientNone): self.message_queue deque(maxlenwindow_size) # 原始消息队列 self.condensed_history [] # 摘要历史 self.llm llm_client def add_message(self, role, content): self.message_queue.append({role: role, content: content}) self._check_and_condense() def _check_and_condense(self): if len(self.message_queue) self.max_window: # 取出最老的2-3轮进行摘要 to_condense [self.message_queue.popleft() for _ in range(2)] summary self._call_llm_for_summary(to_condense) self.condensed_history.append(summary) def get_context_for_llm(self): # 组合摘要历史和近期原始对话作为最终上下文 return self.condensed_history list(self.message_queue)实操心得摘要的触发条件和摘要的粒度需要仔细调优。过于频繁的摘要会导致信息损失而摘要过于简略则失去意义。一个实用的技巧是让LLM在摘要时特别关注“用户陈述的事实”、“达成的共识”和“待办事项”这比总结整个对话流程更有用。3.2 长期记忆的实现向量检索与结构化存储长期记忆是Agent的“知识大脑”设计重点在于如何高效存储和检索语义信息。我设计了双存储结构向量存储 (Chroma)存储记忆片段的嵌入向量。每个向量关联一个唯一的memory_id。元数据存储 (SQLite)存储记忆片段的详细信息。memory_id(主键与向量ID对应)user_id(用户标识)content(记忆文本如“用户最喜欢的颜色是蓝色”)memory_type(枚举fact/preference/event_summary)source_session(来源会话ID)timestamp(创建时间)access_count(被检索次数)last_accessed(最后检索时间)记忆的“写入”流程从短期记忆沉淀这不是自动进行的而是在对话自然停顿或任务完成时由Agent主动触发。例如在帮助用户完成酒店预订后Agent可以启动一个子流程分析最近的对话历史。调用LLM提问“从上述对话中有哪些关于用户的长期事实如姓名、地址、稳定偏好如房型、楼层要求或值得记录的总结性事件需要保存到长期记忆”LLM会以结构化格式如JSON输出识别出的记忆片段。将每个片段的内容通过Embedding模型转换为向量。将向量存入Chroma同时将元数据存入SQLite。记忆的“读取”流程工作记忆检索这部分是工作记忆的核心下文会详述。简言之就是根据当前查询从Chroma中找出最相关的几个记忆片段。注意事项长期记忆的“垃圾回收”同样重要。需要定期清理那些access_count极低、且timestamp非常久远的记忆片段或者对相似记忆进行去重合并防止数据库无限制膨胀影响检索效率。3.3 工作记忆的引擎LangGraph状态机工作记忆是整个系统的“调度中心”。我用LangGraph来实现它因为它能清晰地将检索、评估、决策、执行等步骤定义成节点并通过状态流来控制。定义一个核心的“状态”对象from typing import TypedDict, List, Annotated import operator class AgentState(TypedDict): # 输入 user_input: str # 短期记忆 conversation_history: List[dict] # 包含原始消息和摘要 # 工作记忆动态部分 retrieved_memories: List[str] # 从长期记忆中检索到的原始文本 relevant_memories: List[str] # 经过LLM筛选后的关键记忆 # 输出 llm_response: str构建工作记忆图图的节点大致包括retrieve_memories节点接收当前user_input和conversation_history生成搜索查询。这里可以用LLM将当前对话意图改写为更适合检索的查询词。然后用这些查询词去Chroma中做向量相似性搜索将结果记忆文本存入state[‘retrieved_memories’]。filter_memories节点检索到的记忆可能很多比如10条。此节点调用LLM基于当前任务评估每条记忆的相关性进行排序、去重并选择Top-K比如3条最关键的存入state[‘relevant_memories’]。generate_response节点这是核心推理节点。它将user_input、conversation_history和relevant_memories组合成一个最终的Prompt发送给LLM生成Agent的回复存入state[‘llm_response’]。同时它可能还会判断是否需要触发“记忆写入”流程。update_conversation_history节点将用户输入和AI回复作为新的一轮对话添加到短期记忆管理中。这些节点通过边连接可以设计条件逻辑。例如如果retrieved_memories为空可以直接跳转到generate_response或者如果LLM的回复中包含确认完成某项任务的信息可以并行触发一个save_to_long_term_memory节点。实操心得在filter_memories节点给LLM的指令非常关键。我常用的Prompt是“你是一个信息筛选助手。以下是当前用户的问题和对话背景[...]。以下是从知识库中检索到的一些可能相关的记忆片段[...]。请严格根据当前问题的需要选出最直接相关、最可靠的记忆最多3条并忽略那些模糊、过时或无关的信息。直接输出选中的记忆片段的原文用编号列出。”4. 端到端整合与系统流程剖析让我们通过一个完整的用户交互场景把短期、长期、工作记忆串联起来看看数据是如何流动的。场景用户第二次咨询旅行建议。用户输入“我又来了还记得我上次说想去个温暖的海边度假吗现在有什么好推荐”工作记忆启动 - 检索系统将当前用户输入和短期记忆可能包含本次会话的问候作为上下文。retrieve_memories节点运行。它可能生成类似“用户 海边 温暖 度假 历史偏好”的查询向量。向量数据库返回Top-5相关记忆片段例如“用户于两周前咨询过冬季温暖海岛目的地。”“用户偏好安静、开发度不高、拥有白色沙滩的海岛。”“用户预算范围在人均每日1000元左右。”“用户护照有效期至2026年。”这是一个更早的记忆“用户不喜欢长途飞行超过10小时。”工作记忆 - 筛选filter_memories节点运行。LLM根据当前问题“现在有什么好推荐”进行判断。记忆1历史咨询和记忆2具体偏好高度相关。记忆3预算相关但可能不是推荐目的地的首要因素保留。记忆4护照与当前推荐目的地无关过滤掉。记忆5飞行时间相关保留。最终记忆1,2,3,5被选为relevant_memories。工作记忆 - 生成响应generate_response节点将以下内容组合成Prompt系统指令“你是一个旅行顾问根据用户历史和偏好提供建议。”相关长期记忆[记忆1,2,3,5的文本]短期对话历史[“用户我又来了...”]当前用户问题。LLM基于这些丰富的上下文生成个性化回复“当然记得您上次提到了喜欢安静、白沙滩且飞行时间短于10小时的温暖海岛。结合您的预算我建议可以考虑一下菲律宾的巴拉望或者马来西亚的刁曼岛。它们目前正值旱季天气晴朗而且相对小众...”短期记忆更新将这一轮QA加入短期记忆队列。长期记忆的潜在更新在此轮对话结束后系统可能触发记忆沉淀流程。LLM可能会判断“用户再次确认了对安静、短程飞行海岛的偏好”这一信息可以作为对原有偏好记忆的一次强化或者作为一个新的事件总结“用户于X月X日再次咨询并接受了巴拉望和刁曼岛的推荐”存入长期记忆。这个流程展示了记忆体系如何让Agent表现出连续性和个性化。如果没有长期记忆Agent每次都会从一个“空白”状态开始无法提供基于历史的服务。5. 性能优化与高级技巧实现基础功能后要让它高效、可靠还需要一些优化技巧。5.1 检索优化超越简单的向量搜索混合检索 (Hybrid Search)单纯向量搜索可能受限于Embedding模型的质量。可以结合关键词搜索如BM25。例如对于“预算1000元”这种精确数字关键词搜索更有效。我们可以同时进行向量检索和关键词检索然后对结果进行重排序。查询扩展 (Query Expansion)让LLM基于原始用户问题生成多个相关的查询变体。例如对于“温暖海边”可以扩展出“热带海岛”、“冬季度假胜地”、“阳光海滩”等然后用这组查询去并行搜索合并结果能大大提高召回率。元数据过滤在向量检索时可以附带过滤条件。例如user_id当前用户ANDmemory_typepreference。这能确保检索到的记忆不仅语义相关而且在业务逻辑上也有效。Chroma和Pinecone都支持带过滤的搜索。5.2 记忆的维护与演化记忆强度与衰减可以引入类似“艾宾浩斯遗忘曲线”的简化模型。每个记忆有一个“强度”值每次被成功检索并利用即出现在relevant_memories中并最终贡献了高质量回复其强度增加。随着时间的推移强度缓慢衰减。定期清理强度低于阈值的记忆。这能让记忆系统“用进废退”。记忆融合与去重定期扫描长期记忆让LLM识别内容相似或重复的记忆片段例如“用户喜欢狗”和“用户养了一只金毛”并自动合并成一个更完整、更简洁的新记忆删除旧记忆。记忆抽象与泛化当某个特定事实如“用户2023年去了巴黎”出现多次或者与更广泛的模式如“用户喜欢欧洲文化旅行”相关联时可以尝试让LLM生成一个更抽象、更上层的记忆“用户对欧洲旅行有浓厚兴趣”并将具体事实作为支撑证据。这能节省空间并提升推理能力。5.3 工程化考量异步操作记忆检索、LLM调用都是I/O密集型操作。务必使用异步Async编程避免阻塞主线程。LangChain/LangGraph对异步有良好支持。缓存策略对于高频但不变的用户信息如用户名可以在内存中设置缓存避免每次对话都去向量数据库查询。监控与评估需要建立监控指标例如记忆检索命中率、检索到的记忆被LLM判定为相关的比例、用户对个性化服务的满意度可通过后续对话情感或明确反馈衡量。这些数据是迭代优化记忆系统的关键。6. 常见问题与实战排坑记录在实际开发中我遇到了不少坑这里分享出来希望能帮你节省时间。问题1检索出来的记忆不相关甚至干扰LLM判断。排查首先检查Embedding模型是否合适。对于中文场景使用针对中文优化的模型如BGE通常比通用英文模型更好。其次检查存入长期记忆的“记忆片段”质量。如果存入的是大段未经提炼的对话检索噪音必然大。解决强化“记忆写入”时的提炼环节。设计更精细的Prompt让LLM提取纯粹的事实、偏好或事件总结而不是存对话片段。例如Prompt可以是“请仅提取一句客观的、可长期保存的事实或用户陈述的明确偏好。”问题2上下文token数增长过快成本激增。排查短期记忆的滚动窗口是否太小是否过度依赖原始长对话而缺少摘要工作记忆检索时是否将过多的relevant_memories塞进了Prompt解决更积极地使用摘要。不仅对溢出的历史做摘要也可以定期如每5轮对话对全部短期记忆做一次轻量级总结然后清空原始队列只保留摘要。在filter_memories节点严格限制输出数量如最多2条。并让LLM在筛选时不仅输出原文还可以输出一个更简短的“一句话概括”用这个概括代替原文放入Prompt能极大节省token。问题3Agent变得“固执”或“矛盾”因为长期记忆中存在过时或冲突的信息。排查用户偏好可能改变如以前喜欢咖啡现在喜欢茶。如果系统只是不断添加新记忆而不更新旧记忆就会产生冲突。解决实施记忆版本管理当检测到新记忆与旧记忆明显冲突时例如LLM判断“用户现在喜欢茶”和“用户过去喜欢咖啡”指向同一属性可以标记旧记忆为“过时”或将其强度大幅降低。新记忆覆盖旧记忆。在Prompt中增加冲突解决指令在给LLM的最终Prompt里加入一句“如果提供的背景信息中存在矛盾请以最新、最具体的信息为准并可以委婉地向用户确认。”问题4系统响应延迟明显增加。排查瓶颈通常出现在向量检索或LLM调用环节。解决向量检索确保Chroma数据库有索引。限制返回结果数量如k5。考虑使用更快的本地Embedding模型。LLM调用对于filter_memories这类对创造力要求不高的任务使用速度更快的模型如GPT-3.5-Turbo。将多个可以并行的LLM调用如生成查询词和筛选记忆改为异步并行。构建AI Agent的记忆体系是一个从简单到复杂、不断迭代的过程。我的体会是一开始不必追求完美的三层架构和复杂的记忆演化算法。从实现一个基于向量数据库的、最简单的“长期记忆”检索开始让它能回答“你记得我之前说过XXX吗”这个问题就已经能带来用户体验的质的飞跃。在此基础上再逐步引入短期记忆的容量管理、工作记忆的智能筛选最终形成一个有机的整体。这个过程中最重要的不是技术的复杂度而是对Agent交互场景的深度理解以及持续地基于真实用户反馈进行优化。
返回列表