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

资讯详情

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

AI Agent记忆系统详解:从短期记忆到长期记忆的架构实践

AI Agent记忆系统详解:从短期记忆到长期记忆的架构实践 你肯定遇到过这种情况一个 AI Agent你上午刚跟它聊完项目背景和代码规范下午重新打开新会话它一脸茫然地问你“你的项目叫什么来着”。更烦人的是你反复告诉它“不要用 React Hook 里的 useEffect 做数据请求”“我习惯双空格缩进”但它永远记不住。问题出在哪不是模型不够聪明而是绝大多数 Agent 天生“没有记忆”。模型本身是一台没有状态的推理机你输入什么它就回答什么上下文一断一切归零。这也是“AI Agent”领域里最难补齐的一块拼图。这篇文章是“走进 AI Agent”系列的第三篇专门聊记忆。我会从为什么 Agent 记不住你讲起拆开短期记忆、工作记忆、长期记忆这几层概念然后给出一个可以直接落地的记忆模块实现思路最后结合本地历史记录迁移、编程 Agent 的代码记忆召回、双网络记忆模型这些真实场景把“让 Agent 记住你”这件事彻底讲透。适合三种人看正在搭建个人 Assistant 的开发者、想把大模型做成企业级长期服务的架构师以及单纯好奇 Agent 记忆机制的产品经理。1. Agent 天生“健忘”的根因藏在无状态架构里1.1 大模型本质上是“一次性处理函数”我先说一个很多人没想清楚的事实大语言模型本身不具备任何持久化能力。你把一段 prompt 发给它它根据这段输入给出输出整个过程是一次性计算。你上一次问过它什么它中间生成过什么逻辑它自己完全不记得也没有任何“意识”去主动回忆。类比一下它就像一个考前背完题库的临时工你给多少题它答多少题。你第二天再来问它还是“第一天”的状态因为它的“工作记忆”只在接题那一刻被唤起。这就是无状态stateless架构。AI Agent 和普通聊天机器人最大的区别在于Agent 会调用工具、会写代码、会决策但只要你把它的对话上下文丢掉它立刻回到“陌生人模式”。这意味着要让 Agent 具备“记住你”的能力这一层功能绝不能依赖模型本身而是要在外部搭建一套记忆系统把该记的东西存下来等需要用的时候再喂回去。1.2 上下文窗口并不是“记忆”很多人会把大模型的上下文窗口context window当成记忆这是一个很容易踩的误区。上下文窗口只是“当前对话里能放得下的临时便签”它有两个硬约束长度有限以常见的 128k 上下文窗口为例看起来很大但对一个长期服务的 Agent 来说它只够容纳几小时的高频对话远不能覆盖你过去三个月的偏好和决策。长度等于成本与延迟窗口里的 token 数量越多每次推理的算力开销越大、响应越慢。你不可能为了让它记住你就把一整年的历史对话全部塞进上下文。所以更准确的理解是上下文窗口只能充当“短期工作台”记忆系统的目标是把这个工作台之外的信息按需取回来放到工作台上。上下文窗口是内存条长期记忆是硬盘两者根本不是一个层级的东西。1.3 无状态带来的连锁工程问题一旦 Agent 不能记住你服务体验会出现一系列连锁崩坏用户需要重复交代背景。客服场景里用户上一轮刚说了“我买的是 2023 款 Pro 型号”下一轮 Agent 问“请问您购买的是哪一款”用户体验直接崩塌。个性化无法沉淀。用户明确说过“我喜欢简洁回复”“请直接给代码不要解释”但 Agent 每次都是默认话术。跨轮次的复杂任务无法推进。真正的 Agent 任务往往需要多轮对话、多次工具调用如果每次都要重来Agent 就退化成了一个只能回答单轮问题的接口。理解了这些根源你才能意识到给 Agent 加记忆不是加一个聊天记录文件那么简单而是一次架构升级。2. 三层记忆架构短期、工作、长期各管一段把记忆系统拆成三层是从认知科学里借鉴来的思路。“双网络记忆模型”这个概念也源自这里一套网络负责处理当前会话的实时信息类似人类的海马体工作记忆另一套网络负责沉淀和检索持久信息类似大脑皮层长期存储。落到工程上我用三层划分最常见2.1 短期记忆会话里的“临时便签”短期记忆对应的是当前会话上下文。它的职责是保存本轮对话的用户输入、Agent 输出、工具调用结果确保多轮对话有连贯性。工程上它通常就是一个消息缓冲数组messages [ {role: system, content: 你是个人助理回复简洁。}, {role: user, content: 帮我查下明天的天气}, {role: assistant, content: 好的我来调用天气工具...}, ]实际落地时短期记忆有两点要注意必须设上限。不能无限堆积消息否则迟早爆上下文窗口。常见做法是超过阈值后做“精简摘要”把最早的消息压缩成一段总结塞回去。保留工具调用记录。Agent 和普通聊天不同的是它会调用工具。如果短期记忆里只有对话文字没有工具调用的入参和返回值下一个环节就没法继续决策。很多框架里会专门保存 tool call ID 和 tool result 的配对关系。2.2 工作记忆任务执行中的“草稿纸”工作记忆比短期记忆更微观它描述的是 Agent 正在执行的这个任务进行到哪一步了。举个例子Agent 帮你规划出差它已经查了航班、筛选了三个备选、等你确认选哪一班这时“已经完成到哪一步、卡在哪个决策点”就是工作记忆。工作记忆在工程里通常表现为任务状态树或 JSON 结构{ task: book_flight, status: awaiting_user_choice, staged: { options: [ {flight: CA123, price: 1200}, {flight: MU456, price: 980} ], selected_option: null } }为什么要把工作记忆单独拎出来因为多轮对话往往会跑偏。用户可能先让你订机票中间又问一句“帮我看看上海天气”然后再回来“行了就选第二个”。如果工作记忆混在对话流里没有独立管理Agent 很可能忘了自己正在订机票。所以务实的做法是让对话历史负责普通交流工作记忆单独存一个“任务状态对象”每一轮都做状态更新和校验。2.3 长期记忆从“记事本”到“档案柜”长期记忆是需要跨会话保留的信息它又分两个子类型语义记忆你的偏好、身份、常识性画像。“用户叫张三偏好 Python回复喜欢简短常用数据库是 PostgreSQL。”这类信息要精确、结构化。情景记忆过去发生过的事件。“三天前用户让我把支付模块从同步改成异步原因是超时严重。”我在实际项目里发现长期记忆不能只靠同一个存储器解决。如果全用对话向量embedding存那么“用户偏好的数据库是 PostgreSQL”这种精确事实用相似度检索不一定召回的准确如果全用关系型数据库存那“用户三个礼拜前说过的一句关键需求”又难以被相似语义匹配出来。正确的做法是混合存储结构化画像用表格开放对话历史用向量库两者在召回层合并。这部分我在下一章展开讲。3. 从存储到召回手拆一个最小可用的 Agent 记忆模块下面这部分是全文最“动手”的章节。我会按存储、写入、召回、遗忘四个环节给出一套最小但完整的记忆系统实现思路你可以在自己的 Agent 工程里直接照着搭。3.1 存储选型向量数据库与结构化表怎么分工先说结论记忆系统通常需要两种存储引擎。存储类型适合记忆召回方式典型选型关系型数据库用户画像、偏好标签、关键事实、记忆元数据精确查询、按字段过滤PostgreSQL pgvector向量数据库对话记录、文章片段、非结构化信息语义相似度召回Qdrant、Milvus、Chroma对象存储原始对话日志、历史版本归档手动检索、离线分析本地磁盘、S3 兼容存储对于个人项目和中小团队我推荐直接用 PostgreSQL pgvector因为它把精确查询和向量检索合在一个库里减少了维护成本。不建议一上来就堆一堆中间件记忆系统的核心难点从来不在存储引擎而在写入策略和召回策略存储只要别成为瓶颈就行。结构化表的简单设计可以长这样-- 用户画像表存储精确事实 CREATE TABLE user_profile ( user_id TEXT PRIMARY KEY, key TEXT, value TEXT, confidence REAL, source TEXT, updated_at TIMESTAMP ); -- 对话记忆表存储向量化语义记忆 CREATE TABLE memory_entry ( id BIGSERIAL PRIMARY KEY, user_id TEXT, content TEXT, embedding VECTOR(1536), importance FLOAT, expires_at TIMESTAMP, created_at TIMESTAMP );这里user_id很关键。很多 Agent 项目早期没有用户体系导致记忆没法归属到人后面做多端同步时非常痛苦。我建议你在第一天就把user_id加进去。3.2 写入策略不是所有对话都值得记住记忆系统最怕的是“什么都记”。如果一个 Agent 把用户闲聊的每一句话都存进长期记忆库过一小段时间这个库就会变成噪音池真正重要的信息反而召不回来。我的经验是给“值得记”的信息分三类用户主动声明的事实。“我的项目叫 Atlas”“我不用 Java”“回复里不要出现 emoji”。跨轮次重复出现的信息。用户每次提到“我们后端用的是 Spring Boot”这不是偶然这是强信号必须提取。带决策性质的节点。“我决定用 Postgres 而不是 MySQL”“审批通过了按方案 B 执行”。反观那些不值得记的内容纯寒暄、瞬时性请求“现在几点了”、临时聊天中的无意义重复。这些记了只会增加召回噪声。要落地写入策略最省事的方式是加一个“记忆提取器”它可以是 LLM 能力调用也可以是规则模板。每次对话结束后把当前轮次的对话丢给一个低成本的模型让它输出“需要长期记忆的结构化条目”prompt 你是记忆提取器从对话中提取值得长期保存的用户偏好与事实。 要求 - 只提取明确信息不要推测 - 输出 JSON 数组 - 每条包含 key/value/source/importance(0-1) - 没有就不输出 这个提取器不需要很复杂但它决定了记忆库的质量。我会专门在第五节讲记忆污染问题这里先埋个伏笔写错记错比不记更致命。3.3 召回相关性、时效性、重要性的三角平衡召回是记忆系统里最有技术含量的部分。理想状态是每次对话开始时系统自动从长期记忆库中挑出与当前任务最相关的 5~20 条信息注入到上下文里让 Agent 感觉自己“记得你”。但“最相关”是一个很模糊的概念只做向量相似度远远不够。我用一个生日提醒场景来解释相关性用户现在在聊辅食计划那“孩子两岁”就比“用户父亲生日 5 月 20 日”更相关。这部分靠 embedding 相似度的召回。时效性用户一年前说过“我在学前端”最近三个月他一直在写后端“在学前端”这条记忆就不应该再进上下文。所以记忆条目必须有updated_at和有效期。重要性用户画像里的“姓名”“工作角色”这类高置信度、高重要性信息应该每次都带。它们不是靠相似度召回的而是靠规则强制注入的。我的实现方案是“多路召回 权重融合”先用向量召回 top 30再根据时间和重要性重排取 top N。同时把用户画像表里的高置信条目单独组装成一段“user context”固定注入。这样既保证语义相关又保证关键事实不丢。3.4 遗忘机制永久记住才是灾难很多人会觉得“记忆越多越好”这是另一个误区。真实世界里人类的记忆是会被时间和新信息冲淡的。Agent 的记忆系统如果没有遗忘机制长期跑下去一定会出问题旧记忆与现实现冲突“用户 2024 年在用 Vue 2”但 2026 年早换 Vue 3 了。过期记忆干扰相关性存了 1000 条记忆之后哪怕召回策略再好也难免把过时信息翻出来。存储膨胀导致成本上升向量库检索速度下降存储费用上涨。遗忘策略可以有三种层次策略做法适用场景TTL 过期每条记忆带expires_at到期后退出召回临时性偏好、活动安排重要性衰减importance 值随时间递减低于阈值自动归档情景记忆、对话片段用户显式删除/纠正暴露记忆管理接口让用户说“这件事记错了删掉”画像类关键记忆我在项目里最推崇的是“让用户干预”这一条。Agent 有记忆能力之后必须给用户一个可见、可控的记忆面板。用户能看到系统记住了什么、能亲手删掉错误条目。没有这个面板记忆系统迟早变成黑箱最后用户只会觉得这个 Agent“自作聪明”。4. 四个落地样本对话迁移、代码记忆、双网络协同、知识库底座理论说得够多了这一章我结合几个具体的、我现在梯队的落地样本把“让 Agent 记住你”的几种常见形态都过一遍。4.1 本地历史对话记录的存储与迁移以 WorkBuddy 为例“WorkBuddy 历史对话记录、本地记忆迁移”是最近大家聊得比较多的一类需求本质是用户不想依赖云端的记忆而是希望 Agent 的聊天记录能存在本地换一台电脑、换一个 Agent 前端时这些记忆能跟着搬过去。我用 WorkBuddy 这类本地优先工具举例完整的迁移流程分四步导出历史对话。从老环境里把聊天记录导出成 JSON 或 Markdown 文件段结构保留 role、content、timestamp、message id。清洗与结构化。原始对话里混着大量无关内容不能直接塞进记忆库。我建议先做一轮预处理去掉工具调用的中间噪音只保留用户核心诉求和最终结论按会话拆分。构建“用户摘要文件”。把清洗后的结果提炼成一份user_profile.md里面写清楚用户偏好、常用技术栈、每天都在处理什么任务。这个摘要文件是记忆系统的“元数据”每次新会话开始都可以读一遍。导入新 Agent 环境。新环境启动时读取这些本地文件写入自己的长期记忆库同时保留归档原文件便于回溯。这四步看起来简单但很多人会漏掉第二步和第三步直接把几千条原始记录塞进新 Agent导致体验极差。要点是迁移记忆不是迁移原始日志而是迁移“提炼后的信息”。4.2 编程 Agent 的代码记忆召回OpenCode 是怎么想起来你改过什么的“OpenCode 如何通过记忆召回代码修改情况”这个热词很有意思因为编程类 Agent 对记忆的要求和聊天类完全不一样。代码场景里Agent 需要记住的不是“你喜欢什么风格”而是“这个文件我上次怎么改的、为什么要这样改”。以 OpenCode 这类本地优先的编程 Agent 为例它的代码记忆召回通常围绕三个维度展开变更足迹每次修改文件时记录下修改时间、涉及文件、diff 摘要、关联的 commit message。这相当于给代码仓库加了一层“修改语义索引”。意图记录只记 diff 不够最好还要把修改原因记录下来。“因为线上超时把同步请求改成异步”这条意图信息比 diff 本身更值钱因为下次改同一个模块时Agent 需要知道历史包袱在哪里。主动召回当用户要求修改某个文件时Agent 先检索这个文件的历史变更记忆把上次的改法、踩过的坑作为上下文注入再开始动手。我举一个很实际的场景三天前你把订单模块里的verify()函数从同步改成异步原因是对外接口频繁超时。今天用户让 Agent 在同一个函数里加缓存逻辑。没有代码记忆的 Agent 会直接加缓存完全不考虑异步上下文有代码记忆的 Agent 会先提醒“这里已经是异步实现加缓存时要注意并发问题”。这就是记忆召回对代码质量的价值。4.3 双网络记忆模型短期与长期的协同与冲突“双网络记忆模型”这个词听起来复杂实际上描述的就是短期记忆通道和长期记忆通道如何协同工作。一个完整的 Agent 记忆系统可以抽象成两张网短期记忆网络运行在当前会话中接收用户的每一句话、每一个反馈实时更新“对话状态”和“最近偏好”。长期记忆网络运行在会话后台定期把短期记忆里值得沉淀的内容抽取、格式化、写入长期库并在新会话开始前把关键画像召回进短期工作台。双网络协同的核心是“双向写入”前向写入会话中用户说“以后都用 pnpm”短期网络立刻记住这个临时偏好对话结束时写入长期网络。反向纠正新会话里用户说“不对我改回 npm 了”短期网络捕获到纠偏信号后不仅要更新当轮对话状态还必须反向去改长期库里的旧画像。这一点很容易被忽略。很多 Agent 只是在新一轮对话里临时记住了“npm”但长期库里还躺着“pnpm”下次又会做错。双网络之间要有一个明确的冲突解决规则。我的建议是当用户当前意图与长期记忆冲突时以当前会话为主同时给长期记忆打上“待更新”标记等待用户确认后再覆盖。4.4 Obsidian 知识库把 Agent 的外部记忆建在笔记之上最后一个样本是知识库型记忆。有些人不是要 Agent 记住“他说过什么”而是希望 Agent 能“调用我积累的资料”。Obsidian AI Agent 的组合最近热度非常高因为它把“记忆”从对话记录扩展成“知识资产”。思路是把 Obsidian Vault 当成一个外接记忆底座在 Vault 里按固定规范建立笔记比如用户档案.md、项目决策日志.md、学习笔记/。Agent 通过文件读取或索引插件扫描这些 Markdown 文件把它们切成 chunk写入向量索引。对话时Agent 先检索 Vault 里相关内容再结合对话上下文生成回答。这样做的好处是记忆完全本地化、可编辑、可追溯。坏处是笔记质量参差不齐而且没有严格的时效性标记。所以我一般会在笔记文件名或 frontmatter 里强制要求写updated:字段方便召回层做时间过滤。如果你个人已经有 Obsidian 知识库这个方案比“纯对话记忆”更值钱因为你是在让 Agent 站在你整理过的信息上工作。5. 记忆系统的暗坑污染、不同步、隐私与成本最后必须聊一聊我在真实项目里反复踩、也看别人反复踩的坑。很多 Agent 项目把记忆系统搭起来了结果体验比没有记忆还差基本都是栽在这几个问题上。5.1 记忆污染坏记忆比没记忆更可怕记忆污染是指长期库里存了错误或过时的信息并且这些错误信息在召回时被当作事实用进了上下文。这样产生的后果非常隐蔽Agent 会“自信地犯错”而且因为有记忆背书用户会觉得它蠢得离谱。我遇到过最典型的污染案例一次自动提取时把用户一句吐槽“我恨死这个 Python 环境了”提取成了“用户偏好不喜欢 Python”。结果之后所有涉及 Python 的建议Agent 都会刻意避开用户完全摸不着头脑。避免污染的实践手段有三个置信度评分记忆提取时明确区分“用户明确说的”和“推测出来的”。推测类记忆 confidence 低于 0.6 就不入长期库。记录来源每条记忆保存对应的原始对话片段方便回溯和纠错。定期复核每隔一段时间抽样检查长期记忆库里的条目是否仍然准确。这个事情甚至可以用另一个 Agent 来做把明显过时或矛盾的记忆筛选出来人工确认后清理。5.2 记忆同步同一用户、多端共用一套记忆现在的用户不会只在一个终端里使用 Agent。手机端、电脑端、网页端如果各存各的长期记忆就会出现“手机端认识你电脑端不认识你”的割裂体验。记忆同步要解决两个问题写冲突。用户可能同时在手机和电脑上跟 Agent 说话两个会话都在向长期库写入画像。解决方式是为每条记忆增加updated_at和版本号写入时做合并判断。简单点的规则是“后写的覆盖先写的”复杂点的是按字段级合并。召回一致性。记忆库是多副本存储时要保证召回时读到的是最近版本否则节点间数据滞后会让用户觉得“记忆错乱”。一开始就定义好user_id和全局唯一记忆 ID会给多端同步省下大麻烦。我见过太多项目在最开始图省事用设备本地 ID 做记忆归属后面做同步时几乎要重写整个存储层。5.3 隐私边界本地记忆与云端记忆的取舍记忆系统天然涉及隐私。用户画像里可能有姓名、联系方式、健康状况、工作单位对话记录里更可能夹带敏感业务信息。给 Agent 加记忆实际上是在给用户建一个“数字档案”这必须谨慎。我的原则是能本地存就本地存必须上云就加密。推荐采用“本地优先”的架构把原始对话记录放在本地数据库或本地文件系统云端只存经过脱敏的向量索引。即便需要向量化也要在本地完成 embedding 之后再上传避免原始文本出网。同时必须提供两个用户能力一键导出和彻底删除。没有这两个能力记忆系统在合规上就是一颗定时炸弹。我见过有团队把“用户偏好”存得很细但用户想删却找不到入口最后只能投诉。5.4 召回质量与性能成本的平衡最后一个实战问题记忆召回不是免费的。每次对话都去向量库检索、再把 top N 注入上下文增加的 token 成本和时间延迟会随记忆规模上升而明显。这里分享几个我自己在用的调优策略召回条数要克制。一次性注入 50 条记忆Agent 根本顾不过来还容易上下文混乱。我的默认值是 top 5~10 条高重要性画像单独附加总记忆上下文控制在 800~1200 token 以内。设置召回阈值。向量相似度低于 0.7 的条目默认不注入宁可不给记忆也不给错误记忆。这个阈值可以根据自己的 embedding 模型调整先跑一批数据看分布再定。缓存高频记忆。用户画像中那些每次都关键的条目比如姓名、工作内容、核心偏好可以缓存到内存里每次会话直接读缓存不查库。异步重建索引。对话写入时先入原始库由后台任务异步更新 embedding 索引避免阻塞主对话链路。性能优化的本质是把“记忆召回”当成一个独立的服务来设计而不是在每次对话里临时拼接一堆查询。它有缓存层、有过滤规则、有降级方案。当用户量上来之后这一层的重要性会远超你的预期。我在实际项目里最深的体会是给 Agent 做记忆不要追求一步到位的“完美记忆”而是先跑通“用户画像文件 短历史归档”这种轻量方案让用户能看见、能纠正再逐步加入向量检索和自动提取。记忆系统是一个要和用户长期相处的模块它最核心的指标不是存储了多少条记忆而是用户是否觉得“这个 Agent 懂我”。能懂到这个程度你就已经赢过市面上绝大多数 AI Agent 了。
返回列表