Agent记忆系统实战:从上下文窗口到向量检索的分层架构

发布时间:2026/9/13 4:53:33
Agent记忆系统实战:从上下文窗口到向量检索的分层架构 我们先从一组真实的工程场景说起。我接触过不少 Agent 项目早期大家的做法都很一致用户问一句Agent 答一句最多把当前会话的上下文带上。跑 Demo 没问题一旦进入真实业务就露馅了——用户昨天刚说过我家里有两个小孩推荐行程要考虑儿童设施今天再问帮我安排周末活动Agent 像失忆了一样把所有信息重新问一遍。做客服的、做个人助理的、做知识库问答的都会被同一个问题卡住Agent 没有记忆就永远停留在聊天机器人的层次做不成真正的智能体。所以这篇实战文章我打算把 Agent 记忆系统这件事情彻底拆开讲。我会先解释清楚为什么记忆是 Agent 工程的刚需再给出一个可以落地的分层架构方案最关键的是我会把长期记忆的向量化存储、检索召回、读写策略这些核心环节连同代码实例和踩坑经验一并梳理出来。适合正在做 Agent 开发、想给自己的智能体加上跨会话记忆能力的工程师以及那些已经尝试过简单记忆方案但发现效果不理想、需要系统化思路的朋友。1. 为什么 Agent 需要记忆——无状态调用的致命短板1.1 上下文窗口不是记忆很多人刚接触 Agent 开发时会有一个直觉反应模型不是支持几十万 token 的上下文吗把聊天记录全塞进去不就有记忆了这个想法本身不算错但它把记忆和上下文长度混为一谈了。上下文窗口是什么它是模型单次推理时能看到的信息总量。你把 10 万 token 的历史对话全塞进去模型确实能知道之前聊过什么但这里有几个致命问题。第一是成本主流大模型的输入 token 是按量计费的每次请求都带 10 万 token一个月下来账单会非常难看。第二是噪声对话历史里充满了嗯好的谢谢这类无关信息真正的关键事实——用户的偏好、之前确认过的决策、尚未完成的任务——可能只占很小一部分让模型在大量噪声里找关键信息既浪费能力又容易出错。第三是策略缺失记忆不是简单回放历史而是要在合适的时间用合适的形式把合适的旧信息拿出来参与当前决策这需要一个管理机制而不是一股脑全塞进去。打个比方上下文窗口像一张桌子上能摆下的文件数量。记忆系统则不是桌面而是档案柜。你要的不是把档案柜里所有文件都摊在桌面上而是知道自己有哪些文件、放在哪、什么时候该去取哪一份。1.2 没有长期记忆的 Agent永远在重新认识用户我复盘过不少失败的 Agent 项目发现它们的交互模式几乎一模一样第一轮对话用户需要把背景信息完整讲一遍Agent 当时能理解、能回答。等到第二天用户再来Agent 又是全新的状态用户得再讲一遍。用户不是技术人员他们对这种体验的容忍度非常低。在他们看来昨天刚跟你说过的事今天你就不记得了这不是技术限制这就是产品做得不行。更隐蔽的问题是很多任务本身就是跨会话的。用户周一让 Agent 帮忙调研三个方向的竞品周三回来问上回那三个方向的调研结果里关于定价策略的部分帮我再展开讲讲。如果 Agent 不记得三个方向是哪些这个对话根本没法继续。没有记忆Agent 就只能完成单轮问答级别的任务永远做不了持续服务级别的产品。1.3 记忆失效带来的连锁反应我在一个客户项目里还观察到一个现象当 Agent 记忆功能不稳定时用户会逐渐养成过度描述的习惯——明明之前说过的信息每次都要刻意再强调一遍生怕 Agent 忘了。这直接导致对话变长token 消耗上升用户体验下降。可以说记忆系统的质量会从多个维度反噬整个 Agent 产品的核心指标。这里需要认识到的核心结论是长期记忆不是 Agent 的可选增强功能而是从玩具走向工具的分水岭。2. 记忆系统总体架构短期、长期与工作记忆的分层设计2.1 三种记忆的分工逻辑既然要在工程上实现记忆第一步不是写代码而是把记忆的类型分清楚。认知科学里把记忆分为感觉记忆、短期记忆、长期记忆Agent 工程可以借鉴这个思路但要从工程可实现的角度重新定义。我按自己项目中验证过的方案把 Agent 记忆拆成三层记忆层生命周期存储介质核心作用典型数据工作记忆单次推理过程Context window当前决策的临时信息当前用户输入、临时检索结果、中间推理步骤短期记忆单会话内分钟~小时级Redis / 内存维持多轮对话的连贯性本轮对话的完整消息序列、待办状态长期记忆跨会话天~月~年级向量数据库 结构化数据库跨会话记住用户特征与历史决策用户偏好、事实信息、项目历史、任务状态这个分层实践的意义在于每一层都有各自的存储成本和访问速度。工作记忆就是当下脑子在想的事短期记忆是这次聊天还没结束得记住刚才聊到哪了长期记忆是哪怕半年后用户再来我也知道他是什么样的人、关心什么事。2.2 为什么一定要先分层再整合我见过一些团队走了另一个极端为了省事把界面上能看到的历史全部通过接口捞出来也不管是哪个会话的统统塞进 Prompt。这种做法表面上是全量记忆实际上在真实业务里撑不过两个星期——历史数据膨胀得极快响应延迟和账单金额一起上涨而且不同会话之间的信息互相污染Agent 经常把 A 项目的信息当成 B 项目的来用。分层本质上是把记忆从数据堆积变成信息管理。每一层有独立的写入策略、存储策略、读取策略和过期策略。短期记忆负责会话内的连贯性长期记忆负责跨会话的持久性工作记忆则像一个高速缓存协调前两者与当前决策的关系。三者配合好了Agent 才能做到该记的记得住不该记的不乱记该忘的忘得掉。2.3 长期记忆内部还可以细分长期记忆本身也不是一个大杂烩。在实践中我习惯把长期记忆再分为三类每一类的存取方式都有差异情景记忆Episodic Memory记录发生过什么。比如2024年6月3日用户询问过上海出差住宿推荐。这类记忆偏事件性适合用时间线方式管理。语义记忆Semantic Memory记录用户是什么样的人。比如用户偏好安静的咖啡厅用户从事跨境电商行业。这类记忆是高度抽象和结构化的直接影响 Agent 的个性化表现。程序性记忆Procedural Memory记录之前怎么做的。比如处理退款时用户希望先确认再执行不要直接操作。这类记忆对 Agent 的行为策略进行调整。我个人在实操中最大的感受是情景记忆决定了 Agent 能回忆起什么语义记忆决定了 Agent 怎么理解用户程序性记忆决定了 Agent 怎么行动。三层都齐了长期记忆才算完整。3. 长期记忆的核心实现向量存储、摘要提取与检索召回3.1 记忆的写入不是存原文而是存入有意义的信息长期记忆的写入是最容易被低估的环节。很多第一次做记忆系统的开发者会把原始对话直接嵌入向量库这种做法在数据量小的时候似乎可行一旦数据量大起来检索质量会急剧下降。原因很简单原始对话里大部分内容没有长期保留价值而真正有长期价值的信息往往分散在不同的对话片段里直接存原文会导致关键事实被噪声淹没。我采用的方案是先抽取再存储。每一轮或每一段对话结束后由一个轻量级的记忆抽取模块通常是用 LLM 调用完成三件事事实抽取从对话中提取出可验证的、长期有效的信息比如用户公司有 50 人规模用户偏好 Vue 技术栈。偏好识别提取用户表达出的偏好和倾向比如用户不喜欢主动推销的回复风格。事态追踪判断当前对话中有没有未完成的任务、承诺或待办事项比如用户要求下周二前给出一版方案。抽取结果统一转化为结构化的记忆条目再进入存储层。这样做有一个额外的好处你可以对每一条记忆做审核、修改和删除记忆系统变成可维护的而不是一个只能追加的黑盒。3.2 存储选型向量库负责模糊回忆结构化库负责精确查证长期记忆的检索场景天然分成两类。一类是模糊回忆根据当前对话的语义找到相关度最高的记忆片段比如用户说上次那个安静的咖啡馆系统要在记忆里找安静咖啡馆这两个语义相关的条目。这类场景适合用向量数据库做语义检索。另一类是精确查证比如用户上个月 20 号提交的退款申请状态是什么这类场景用关键词或结构化条件一查就有不需要语义匹配。这类数据放在传统的关系型数据库或文档数据库里成本更低、查询更稳定。所以我的标准方案是双写向量数据库我常用 pgvector也可以用 Milvus、Chroma、Qdrant负责语义检索关系型数据库PostgreSQL或文档库MongoDB负责结构化存储。两条链路各有侧重点组合起来才能兼顾理解与精确。以下是一个典型的记忆条目在 PostgreSQL 中的表结构设计参考CREATE TABLE agent_memories ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), agent_id VARCHAR(64) NOT NULL, -- 哪个 Agent 的记忆 user_id VARCHAR(64) NOT NULL, -- 哪个用户的记忆 memory_type VARCHAR(16) NOT NULL, -- episodic / semantic / procedural content TEXT NOT NULL, -- 记忆的文本描述 importance REAL NOT NULL DEFAULT 0.5, -- 重要程度用于优先级衰减 access_count INTEGER NOT NULL DEFAULT 0, -- 被检索命中的次数 last_accessed_at TIMESTAMP DEFAULT NOW(), created_at TIMESTAMP DEFAULT NOW(), expires_at TIMESTAMP, -- 过期时间NULL 表示持久保留 metadata JSONB -- 额外的结构化元信息 ); CREATE INDEX idx_memories_user ON agent_memories(user_id);向量部分我通常直接用 pgvector 扩展把content字段的 embedding 存入同一个表这样省去维护两套存储的运维成本又能同时支持 SQL 条件过滤和向量相似度检索非常适合中小型 Agent 项目。3.3 检索召回让对的记忆在对的时候出现存储解决的是有没有检索解决的是能不能拿出来。我在实践中发现单纯靠向量相似度检索出来的记忆往往不是最该被用到的。原因在于对话的当前意图和长期记忆的关联不是只有一个维度。所以我的检索模块采取了多路召回 重排的策略第一路是向量召回把用户当前输入和对话上下文做 embedding从向量库捞出 top K 相似的记忆条目。第二路是结构化召回根据当前对话中出现的实体比如用户 ID、项目名、日期、地点从关系库里精确查证相关记录。第三路是重要性加权召回在向量分数基本接近的情况下优先返回importance更高、最近被访问过的记忆。这三路召回的结果合并后再按相关性和重要性的加权分数统一排序截取出每次送入 Prompt 的记忆上限我一般控制在 5~10 条太多会稀释模型注意力。这样做的好处是Agent 既不会漏掉关键事实也不会被海量记忆冲昏头脑。3.4 遗忘机制记忆系统要会做减法记忆系统的边界条件比想象中更容易被忽略——不会遗忘的记忆系统最后一定会变成噪声污染源。用户的偏好会变项目的事实会过时时间久远的记忆如果没有价值只会让检索结果越来越杂乱。我的策略是两套机制并行时间衰减给每条记忆设置expires_at每过一段时间复查一次把过期且没有再被访问的记忆自动清理或归档。这个时间窗口根据记忆类型不同而不同语义记忆如用户偏好保留期较长情景记忆如某次临时事件保留期较短。重要性机制被多次成功检索并参与回答的记忆importance会不断增加这意味着它被长期保留的优先级更高。反之长期不被命中的记忆会逐渐边缘化。简单说就是记忆的价值 信息本身的重要程度 × 被使用的频率系统根据这个价值来决定每条记忆的存留优先级。4. 一个可运行的实战示例带长期记忆的客服 Agent4.1 项目规划与模块划分前面讲的都是设计原则这部分我用一个具体例子把它串起来。假设我们要做一个带长期记忆的客服 Agent它的业务场景是用户可能是老客户会多次来咨询售后问题Agent 需要记住用户的设备型号、之前反馈过的故障、用户的沟通偏好以便提供连续、个性化的服务。我按以下模块来组织工程代码memory_writer.py对话结束后异步抽取记忆并写入存储。memory_reader.py每次用户新消息进来从存储中召回相关记忆。memory_store.py封装 PostgreSQL pgvector 的读写操作。agent.py主逻辑组织 Prompt把记忆注入系统提示词。整个项目的核心 API 其实只有两个一个是写入记忆一个是读取记忆但这两件事要做好后面藏了不少细节。4.2 记忆写入模块的实现写入模块的关键是什么时候抽和怎么抽。我采用的触发策略不是每一轮都抽而是当一轮对话结束时比如用户发出结束信号或者连续几轮没有新消息对整个对话片段做一次总结和抽取。这样可以避免对话中途反复抽取造成资源浪费。核心逻辑伪代码如下def write_memories_from_conversation(agent_id, user_id, messages): # messages 是本次对话的消息列表 extraction_prompt f 分析以下客服对话提取值得长期记住的信息。 要求 1. 用户的设备型号、购买时间、使用场景等事实信息 2. 用户表现出的偏好或沟通习惯 3. 尚未解决的工单或待办事项 4. 每条记忆请用一句话描述并标注类型: fact / preference / task 对话内容 {messages} 请以JSON数组输出格式[{{type: ..., content: ..., importance: 0.0-1.0}}] response llm_chat(extraction_prompt) memory_items parse_json(response) for item in memory_items: embedding get_embedding(item[content]) memory_store.insert( agent_idagent_id, user_iduser_id, memory_typeitem[type], contentitem[content], importanceitem[importance], embeddingembedding )这里要注意几个细节。第一抽取用的 Prompt 里的输出格式一定要给严格否则解析 JSON 时会频繁踩坑。第二importance字段很关键它不应该是模型拍脑袋给的我会额外做一个规则修正——如果内容里出现了具体的时间、金额、型号、联系方式这类高价值实体就把重要程度调高。第三抽取任务建议用异步队列执行不要阻塞用户的实时响应。4.3 记忆读取与 Prompt 注入读取端的核心逻辑就是把检索到的记忆转化成 Prompt 里的背景信息让模型在回答前先想起来。def build_system_prompt(user_id, current_query): # 召回记忆多路召回取 top 5 query_embedding get_embedding(current_query) memories memory_store.search( user_iduser_id, query_embeddingquery_embedding, top_k5, min_score0.75 # 低于相似度阈值的不要 ) memory_text \n.join(f- [{m.memory_type}] {m.content} for m in memories) system_prompt f 你是一个耐心专业的客服助手。 以下是关于用户的长期记忆请你在回答时充分利用这些信息 {memory_text} 规则 - 如果记忆中有用户之前提到过的设备和故障信息不要重复询问直接基于已知信息作答。 - 如果记忆中没有找到相关信息才向用户提问。 - 不要主动提及你有记忆系统或这些信息来自记忆显得自然即可。 return system_prompt我在这个模块里踩过的最大一个坑是——记忆不是越多越好而是越准越好。初版实现把召回阈值设得太低什么边角料都想让模型看到结果就是模型被大量低价值记忆干扰回答既啰嗦又不精准。后来我把min_score加到 0.75并且强制限制最多 5 条记忆回答质量反而明显上升。这背后的道理是大模型的长上下文是锦上添花但真正决定输出质量的永远是和当前任务最相关的几条关键信息。4.4 完整的主流程Agent 主流程其实就是三件事读记忆、组织 Prompt、对话。def handle_user_message(user_id, user_message, conversation_state): # 1. 从短期记忆中恢复当前会话状态 session short_term_memory.get_session(user_id) # 2. 从长期记忆中召回相关信息 system_prompt build_system_prompt(user_id, user_message) # 3. 组装请求调用大模型 response llm_chat( system_promptsystem_prompt, messagessession.history [{role: user, content: user_message}] ) # 4. 更新短期记忆 short_term_memory.append(session, user_id, user_message, response) # 5. 异步触发长期记忆抽取不阻塞 async_queue.submit(write_memories_from_conversation, user_id, session.history) return response从这段代码可以看出整条链路的执行原理是用户在某一轮发起请求时Agent 先查一下这个用户的档案长期记忆再结合当前会话的上下文短期记忆做出回答。客服场景中用户第一轮可能说我的 R5 系列显示器最近总是黑屏如果记忆里有该用户 2024 年 3 月购买过 R5 系列Agent 就不会再问您的设备型号是什么而是直接进入故障排查流程。用户的体感会从每次都要重复报修信息变成连续服务这就是记忆系统带来的产品价值。5. 记忆写入与读取的工程细节冲突、过期与隐私5.1 记忆冲突用户改主意了怎么办这是我在生产环境里遇到过最棘手的问题。用户第一次说我偏好邮件沟通Agent 记住了。两周后用户又说以后别发邮件了用微信通知如果记忆系统只做简单的追加写入库里就会同时存在两条互相矛盾的记忆。检索出来之后模型看到偏好邮件和偏好微信同时存在行为就会变得不可预测。我给这套机制加了一个轻量级的冲突处理模块写入新记忆之前先在库里搜索一下是否有同类型、主题相近的旧记忆。如果有就用新的覆盖旧的把旧条目标记为superseded而不是直接删除。这样历史可追溯但检索时永远不会把已经失效的旧记忆捞出来。冲突检测的粒度不需要做到完美只要在同类型preference对preference且向量相似度高的情况下做替换就能解决绝大多数实际问题。5.2 记忆过期的策略细化上一章讲了时间衰减这里补充一些具体的工程参数参考。不同记忆类型的过期策略我通常这样配置记忆类型默认有效期过期后处理说明用户事实fact180 天保留但降低优先级用户情况可能变化但旧信息仍可能有用用户偏好preference365 天保留偏好相对稳定且靠冲突覆盖机制纠偏临时事件episodic30 天自动清理过期的事件类记录很容易变成噪声待办任务task任务完成后 7 天标记完成并归档避免已完成任务反复被召回这套参数不是拍脑袋定的而是根据客服场景里用户信息平均半年到一年会有明显变化的经验值。不同业务的参数差异很大我给的数值适合做起点上线后要根据实际检索命中率和用户反馈去调。5.3 记忆隐私和权限边界记忆系统存了用户的信息就必须考虑权限管控。设计时的红线是Agent 的记忆不是开发者的私有数据池而是服务用户的功能设施用户应该有知情和控制的权利。在工程上至少要覆盖三件事第一记忆数据的访问权限必须严格隔离用户 A 的 Agent 永远不能检索到用户 B 的记忆这个要在存储层的查询条件里强制带上user_id不能只靠业务代码自觉。第二要给用户提供查看记忆和删除记忆的接口。我在一个产品里加了记忆管理页面用户能看到 Agent 记住了自己哪些信息也可以一键清除。这既符合隐私合规的要求也让用户对 AI 建立信任。第三敏感信息身份证号、银行卡号这类不建议进长期记忆就算业务上需要也要先做脱敏处理否则一旦数据库泄露风险不可控。5.4 记忆污染的防护不是所有对话都值得记住最后要强调的是不是所有对话内容都值得写入长期记忆。客服场景里用户可能说这东西真难用气死我了这是一句情绪宣泄不是值得长期记忆的偏好更不是用户的事实信息。如果模型把所有内容都抽成记忆库就会被污染后期检索质量会雪崩式下降。我的过滤策略是三个维度结合一是模型的抽取 Prompt 本身就做了语义筛选只输出符合fact / preference / task三类的内容二是设置抽取置信度阈值模型输出的importance低于 0.3 的条目默认进待审核区三是设置人工或规则兜底对某些明显不适合长期记忆的内容如包含咆哮、抱怨、零碎闲聊直接丢弃。这三个维度结合基本能把记忆库的信噪比控制在合理范围内。6. 评估指标与后续扩展思路6.1 如何给记忆系统的效果打分记忆系统做得好不好如果没有量化指标就很容易变成玄学。我在项目中总结了一套可操作的评价维度可以对应到测试用例上记忆命中率Recall在测试集里构造上次会话提到过、本次会话需要用到的用例看 Agent 能否成功召回相关记忆。我用一组 200 条的测试问题集统计召回率目标做到 90% 以上。事实一致性FaithfulnessAgent 回答中提到的我记得您之前……这类内容是否有凭有据是记忆里的真实信息还是模型自己编造的。这里要防的就是模型被记忆启发后产生的幻觉。干扰鲁棒性Anti-Noise故意往用户对话里插入无关信息检查 Agent 是否会被干扰误把无关内容写进记忆。时效性Freshness用户更新偏好之后Agent 是否在下一次对话中立即体现新偏好而不是仍然沿用旧信息。这四类指标我建议做成自动化回归测试每次改记忆模块都要跑一遍防止优化一个指标的同时搞砸了另外的指标。6.2 从单条记忆到记忆图谱的扩展上面讲的方案是扁平记忆条目 向量检索应对大多数业务场景已经够用。但如果你的 Agent 要处理的记忆量非常大且记忆之间的关系很复杂——比如用户既是项目发起人又是某个供应商的联系人同时还和历史工单有复杂关联——扁平记忆就不够用了。这时候我会建议演进到记忆图谱Memory Graph。记忆之间用关系链接起来比如用户A --[偏好]-- 安静环境 用户A --[拥有]-- 设备R5 设备R5 --[关联工单]-- 工单#12345图谱化带来的最大好处是支持多跳推理。扁平检索只能找到直接相关的记忆而图谱可以通过关系链推导出用户 A 咨询显示器故障而其工单 #12345 显示该故障可能是显卡兼容性问题这类隐藏关联。这个方向是 Agent 记忆系统的重要发展空间但实现复杂度比扁平方案高不少建议先把基础做扎实再考虑升级。6.3 记忆的自我反思与质量控制在工程实践中我认为记忆系统的天花板不在存储和检索技术而在质量管理。再先进的向量库也挽回不了垃圾记忆进、垃圾回答出的结局。所以我在项目后期投入了大量精力做记忆质量的闭环控制定期抽样检查记忆库里的条目看哪些是错误信息、哪些是过时信息用反馈循环来修正抽取模块的 Prompt。一个可行的做法是建立记忆质量周报统计本周写入的记忆条数、被命中的占比、被用户纠正的次数。如果发现某类记忆比如对用户情绪的判断经常被模型误抽取就去优化抽取 Prompt 的规则给模型加上更明确的负面清单。这套机制坚持下来记忆系统的效果曲线会持续向上而不是上线即巅峰、越用越乱。我从好几个项目里得到的一个一致的体会是Agent 记忆系统80% 的价值来自踏踏实实的数据管理20% 来自花哨的算法。做好分层、做好写入抽取、做好召回过滤、做好冲突管理这套基础架构能支撑你走很远。至于要不要上图谱、要不要做反思完全取决于业务复杂度不要为了技术炫技而过度设计。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询