AI智能体长期记忆系统:三层架构设计与工程实践

📅 2026/8/25 18:35:47
AI智能体长期记忆系统:三层架构设计与工程实践
1. 项目概述为什么AI智能体需要“长期记忆”如果你玩过早期的AI聊天机器人或者用过一些基础的智能体框架大概率会遇到一个让人抓狂的问题聊着聊着它就把之前聊过的事情给忘了。你告诉它你叫张三是个程序员喜欢Python。过了几轮对话你再问它“我是做什么的”它可能一脸茫然或者开始胡编乱造。这就是典型的“短期记忆”或“上下文窗口”限制问题。对于构建真正能辅助工作、处理复杂任务的AI智能体来说这种“失忆症”是致命的。想象一下你希望训练一个帮你处理日常邮件的智能体。它需要记住你的邮件偏好、常用联系人、处理过哪些类型的邮件以及你的回复风格。如果每次对话它都从零开始那它永远无法成为你的得力助手。这就是“长期记忆”要解决的核心痛点让AI智能体能够跨越单次会话的界限记住关键的用户信息、历史交互和任务上下文从而提供连贯、个性化且真正有用的服务。最近一个名为Hermes Agent的开源项目引起了我的注意。它没有选择在单一的记忆机制上做文章而是提出了一套三层记忆体系试图系统性地解决AI智能体的“失忆”问题。这听起来不像是一个简单的技术补丁更像是在为智能体构建一个类似人类的记忆系统。今天我就结合自己的实践来深度拆解这套体系的设计思路、实现细节以及在实际部署中可能遇到的“坑”。2. Hermes Agent三层记忆体系设计思路拆解Hermes Agent的三层记忆体系其核心思想是模仿人类记忆的层次结构瞬间的、短期的和长期的。它不是简单地把所有对话记录都存进一个向量数据库而是根据信息的性质、重要性和使用频率进行分层存储和管理。2.1 第一层工作记忆Working Memory这相当于智能体的“大脑前台”或“思维缓存”。它的生命周期最短通常只存在于单次任务执行或一轮对话的上下文中。功能定位存储当前任务执行的即时状态、中间结果、工具调用参数、以及从长期记忆中提取出来的、与当前任务高度相关的片段信息。你可以把它理解为程序运行时的堆栈和寄存器。技术实现通常直接利用大语言模型LLM本身的上下文窗口Context Window。例如在提示词Prompt中我们会把当前用户指令、系统指令、以及从长期记忆中检索到的相关“记忆片段”一起喂给模型。Hermes Agent可能会通过精心的Prompt工程将这部分信息结构化地组织在上下文中。设计考量这一层的目标是“快”和“准”。它不负责永久存储只负责为当前推理提供最直接、最相关的信息输入。设计难点在于如何高效地从下层记忆中提取精准信息并避免无关信息污染当前上下文导致模型注意力分散。2.2 第二层短期记忆Short-term Memory这一层可以类比为人类的“短期记忆”或“最近经历”。它保存了最近一段时间内例如过去几次会话、几天内发生的交互历史。功能定位记录完整的对话历史、任务执行日志、用户临时的偏好声明等。当用户说“就像上次那样处理”时智能体需要从这里找到“上次”的具体情况。技术实现通常采用传统的数据库如SQLite、PostgreSQL或键值存储如Redis来保存结构化的对话记录。每条记录可能包含时间戳、会话ID、用户消息、智能体回复、使用的工具、消耗的Token数等元数据。设计考量短期记忆需要平衡“容量”和“访问速度”。它比工作记忆持久但又不像长期记忆那样需要复杂的语义检索。它的数据结构更规整便于按时间、会话等维度进行查询和回溯。一个常见的策略是设置滚动窗口只保留最近N条记录或N天内的记录避免数据无限膨胀。2.3 第三层长期记忆Long-term Memory这是整个体系的核心也是实现“不再失忆”承诺的关键。它旨在存储那些需要被持久化、并在未来各种可能场景下被回想起来的知识。功能定位存储用户的个人信息如姓名、职业、偏好、智能体学到的领域知识、完成的重要任务总结、以及从历史交互中提炼出的通用模式或规则。技术实现这是最复杂的一层通常结合多种技术向量数据库核心如Chroma、Weaviate、Qdrant、Milvus。将文本信息如“用户张三是一名后端工程师擅长使用Go和Docker”通过嵌入模型Embedding Model转化为高维向量Vector并存储起来。当需要回忆时将当前查询如“用户擅长什么技术”也转化为向量在向量空间中进行相似度搜索找到最相关的记忆片段。这是实现“语义搜索”和“模糊回忆”的基础。图数据库可选但强大如Neo4j。用于存储实体用户、项目、概念之间的关系擅长、参与、喜欢。当记忆不再是孤立的片段而是相互关联的网络时智能体可以进行更复杂的推理例如“用户喜欢Go那他对云原生和微服务架构可能也感兴趣”。传统数据库用于存储需要精确查询的结构化信息比如用户的账户ID、配置项等。设计考量长期记忆的设计难点在于“写什么”和“怎么读”。记忆的写入Memorization不是所有对话都值得进入长期记忆。需要设计“记忆提炼”机制。这通常是一个由LLM驱动的过程定期或在对话关键节点让LLM分析最近的交互判断是否有值得长期保存的信息并将其总结、结构化后存入向量库或图库。例如将一段关于技术讨论的对话总结为“用户掌握了Kubernetes的Pod调度原理”这样一个知识断言。记忆的读取Recall当新任务到来时如何从海量长期记忆中检索出最相关的部分这涉及到检索策略如基于向量相似度的语义检索、基于时间或元数据的过滤检索、结合多种检索器的混合检索以及检索结果的重排序Reranking确保返回的信息既相关又精炼。这三层并非孤立而是协同工作的。一个典型的流程是用户提出新请求 - 从长期记忆中语义检索相关历史 - 结合短期记忆中的近期上下文 - 将所有相关信息组织进工作记忆即当前Prompt- LLM基于此生成回复或执行动作 - 将本次交互摘要后决定是否及如何更新长/短期记忆。3. 核心细节解析与实操要点理解了设计思路我们来看看在实现这套体系时有哪些必须关注的魔鬼细节。3.1 记忆的粒度与编码存“原始对话”还是存“知识摘要”这是长期记忆构建的第一个关键决策。直接存储每轮对话的原始文本Raw Text是最简单的但问题很大信息冗余对话中有大量问候语、重复确认、无关细节。噪声干扰不利于精准检索。存储低效占用大量向量空间。Hermes Agent更可能采用的也是我实践中强烈推荐的方式是存储结构化的知识摘要Structured Summary。具体操作在对话的某个节点例如一个任务结束、或每10轮对话后触发一个“记忆提炼”步骤。用一个专门的LLM调用可以是同一个模型但使用不同的Prompt对刚发生的这段交互进行分析。Prompt示例你是一个记忆提炼助手。请分析以下对话片段并提取出值得长期记忆的、关于用户【张三】的客观事实、偏好或技能。请以简洁、结构化的断言形式输出每条断言独立一行。 示例输出 - 用户张三的职业是后端开发工程师。 - 用户张三目前正在学习Kubernetes。 - 用户张三不喜欢冗长的会议。 对话片段 [此处插入最近的若干轮对话历史]将LLM输出的这些结构化断言通过嵌入模型编码成向量存入向量数据库。每条断言作为一个独立的记忆向量。这样记忆的粒度是“一个事实点”检索时更精准也更容易进行后续的知识关联和推理。注意这个提炼过程本身消耗Token并且有延迟。需要在“记忆质量”和“系统开销”之间做权衡。通常对于任务型智能体在任务边界处进行提炼是性价比最高的。3.2 检索策略如何从记忆海洋中精准打捞当智能体需要“回忆”时简单的向量相似度搜索可能不够。假设用户问“我上周说的那个关于数据库的项目是什么” 如果记忆里存的是摘要“用户讨论了数据库分库分表方案”向量相似度搜索可能能匹配上。但如果用户问“把我所有和‘项目’相关的事情都告诉我”就需要更复杂的检索。混合检索Hybrid Retrieval策略是更优解语义检索向量搜索处理模糊查询如“我之前说的优化方法”。关键词检索全文搜索/元数据过滤处理精确查询如“时间:上周”“标签:项目”。这需要你在存储记忆时额外保存一些元数据字段如timestamp,entity涉及实体如“项目A”topic主题如“数据库优化”。时间衰减检索给更近的记忆更高的权重因为用户通常更关心最近发生的事情。在Hermes Agent或类似框架中你可能会看到它使用像LangChain的Retriever或LlamaIndex的QueryEngine来组合这些检索器。核心代码逻辑可能类似于# 伪代码示例 from typing import List from your_vector_store import VectorStoreRetriever from your_keyword_store import KeywordRetriever class HybridMemoryRetriever: def __init__(self, vector_retriever: VectorStoreRetriever, keyword_retriever: KeywordRetriever): self.vector_retriever vector_retriever self.keyword_retriever keyword_retriever def get_relevant_memories(self, query: str, filters: dict None) - List[Memory]: # 并行或顺序执行多种检索 vector_memories self.vector_retriever.search(query, top_k5) keyword_memories self.keyword_retriever.search(query, filtersfilters, top_k5) # 结果融合与去重例如基于记忆ID all_memories merge_and_deduplicate(vector_memories, keyword_memories) # 可选使用一个轻量级Reranker模型对结果重排序 reranked_memories rerank(query, all_memories) return reranked_memories[:5] # 返回最相关的Top K个记忆3.3 记忆的更新与遗忘智能体也需要“新陈代谢”记忆不是只增不减的。无效、过时或冲突的记忆会污染检索结果。因此需要设计记忆的更新和遗忘机制。冲突解决当新提炼的记忆与旧记忆冲突时例如旧记忆说“用户喜欢咖啡”新记忆说“用户现在改喝茶了”如何处理简单的策略是“以新为准”直接覆盖。更复杂的策略是引入置信度或来源让LLM在需要时进行推理判断。记忆衰减与归档对于短期记忆可以采用基于时间的滚动窗口自动删除。对于长期记忆可以设计“访问频率”或“最后访问时间”机制。长期不被触及的记忆可以将其移动到“归档”区降低其在主检索池的权重甚至转移到冷存储而不是直接删除以备极端情况下的全量回忆。主动遗忘Forgetting应提供用户接口允许用户明确指出“请忘记关于XXX的事情”。这涉及到从向量库中删除对应的向量条目是一个伦理和功能上都重要的特性。4. 基于Hermes Agent思路的实操搭建指南虽然我无法获取Hermes Agent闭源部分的精确代码但基于其公开的三层架构理念我们可以用主流开源工具栈搭建一个具有类似能力的智能体系统。这里我以Python生态为例展示一个简化版的实现路径。4.1 环境准备与工具选型核心组件LLM用于对话、记忆提炼、推理。可选OpenAI API、或本地部署的Ollama运行Llama 3、Qwen等、vLLM等。向量数据库存储长期记忆的核心。Chroma轻量、易用或Qdrant性能强、功能全是很好的起点。传统数据库存储短期记忆和元数据。SQLite开发测试或PostgreSQL生产环境。应用框架LangChain或LangGraph。它们提供了构建Agent所需的工作流、工具调用、记忆管理等高级抽象能极大简化开发。Hermes Agent很可能也基于类似的框架构建。安装基础依赖pip install langchain langchain-community langchain-chroma langgraph # 根据你选的LLM和向量库安装对应的集成包 pip install chromadb qdrant-client openai4.2 构建三层记忆系统的代码骨架以下是一个高度简化的概念性代码结构展示了如何将三层记忆整合到一个LangChain/LangGraph的智能体中。import uuid from datetime import datetime from typing import List, Optional from langchain.schema import BaseMessage, HumanMessage, AIMessage from langchain.vectorstores import Chroma from langchain.embeddings import OpenAIEmbeddings # 或用本地模型 from langchain.memory import ConversationBufferMemory, SQLChatMessageHistory from pydantic import BaseModel # ---------- 1. 定义数据结构 ---------- class LongTermMemoryItem(BaseModel): id: str content: str # 结构化的知识摘要如“用户是Python开发者” embedding: Optional[List[float]] None metadata: dict # 如 {entity: user, topic: skill, timestamp: ..., source_session: xxx} created_at: datetime last_accessed_at: datetime # ---------- 2. 初始化各层存储 ---------- # 短期记忆使用SQLite存储对话历史 short_term_memory_store SQLChatMessageHistory( session_iduser_session_001, connection_stringsqlite:///./chat_history.db ) # 长期记忆使用Chroma向量库 embedding_model OpenAIEmbeddings(modeltext-embedding-3-small) # 或本地嵌入模型 vector_store Chroma( collection_namelong_term_memories, embedding_functionembedding_model, persist_directory./chroma_db ) # ---------- 3. 记忆管理器类核心 ---------- class ThreeLayerMemoryManager: def __init__(self, user_id: str): self.user_id user_id self.short_term_store short_term_memory_store self.long_term_vector_store vector_store def add_to_short_term(self, message: BaseMessage): 添加消息到短期记忆对话历史 self.short_term_store.add_message(message) def get_short_term_history(self, k: int 10) - List[BaseMessage]: 获取最近k条短期记忆 all_messages self.short_term_store.messages return all_messages[-k:] def _summarize_for_long_term(self, recent_messages: List[BaseMessage]) - List[str]: 调用LLM将近期对话提炼成长期记忆断言简化示例 # 这里应该构造一个Prompt让LLM进行总结提炼 # 例如f请从以下对话中总结关于用户{self.user_id}的长期事实\n{recent_messages} # 调用LLM... # 假设返回一个断言列表 fake_assertions [用户是一名全栈开发者, 用户最近在关注AI智能体技术] return fake_assertions def update_long_term_memory(self): 在适当时机如对话轮次达到阈值、任务结束时触发更新长期记忆 recent_messages self.get_short_term_history(k20) if not recent_messages: return # 步骤1提炼记忆 memory_assertions self._summarize_for_long_term(recent_messages) # 步骤2存入向量数据库 for assertion in memory_assertions: memory_item LongTermMemoryItem( idstr(uuid.uuid4()), contentassertion, metadata{ user_id: self.user_id, source: conversation_summary, timestamp: datetime.now().isoformat() }, created_atdatetime.now(), last_accessed_atdatetime.now() ) # 生成嵌入并添加 self.long_term_vector_store.add_texts( texts[assertion], metadatas[memory_item.metadata], ids[memory_item.id] ) print(f已更新长期记忆新增{len(memory_assertions)}条断言。) def recall_from_long_term(self, query: str, k: int 3) - List[str]: 从长期记忆中检索相关记忆 docs self.long_term_vector_store.similarity_search(query, kk) return [doc.page_content for doc in docs] # ---------- 4. 在Agent工作流中集成记忆 ---------- # 假设我们有一个简单的LangChain Agent from langchain.agents import AgentExecutor, create_react_agent from langchain.tools import Tool from langchain.prompts import PromptTemplate # 初始化记忆管理器 memory_manager ThreeLayerMemoryManager(user_idzhangsan) # 定义一个“回忆”工具供Agent在需要时主动调用 def recall_memory(query: str) - str: 一个工具函数让Agent能主动查询长期记忆。 memories memory_manager.recall_from_long_term(query, k2) if memories: return f根据我的记忆{; .join(memories)} else: return 我没有找到相关的长期记忆。 tools [ Tool( nameRecallMemory, funcrecall_memory, description当你需要回忆关于用户的长期信息时使用此工具。输入是一个查询字符串。 ), # ... 其他工具 ] # 构建Prompt将记忆上下文融入 prompt_template PromptTemplate.from_template( 你是一个有帮助的助手拥有与用户互动的记忆。 **关于用户的长期记忆摘要** {long_term_memory_context} **最近的对话历史** {chat_history} **当前问题** {input} 请根据以上信息思考并回答问题。你可以使用工具。 ) # 在每次Agent调用前动态准备上下文 def prepare_context(user_input: str): # 1. 从长期记忆中检索相关背景 lt_context memory_manager.recall_from_long_term(user_input) or [无相关长期记忆] lt_context_str \n.join(lt_context) # 2. 获取短期对话历史 st_history memory_manager.get_short_term_history(k5) history_str \n.join([f{msg.type}: {msg.content} for msg in st_history]) # 3. 将当前用户输入添加到短期记忆 memory_manager.add_to_short_term(HumanMessage(contentuser_input)) return { long_term_memory_context: lt_context_str, chat_history: history_str, input: user_input } # Agent执行流程简化示意 user_query 我之前跟你提过我擅长什么编程语言吗 context prepare_context(user_query) # 将context填充到prompt并调用Agent... # agent_response agent_executor.invoke(context) # 将Agent的回复也添加到短期记忆 # memory_manager.add_to_short_term(AIMessage(contentagent_response)) # 定期或在对话合适节点触发长期记忆更新 # if some_condition: # memory_manager.update_long_term_memory()这个示例展示了核心的集成逻辑一个中心化的MemoryManager管理三层存储在Agent运行前通过prepare_context函数组装工作记忆Prompt上下文并提供工具让Agent能主动查询长期记忆。4.3 部署与配置心得嵌入模型的选择至关重要长期记忆的检索质量很大程度上取决于嵌入模型。如果使用本地部署text-embedding-3-small的量化版、BGE、M3E等都是不错的选择。务必确保嵌入模型与你的主要语言中文/英文匹配。向量数据库的持久化与备份Chroma的persist_directory参数确保数据落盘。生产环境务必定期备份chroma_db目录。对于Qdrant要配置好快照和持久化卷。记忆提炼的触发策略不要每轮对话都提炼开销太大。可以考虑a) 定时触发如每30分钟b) 基于对话轮次触发如每10轮c) 基于事件触发如用户说“记住这个”或任务标记完成时。元数据Metadata是宝藏在向向量库存储记忆时尽可能丰富元数据字段user_id,session_id,topic,entity_type,confidence等。这能为后续的混合检索和精细化管理提供巨大便利。5. 常见问题与排查技巧实录在实际搭建和运行这类记忆系统时我踩过不少坑。这里分享几个典型问题和解决思路。5.1 问题检索结果不相关或噪声太大症状用户问“我的爱好”返回的记忆却是“用户昨天吃了饺子”。排查与解决检查嵌入模型首先确认你的嵌入模型是否适合你的文本领域。用一些标准句子测试其相似度计算是否合理。优化记忆写入内容问题很可能出在“记忆提炼”环节。如果存入向量库的是冗长的原始对话噪声必然多。强化你的总结提炼Prompt严格要求LLM输出简洁、客观的事实断言。可以增加示例Few-shot来引导格式。调整检索策略单纯靠向量相似度可能不够。引入元数据过滤。在检索时除了语义查询附加过滤器如metadata[entity_type] hobby。或者实现混合检索结合关键词匹配。尝试重排序Reranking在初步检索出Top K例如10个结果后使用一个更精细但开销大的重排序模型如BGE-Reranker对结果再次排序取Top 3能有效提升精度。5.2 问题记忆冲突或信息过时症状用户说“我现在不喜欢吃辣了”但智能体依然根据旧记忆推荐川菜馆。排查与解决实现记忆版本管理或置信度为每条长期记忆增加version或confidence_score字段。当新提炼的记忆与旧记忆语义高度相似但内容相反时可以提升新记忆的置信度或让旧记忆失效。设计记忆刷新机制为记忆条目增加last_accessed_at最后访问时间和access_count访问次数。在检索时可以引入时间衰减因子让更近、更常被访问的记忆有更高权重。对于长期未被访问且置信度低的记忆可以移至“归档”区。提供用户修正接口这是最直接有效的方法。当智能体引用一条记忆时可以提供“这条信息已过时”的反馈按钮。点击后系统可以标记或删除该条记忆。5.3 问题系统延迟明显增加症状每次对话响应变慢尤其是开启记忆功能后。排查与解决异步化记忆操作记忆的写入尤其是LLM总结提炼和读取向量检索是比较耗时的I/O操作。务必将其设计为异步任务不要阻塞主对话线程。例如使用asyncio或消息队列将记忆更新任务丢到后台执行。缓存热点记忆对于高频使用的用户信息如用户名、基础偏好可以在内存或Redis中设置缓存避免每次对话都去查询向量库。限制检索范围不要每次都进行全库检索。利用user_id等元数据严格过滤只检索当前用户的记忆。控制返回的记忆条数Top KK值不宜过大通常3-5条足以提供上下文。评估向量数据库性能如果数据量很大10万条Chroma可能遇到性能瓶颈。考虑升级到Qdrant、Weaviate或Milvus等为大规模向量搜索优化的专业数据库。5.4 问题记忆提炼消耗大量Token成本高症状API调用费用激增分析发现主要是记忆提炼的LLM调用导致的。解决降低提炼频率不要每轮对话都提炼。根据业务逻辑在自然断点如话题结束、任务完成进行。使用更小的模型进行提炼记忆提炼任务对推理能力要求低于主对话任务。可以尝试使用更小、更便宜的模型如GPT-3.5-Turbo来处理总结提炼。批量处理积累一定量的对话记录后例如一个会话结束后进行一次性的批量总结比多次小总结可能更高效。设定提炼预算为每个用户或每个会话设置一个Token预算用于记忆相关操作防止滥用。构建一个有效的长期记忆系统远不止是接上一个向量数据库那么简单。它涉及到对信息生命周期的全面管理从感知、筛选、编码、存储到检索、更新和遗忘。Hermes Agent提出的三层体系提供了一个清晰的设计框架。在实际落地时你需要像设计一个数据产品一样仔细权衡每一层的容量、速度、成本和准确性。从我自己的实践来看最大的挑战往往不在技术实现而在产品逻辑上到底什么信息值得被记住以何种形式记住如何在尊重用户隐私的前提下提供个性化服务这些问题的答案需要你和你的用户共同去寻找。技术是骨架而对需求的理解和人性化的设计才是让智能体真正拥有“灵魂记忆”的关键。