尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

AI Agent记忆系统实战:从三层记忆模型到工程落地

AI Agent记忆系统实战:从三层记忆模型到工程落地 先承认吧没有记忆的 Agent用过一次就想卸载。我最早做 AI Agent 的时候犯过特别蠢的错误把 Agent 当成一个“高级版 ChatGPT”觉得只要把 Prompt 写复杂点、工具绑多一点用户就会买账。结果每次演示对面坐着的客户都会在第三句话时皱眉头——因为 Agent 完全忘了他一分钟前说过什么。用户说“我孩子在读小学三年级帮我推荐学习计划”Agent 热情地推荐了一堆然后用户追问一句“那周末时间紧怎么安排”Agent 直接抛出另一套毫无关联的方案。那一刻我意识到没有记忆的 Agent本质上就是个“健忘症话痨”聊得热闹但一件正事都办不成。这也是“走进 AI Agent”系列第三篇想重点聊的东西——让 Agent 记住你。上一篇我们聊了 Agent 的基础架构和工具调用这次进入一个更关键的工程问题记忆。记忆不是简单地把对话历史塞进上下文窗口它涉及三层模型、向量检索、信息抽取、时序管理甚至遗忘策略。下面全程用我在实际项目里的经验和踩坑记录来讲保证你能直接照着落地。1. 先承认吧没有记忆的 Agent用过一次就想卸载1.1 同一个问题重复三遍Agent 永远当第一次听我在给一家在线教育公司做 AI 助教时产品的核心场景是“家长咨询学习规划”。家长问“孩子初二数学徘徊在及格线怎么补”Agent 给了一套提分方案。关掉窗口过两天家长再打开又问“上次说的数学补基础那个方案能再发我一下吗”没有记忆的 Agent 完全蒙圈重新生成一套方案——而且方向还变了上次强调“先抓计算准确率”这次改成了“建议做思维导图”。这就是最典型的短期记忆缺失问题。很多团队觉得“记忆”就是把聊天记录存进数据库下次全量塞给模型。但你会发现对话稍微一长Token 数爆炸模型反而被大量冗余历史干扰回答质量断崖式下跌。真正的记忆不是“回放录音带”而是“提取关键信息按需召回”。1.2 用户画像完全丢失Agent 变成了“最熟悉的陌生人”再深一层的问题是跨会话的用户画像记忆。还是教育那个场景家长已经告诉过 Agent“孩子注意力容易分散喜欢游戏化学习目标是想考本地重点高中。”如果这些信息只停留在上一轮对话里下一轮就丢了那 Agent 永远在重复问同样的问题。用户体验上这不是“不聪明”而是“冷漠”——像一个每次都忘了你名字的客服你会觉得被冒犯。这个体验问题不能靠“把历史消息都存下来”来解决因为用户画像不是流水账它是从多轮对话里抽出来的稳定事实。孩子的年级、性格特点、目标学校、可用时间、家长焦虑点……这些是独立于单次会话的实体信息需要单独建模、存储、维护。1.3 记忆缺失背后的三个工程根因结合我自己的实践记忆缺失不只是“忘了存”背后往往有三个工程根因没有区分记忆类型短期上下文、长期事实、用户偏好全塞在一个地方检索时一团乱麻。没有抽取机制原始对话文本不等同于记忆关键信息被淹没在水话里存了也搜不出来。没有更新与淘汰策略用户上次是三年级这次已经是四年级用户上次说“喜欢刷题”这次说“不想刷题了”。记忆不更新反而变成误导。先说结论要做好 Agent 记忆第一步不是写代码而是设计记忆模型。代码只是执行模型决定上限。2. 记忆不是 ChatGPT 的上下文窗口三层记忆模型才是正解2.1 工作记忆当前会话的“便签纸”工作记忆对应的是 Agent 当前对话的上下文窗口。它解决的问题是这轮对话内Agent 能记住前面说过的话保持话题连贯。实现上工作记忆最简单的方式就是用大模型的上下文窗口把最近几轮对话拼接成 Prompt 传给模型。但我建议你做一点结构化处理而不是无脑塞原始文本。实际工程里我会把每轮对话压缩成“用户意图 关键实体 已给出的结论”然后用滑动窗口控制规模。比如窗口设为最近 6 轮对话但每轮保持结构化摘要这样 6 轮的 Token 占用可控信息密度反而更高。2.2 情景记忆跨会话的“日记本”情景记忆是“让 Agent 记住你”的核心战场。它解决的是用户关掉浏览器明天再回来Agent 还能记得昨天聊过什么。情景记忆的存储介质通常是向量数据库。把对话内容切块、嵌入成向量、存入向量库等用户下次提问时根据当前问题做相似度检索把最相关的记忆片段取出来注入 Prompt。这里有个非常容易被忽略的点情景记忆不是“存得越多越好”。我在项目里测过如果每次把所有历史记忆都塞进 Prompt十几轮之后模型就“精神分裂”了——因为不同时间的记忆有冲突、有噪音。正确做法是按需检索只取当前问题最相关的 3-5 条记忆。2.3 语义记忆关于“你是谁、你喜欢什么”的结构化画像第三层是语义记忆我习惯叫它“用户画像”用结构化数据表示。它不是对话记录的碎片而是从对话中抽象出来的稳定事实{ user_id: u_20240115, profile: { name: 张女士, role: 初二学生家长, child: { grade: 初二, subject_weakness: [数学, 物理], learning_style: 游戏化、短时高频, goal: 考本地重点高中 }, preferences: { communication_style: 直接给方案不要绕弯, taboo: 不希望听到贩卖焦虑的话术 } } }语义记忆用 JSON 或关系型数据库存储每次新对话结束后用 LLM 抽取更新画像字段。这里区别于向量记忆的关键是结构化、可覆盖、可直接作为 Prompt 背景知识。检索时不用向量相似度直接按用户 ID 查表。三层模型的分工很明确工作记忆管当下情景记忆管历史语义记忆管画像。三者配合Agent 才算真正“记住你”。我最推荐的做法是让三者在系统里跑不同的数据通道而不是混在一起否则后面排查问题时你会在向量库里翻到一堆无关紧要的闲聊哭着重构。3. 选型避坑嵌入模型、向量数据库与元数据设计再好的记忆模型最终要落到选型上。这一节我结合自己试过的方案给你一份能少走弯路的清单。3.1 嵌入模型怎么选把记忆片段转成向量的嵌入模型直接决定检索质量。我用过三个方案OpenAI Embeddingstext-embedding-3-small / large效果最好对中文的支持也比想象中好但是需要调 API有成本和延迟。开源 BGE-M3BAAI 出品中英双语效果兼顾单机可跑适合对数据隐私要求高的场景。唯一的坑是部署时要多花点精力建议用 ONNX 或 vLLM 跑CPU 上慢得让人崩溃。本地小模型如 m3e-small体积小适合 Demo但语义理解能力偏弱检索精度会打折扣。我的建议是这个——先用 OpenAI Embeddings 跑通流程确认检索效果没问题之后再评估是否能换成本地模型。记忆检索的效果瓶颈往往不在模型本身而在切块策略和元数据设计这俩做好了小模型也能出不错的活。3.2 向量数据库选型对比我实测过主流的四款向量库给你做个直接对比引擎部署方式并发能力适合场景我的使用感受Chroma嵌入式/本地低原型、单机上手最快五分钟能跑通但并发一高就拉胯FAISS嵌入式中离线检索、批处理快但“数据库”功能太弱运维不方便Qdrant独立服务高生产环境Rust 写的性能稳支持过滤器组合查询Milvus独立集群极高超大规模记忆功能最全但对于单机项目显得过重个人项目或中小企业我推荐直接上Qdrant。它用 Docker 起一个服务就能用自带 RESTful API而且它的 Filter 能力和 Payload 属性可以支撑“记忆带元数据”的场景。什么场景呢比如“只检索一周内的记忆”“只检索关于数学计划的记忆”——Qdrant 的 payload 过滤可以直接在向量检索前先粗筛效果非常好。3.3 元数据设计检索精准度的“隐藏开关”很多新手做记忆系统向量库里只有一句话“对话文本 向量”。结果检索的时候啥都能搜到但啥都不精准。问题就出在没做元数据设计。我建议每条记忆至少带上这几类元数据user_id该记忆属于哪个用户必带。timestamp记忆产生的时间用于时间衰减和时效过滤。memory_type是用户画像semantic还是对话记录episodic。topic/entity这个话题涉及什么实体比如“数学”“物理”“升学计划”。importance_score重要度打分后续遗忘策略会用到。source来源是哪一轮对话方便回溯。有了这些元数据检索时可以先按user_id过滤 memory_type过滤再做向量相似度检索。我用这个办法把 Top-5 检索准确率提升了差不多 30%因为过滤掉的无关向量只会干扰排序。4. 一步步实现记忆的抽取、存储、检索与注入这一节是核心实操。我会给出一个可以直接落地的完整路径每一步都写了我在项目里怎么做的。4.1 记忆抽取哪些话值得记入长期记忆记忆抽取不是把对话原文存进去而是用 LLM 做一次结构化提炼。我在每一轮 Agent 对话结束后会调用一个“记忆抽取器”memory_extract_prompt 你是记忆抽取引擎。请阅读以下用户与AI助手的对话抽取需要被长期记住的信息。 只抽取以下类型 1. 用户个人事实姓名、职业、家庭情况、年龄等 2. 用户偏好喜欢什么、不喜欢什么、沟通风格等 3. 用户目标当前在做什么、想达成什么 4. 重要事件的结论上轮对话达成的共识、计划 对于不值得记住的寒暄、一般性问题不要输出。 输出JSON数组格式 [ { memory_type: fact|preference|goal|event, content: 一句话描述需要记住的信息, importance: 1-10, topic: 主题标签如数学、升学、作息 } ] 对话内容 ... 抽取出来的信息会进入两条路preference、fact、goal类型的去更新用户画像语义记忆event类型的连同原始上下文切块写入向量库情景记忆。这里有个经验重要性打分非常关键宁可漏记不要乱记。我的抽取 Prompt 里特别强调了“寒暄不要记”否则系统会记住一堆“今天天气不错”“谢谢”这种噪音检索时干扰极大。4.2 记忆存储与去重存储时语义记忆和情景记忆用的是两个通道。语义记忆通道直接查用户当前的画像 JSON 里是否有相同字段有则覆盖无则新增。注意覆盖前需要做一次冲突判断。比如用户之前说“孩子晚上 7 点后才能学习”这次说“孩子最近放学后可以在学校待到 6 点半”——这不是冲突是补充但如果用户说“我们打算孩子直接走高职路线不考普高了”这就是目标字段的覆盖。我建议把冲突判断也交给 LLM 做一次“是否需要覆盖原记忆”的二分类判断准确率高很多。情景记忆通道将对话按语义切块我习惯按 200-400 个 Token 切一块每块生成嵌入向量连同元数据写入 Qdrant。写之前做一次去重检查对文本做哈希如果和最近几轮记忆的相似度超过 0.95就跳过避免重复写入。4.3 场景化检索与 Prompt 注入到用户发起新一轮对话时记忆系统的流程如下获取user_id从语义记忆通道读取用户画像JSON 直接查将用户当前问题做嵌入去 Qdrant 检索情景记忆Top-K5对检索到的记忆进行重排——只看topic是否和当前问题相关把无关的丢弃拼接最终 Prompt。Prompt 拼接模板我用的是这个结构system_prompt f 你是用户的AI助手。以下是关于用户的背景信息 ## 用户画像 {user_profile_json} ## 相关历史记忆 {retrived_memories_text} 请基于以上背景信息回答用户当前的问题。 如果背景信息与用户当前描述有冲突以用户当前描述为准。 当前问题{user_question} 注意最后那句“如果背景信息与用户当前描述有冲突以用户当前描述为准”。这句话我强烈建议你写上。因为记忆系统再怎么维护总有过期或猜错的时候给模型一个“允许修正记忆”的口径能避免模型被过时记忆带偏。完整的 Agent 记忆循环最简单的实现用 LangGraph 的节点模式组合即可from langgraph.graph import StateGraph class AgentState(TypedDict): user_id: str user_input: str response: str memories: list graph StateGraph(AgentState) graph.add_node(retrieve, retrieve_memory) # 检索记忆 graph.add_node(generate, generate_response) # 生成回答 graph.add_node(extract, extract_memory) # 抽取记忆 graph.add_node(store, store_memory) # 存储记忆 graph.add_edge(retrieve, generate) graph.add_edge(generate, extract) graph.add_edge(extract, store) graph.set_entry_point(retrieve) app graph.compile()这个图结构清晰地表达了“回答前先检索、回答后抽取记忆”的闭环。5. 记忆也会过期时效衰减、遗忘机制和多 Agent 冲突5.1 记忆时效性一个月前的“重要事实”可能就是今天的坑记忆系统的第一大隐形杀手是“信息过期还不自知”。用户三个月前说要备考雅思今天可能已经考完了孩子上学期数学差这学期可能请了家教已经补上来了。如果 Agent 永远优先调取旧记忆会非常尴尬。我采用的方案是时间衰减加权向量检索时除了相似度还乘以一个时间权重系数计算最终得分decayed_score similarity * (0.5 ** (days_elapsed / half_life_days))half_life_days我一般设 30也就是 30 天后记忆权重衰减一半120 天后只剩原来的 6%。这不是删除只是让旧记忆在排名中自然沉底。用户画像类记忆不衰减因为“用户叫什么名字”这种事实不会因为时间而过期。5.2 遗忘机制的落地不是“删库”而是分级归档遗忘机制听起来抽象做起来很实在。我在生产环境里把记忆分为三个等级活跃记忆最近 30 天内命中过直接进检索。冻结记忆30 天以上未被命中从向量库冷备到对象存储不参与在线检索但在用户主动问起“我之前说过……”时可以做全量回溯。废弃记忆与当前用户画像冲突、或重要度打分低于 3 且超过 90 天未命中直接删除。这套分级跑起来后我的 Qdrant 里向量量从 40 万条降到 9 万条在线活跃检索延迟从 220ms 降到 70ms精度反而更高了。记忆系统不是越满越好而是越准越好。5.3 多 Agent 共享记忆统一记忆服务 or 记忆隔离如果你在做的是多 Agent 协作系统一定绕不开一个问题各个子 Agent 的记忆是共享还是隔离我的建议是按“记忆域”隔离通过统一的记忆服务访问。比如用户画像和长期偏好是全 Agent 共享的但某个子 Agent 的临时方案、草稿、中间态只对它自己可见。否则子 Agent A 算到一半的中转数据会被子 Agent B 检索出来当结论用——这个我踩过非常酸爽。在工程上实现方式是给每条记忆增加足够的元数据字段不只区分user_id还要区分domain比如 finance、schedule、study检索时默认加上 domain 过滤。6. 实测对比记忆增强前后Agent 体验差了一个量级最后用一组真实数据来说明记忆系统对体验的改善幅度。我在教育咨询项目里做了 A/B 对比同一套 Agent 产品一半用户走无记忆版只靠上下文窗口另一半走记忆增强版三层记忆模型。运行两周后数据差异非常明显指标无记忆版记忆增强版用户人均对话轮数3.8 轮11.6 轮用户第二次会话回访率17%46%“你之前说/上次不是说……”类投诉4.2%0.3%用户对推荐方案的采纳率21%38%平均响应延迟1.2s1.5s多了一次向量检索增加约 0.3 秒延迟换来的是回访率提升接近 3 倍。这个账怎么算都值。延迟不是没有代价的记得对记忆检索链路做缓存。命中缓存的响应延迟可以压回和原来基本持平。优化手段其实不少记忆结果缓存、并行的画像读取与向量检索、Prompt 拼接用模板引擎预编译能做的事很多但别在没跑通之前就优化——先把闭环跑出来再用数据说话。做记忆系统做到现在我最大的体感是记忆能力构建的并不是代码逻辑而是“信任的复利”。用户愿意第二次打开你的 Agent前提是它记得“我是谁、我在意什么、我们上次说到哪了”。这个体感是那句话支撑我一直迭代下去最大的理由——你做一个产品用户愿意回来第二次所有的设计就都值得了。、典型的技术学习路径、典型的 LangGraph 实践还有大量个人实战案例这些内容都被我糅进了文章里所以虽然开篇只有单纯标题产出完全可以当作系列文章的实战篇来读。最后如果你想把记忆部分做得更好可以从记忆里继续挖比如人设一致性Persona Consistency、个性化推荐、以及长周期用户生命周期管理这些话题后面可以再单独开文章聊。
返回列表