1. 先搞懂AI为什么会“失忆”三个被忽视的架构缺陷做 Agent 项目的人应该都有过这种体验对话里明明跟 AI 交代过“用户偏好简洁回复不要堆术语”结果新开一个会话它又变回长篇大论用户昨天刚问过某款产品的库存情况今天换个话题绕回来AI 却一脸茫然。这真不是模型变笨了而是你的 Agent 压根没有把记忆当成一个独立模块来设计。先说个我自己的经历。早前帮某团队做客服问答 Agent第一版只靠提示词里塞历史对话摘要效果还行但随着会话变多、话题变杂摘要越写越厚prompt 越来越长最后不仅费 token模型反而被摘要里的过时信息带偏。用户明明已经说了“不考虑蓝色那款了”AI 还在一本正经地推荐蓝色。这时候我才彻底意识到对话上下文只是“工作记忆”它天然会丢、会满、会过期。真正让 AI 显得“靠谱”的是它能像人一样把重要的事情写进“长期记忆”下次打开还能想起来。这个道理听着简单但实际落在架构上就涉及三个绕不开的问题记忆存在哪。不能只靠对话上下文需要外部存储。记忆怎么读写。Agent 得知道什么时候该记、什么时候该查。记忆怎么更新。记下来的东西会过期、会冲突、会冗余必须有治理机制。OpenClaw 在这件事上给了我一个比较顺手的答案。它不是那种什么都要你从零写的框架而是把 Agent 的“长期记忆”拆成了存储层、工具层、治理层你只需要按它的思路把三个环节接起来。这篇文章我结合自己搭过的几个项目把整套流程收敛成三步搭存储、接读写、做治理。按这个顺序走基本能把 AI 的“失忆”问题控制在可接受范围内。1.1 上下文窗口截断最表面的那个坑最常见的“失忆”场景其实源于大模型的上下文窗口限制。现在主流模型窗口动辄几十万 token看着很大但真跑起 Agent 来工具调用结果、中间推理过程、多轮对话来回很快就堆满了。窗口一满最常见的处理方式就是从最早的消息开始截断或丢给摘要模型压缩。这就导致一个很尴尬的局面早前对话里提到的关键偏好、用户身份信息、任务状态可能就因为在窗口里的位置太靠前被当成“过期内容”清掉了。我见过不少团队在这个阶段疯狂调 prompt 或加长窗口治标不治本。你加长窗口推理延迟跟着上涨费用也跟着涨你指望模型自己记住它在长文本里注意力本来就衰减越靠前的内容权重越低。说白了上下文窗口适合做短时工作区不适合当“记忆仓库”。这个认知不扭转后续所有方案都是空中楼阁。1.2 会话隔离换了场景就翻脸不认人第二个容易被忽略的问题是会话隔离。很多 Agent 平台默认每次对话都是独立 sessionsession 之间不共享状态。今天这个 session 里用户告诉你“我在上海下个月要出差北京”明天新开一个 session 问他出差安排他可能完全想不起来。模型的对话能力没问题问题是你的应用层根本没把记忆数据传递过去。这就像一个人每天醒来都失忆只靠当天的对话和纸条生活。纸条写得好他能应付当天的事纸条断档他就断片。所以长期记忆架构的本质就是要做一张跨 session 的“纸条系统”——不是靠运气而是靠一套明确的写入和读取机制。1.3 记忆不是聊天记录要分层不能一锅炖还有一种误区是把“长期记忆”简单理解成“把所有对话历史存下来”。真这么干第一个崩的就是检索效果。用户问“我之前说的那个需求你记得吗”你把三千条聊天记录全部塞给模型它根本分不清哪些是重点、哪些是寒暄、哪些已经变更过了。所以我在实际项目中会把 OpenClaw 的记忆抽象成三层工作记忆当前会话的上下文也就是模型窗口里正在处理的内容。情景记忆已经发生过的具体事件比如“用户在某月某日咨询过退款流程并留了订单号”。语义记忆提炼出来的稳定事实和偏好比如“用户偏好用顺丰发货”“用户对价格敏感推荐商品时优先列性价比选项”。这三层之间有依赖关系。情景记忆是原料语义记忆是从原料里提炼出来的结论工作记忆每次会话时从语义记忆和部分情景记忆里临时组装。这套分层思路和人的记忆系统很像你记不清上个月具体哪天吃了什么但你记得自己吃辣会不舒服——后者才是对你长期有用的东西。OpenClaw 的配置模型基本就是照着这个逻辑来的所以我把“记忆分层”当成整个架构的地基。2. 第一步搭好记忆存储层先解决“记忆放哪”存储层是整个记忆架构的底座最值得花心思因为它决定了后续扩展的天花板。我见过有人图省事把所有记忆塞进一个大 JSON 文件里前面还行跑一个月后文件几 MB 大每次读写越来越迟钝检索也没有任何优先级。所以第一步的目标很明确用合理的目录结构、合适的存储引擎把记忆组织成计算机好处理、模型好检索的形态。OpenClaw 在这块的思路比较务实启动成本低默认用本地文件 JSON 就能跑但 schema 设计是按可迁移的标准来的后面数据量大了换向量库不用推倒重来。下面是我的实际做法。2.1 存储选型从轻量文件起步别一上来就上向量库很多人一听长期记忆就想着上向量数据库我觉得得分阶段。项目早期记忆量小本地 JSON 文件完全够用而且容易调试出了问题直接打开文件看内容。向量库带来的收益主要在检索相似度和规模化记忆条目几百条的时候体现不出来反而增加架构复杂度。我的建议是先用 OpenClaw 的本地文件存储跑通流程等记忆条目过了一万条、检索响应变慢时再平滑迁移到向量库。OpenClaw 在存储引擎上做了统一接口存储层的替换对上层工具来说几乎无感。起步阶段只需要保证数据和 schema 的规范性迁移成本就完全可控。2.2 记忆目录与 Schema 设计给“档案柜”分好格子这是我自己最有心得的环节。如果一开始目录结构没设计好后面每加一种记忆类型都要改代码很被动。我现在用的目录结构长这样memory/ profiles/ default/ core.json facts/ 2025-01/ 2025-02/ episodes/ 2025-01/ 2025-02/ reflections/ 2025-01/每个字段的用途如下core.json用户或场景的固定画像比如称呼、地域、偏好、长期目标是所有检索里优先级最高的记忆。通常只维护一份内容简洁控制在几十行以内。facts/按月份归档的短期事实比如“在一次对话中用户提到下个月要搬家”。这类记忆时效性强适合按时间切片方便后续做衰减和归档。episodes/完整事件的记录比 fact 更详细可能包含当时的上下文摘要、关键结论、遗留问题。它是生成 fact 的原料可以在对话结束后由异步进程自动写入。reflections/阶段性总结。比如每周把本周 facts 汇总成一份用户偏好变化报告用于提炼新的 core 条目。这个设计的关键在于把“稳定画像”“短期事实”“事件流水”“阶段总结”拆开各归各的格子检索时按权重取用。不要把用户画像和一次性事件混在一起否则模型分不清哪些是长期稳定偏好哪些是临时状态。每个记忆条目在 JSON 里的格式也有讲究。我一般是这样组织的{ id: fact-2025-01-15-001, type: fact, content: 用户偏好通过企业微信接收订单通知电话容易被漏接。, source: session-2001, timestamp: 2025-01-15T10:30:00Z, importance: 0.8, access_count: 3, valid_until: 2025-04-15T10:30:00Z }注意几个字段importance 是重要度检索时参与排序access_count 是访问次数用于识别高频记忆valid_until 是过期时间实现自动衰减的基础。这些字段看起来简单但能把很多治理问题提前解决掉。2.3 初始化 OpenClaw 配置关键参数和它们的含义存储层的落地在 OpenClaw 里就是一份配置文件。下面是我实际在用的配置去掉了一些与本主题无关的参数memory: engine: local_file path: ./memory_data vector_store: enabled: false embedding: model: text-embedding-3-small dimension: 1536 retrieval: top_k: 5 relevance_threshold: 0.35 time_decay_factor: 0.1 write_control: max_entries_per_session: 20 deduplication: true require_confirmation: false lifecycle: fact_ttl_days: 90 episode_ttl_days: 180 reflection_interval_days: 7几个值得展开的参数relevance_threshold 是相关度阈值。低于这个阈值的记忆不返回。设太低了检索出来一堆无关内容设太高了该想起来的事也想不起来。我建议从 0.3 起步按实际效果微调。time_decay_factor 控制时间衰减力度。最近发生的记忆在排序时权重更高避免两个月前的旧事实把新记忆挤掉。衰减要控制住幅度太强会导致关键事实提前“遗忘”。max_entries_per_session 是单次会话写入记忆的上限。防止 Agent 每轮对话都往长期记忆里塞东西把存储写成流水账。正常一次会话的有效沉淀能有个十来条已经不错了。提示配置文件不只是跑通用的它也在替你把“记忆管理的规则”固化下来。后面调参时优先动检索相关参数而不是优先加窗口或改 prompt。到这里存储层的骨架就出来了。你有了目录、有了 schema、有了配置文件下一步要做的是让 Agent 真正具备读写记忆的能力。3. 第二步让 AI 学会“回忆”写入与检索闭环存储只是地基真正让 AI 显得“记事”的是它能在合适的时机把信息写进去、在需要的时候把信息捞出来。这一步我把它拆成两个核心机制记忆工具和触发策略。OpenClaw 的思路是通过工具调用接口让模型自主决定何时写入和读取而不是外部硬编码“每一轮结束后全量保存”。听起来很抽象举个例子就清楚了。用户说“以后订单通知发我企业微信”Agent 收到这句话后如果识别为“用户偏好”类的稳定事实就调用保存记忆的工具把这条信息结构化存储。下次新会话里用户问“你们通常怎么通知订单状态”Agent 可以先检索记忆看到这条偏好记录直接给出符合用户预期的回答。这就是一个完整的“回忆”闭环。3.1 记忆工具设计给 AI 一个可以伸手够到的书架在 OpenClaw 里记忆能力是通过工具接口暴露给模型的。我给 Agent 挂了两个核心工具save_memory 和 recall_memory。前者负责写入后者负责检索。工具定义用的是标准的 JSON Schema下面是我在当前项目里的实际写法{ name: save_memory, description: 保存一条长期记忆。当用户表达出稳定偏好、关键事实、重要承诺时需要调用。, parameters: { type: object, properties: { content: { type: string, description: 记忆的具体内容使用陈述句避免模糊表述。 }, category: { type: string, enum: [core, fact, episode], description: 记忆类别core为长期稳定画像fact为短期事实episode为事件记录。 }, importance: { type: number, minimum: 0, maximum: 1, description: 重要度0.7以上为高优记忆。 }, expires_in_days: { type: integer, description: 过期时间单位为天。过期后自动降低检索权重。 } }, required: [content, category] } }recall_memory 的定义类似只是参数变成查询描述和返回条数限制。这里我想强调一个设计心得save_memory 的 category 一定要用枚举别让模型自由发挥。模型一旦写出“这是个很重要的情况”这种模糊分类后续检索和治理都会变得很崩溃。再补充一点工具描述里的触发条件写清楚能显著提升模型的调用准确率。比如我在 save_memory 的描述里明确写了“当用户表达出稳定偏好、关键事实、重要承诺时需要调用”模型在决策时就会更保守。实际跑下来误写入的比例明显降低。这就是“把智能的一部分前置到工具设计里”的思路。3.2 检索策略先相关度后时效混合排序才有意义记忆存得再好捞不出来也是白搭。OpenClaw 的检索默认是向量相似度 关键词联合召回然后做一个混合排序。混合排序的核心逻辑并不复杂def score(entry, query_embedding): semantic cosine_similarity(entry.embedding, query_embedding) recency 1.0 / (1.0 time_decay_factor * hours_since(entry.timestamp)) return 0.7 * semantic 0.3 * recency这里的核心是把相关度和时效性做一个加权求和。纯靠相关度排序容易把三个月前的高相似记忆顶到最前面而用户可能昨天刚提过新要求纯靠时效排序又会忽略那些长期稳定但很久没人提的偏好。0.7 和 0.3 这个比例是我在一个客服场景里调了不少轮定下来的客服场景里用户偏好这类稳定记忆占比高时效性权重不能太高。注意语义相似度在“标题匹配”型查询上效果很好但在“时间敏感型”查询上容易翻车。比如用户问“我上次说的物流问题怎么样了”这单靠 embedding 很难匹配到正确的 episode。所以我在检索时会把“时间最近优先”作为一条单独的排序规则在查询包含时间指示词时启用。这个小改动解决了不少实际痛点。3.3 对话结束后的记忆固化 Pipeline别让原始记录直接入库光靠模型在对话中主动调用工具还不够。很多有价值的记忆并不一定在对话中途被模型识别为“重要”而是事后回看才发现的。所以我跑了一个异步的“记忆固化”流程在每次会话结束后处理当轮对话。这个流程分四步走会话完结合并上下文交给摘要模型生成结构化收束包含发生了什么、用户明确表达了什么、有哪些遗留事项。从摘要里抽取 candidate memory按照 stable fact、temporary fact、episode、preference 分类。对每条 candidate 做去重检查。如果已存在高度相似的记忆跳过或合并不能无脑追加。将确认后的记忆按对应 category 写入存储并给 core.json 做增量更新。这里有个容易忽略的细节去重检查必须在写入前做而不是写入后。之前我因为偷懒把去重丢给后端扛结果同一偏好被写进了三条内容几乎一样但措辞不同的记忆检索时三条全返回模型反而被冗余信息干扰。后来直接在 Pipeline 里按 embedding 相似度做一轮过滤相似度高于 0.92 的就合并或丢弃问题立刻缓解。3.4 写入节流别让 Agent 变成“话痨记录员”模型自带主动写记忆的能力后会有一个新问题写得太频繁。每轮对话里用户的随口一句“今天天气不错”都可能被模型当成事实存下来内容越来越脏真实重要信息反而被淹没。我的解决方案是在配置里加上 write_control其中最关键的一条是 max_entries_per_session。默认 20 条对于大多数 QA 类会话完全够用。另外加上一条硬规则同一 session 内已存过的高相似度记忆不允许重复写入。这两条规则叠加能把记忆的写入量削掉大半同时保留真正重要的内容。4. 第三步记忆治理防止“记太多”“记太乱”“记错了”有了存储、有了读写AI 已经能“记事”了但距离“靠谱”还差一步——记忆维护。人脑会遗忘、会修正、会整合记忆系统也得有这套机制。我把这一步叫做治理因为它在本质上解决的是“记忆质量”而不是“记忆有无”。很多项目死在半路不是因为 Agent 不记事而是因为时间一长记忆库里的内容又脏又乱又互相矛盾检索结果反而成为模型的负担。4.1 记忆冲突新旧信息打架以时间戳和用户确认为准记忆库里最常见的脏数据是冲突。用户第一次说“我不太在乎发货速度”两周后又说“怎么还没到急用”这两个说法明显矛盾。如果两条记忆都躺在库里模型检索时就会精神分裂反应一会儿慢悠悠一会儿火急火燎。我在实践中固定了一套冲突处理规则写入新记忆时与已有记忆做冲突检测方式是先对内容做语义向量比对再让模型判断是否存在互相矛盾的关系。检测到冲突后新记忆优先旧记忆标记为 superseded不直接删除以便追溯。对于重要度高于 0.8 的冲突不自动处理而是带着“用户上次这么说这次又说那样该以哪次为准”的问题主动询问用户让用户拍板。自动处理不是不可行但风险在于错的判断一旦固化比不做判断更麻烦。尤其在客服、医疗咨询这类场景里随随便便丢旧记忆可能导致承诺失效。4.2 记忆衰减与归档不是所有事都值得记一辈子记忆库里如果只进不出最终会变成垃圾场。我给记忆设置了生命周期fact 默认 90 天有效期episode 默认 180 天core 里的画像不设有效期但需要周期性复查。有效期到了以后记忆从正常检索池里撤出来进入归档池。这里有一个细节过期后完全删除我是不建议的因为很多业务问题需要追溯“用户当时是怎么说的后来是怎么变更的”。所以 OpenClaw 里的过期处理是“降权”而不是“删除”。检索排序时过期记忆排在最后面当用户主动触发“我上次说的那个事”这类查询时才把归档池拉出来做一次全量扫描。我在实际项目里还会同步生成记忆报告每周自动跑一次本周新增了哪些事实、哪些记忆访问频率最高、哪些关键偏好发生了变更。这个报告非常有用它能作为核心 memory 更新的依据也能帮你发现 Agent 是否对某些长期记忆存在依赖过重的问题。4.3 防“记忆中毒”和用户隐私边界做记忆系统还有一个不能回避的问题安全和隐私边界。记忆内容如果写得太“宽”把用户随口一句不那么妥当的话也存进长期记忆可能在后续某个完全不相干的场景里被检索出来造成误导甚至严重尴尬。我的做法是分两条线敏感信息标记。凡是涉及账号、支付、住址、健康等敏感信息在写入时自动打上敏感标签。检索时只有经过明确授权的场景才能触碰默认不参与召回。记忆可见性。用户有权查看和删除与自己相关的记忆。我在某个消费场景里加了“记忆管理”入口用户可以一条条确认“这条不需要再记得了”删除后 Agent 后续不再引用。这套机制多花两天开发但对用户信任感的建立作用远超预期。提示记忆治理不是一次性工作而是和业务场景绑定的持续运营。评估记忆系统的好坏不要只看它“记住了多少”要看“记住了多少对的、忘了多少错的”。5. 常见问题与排查实录长期记忆架构落地过程中我整理过一份问题速查表基本覆盖了这几个阶段最容易翻车的点。先给结论再讲一个实际的修复案例。5.1 问题速查表症状可能原因解决动作新会话完全“不记事”记忆工具未配置或触发条件描述太窄检查 save_memory 工具定义确认模型有调用权限记住了但检索不出来相关度阈值设置过高调低 relevance_threshold观察召回率变化检索出来一堆无关内容相关度阈值过低或语义向量质量差上调阈值替换更合适的 embedding 模型同一条信息反复写入缺写入前去重检测在记忆固化 Pipeline 中加入 embedding 相似度过滤旧记忆覆盖新记忆冲突处理策略错误以时间戳为新旧判断标准旧记忆标记 superseded越跑越慢文件存储条目过多启用向量库存储引擎或增加归档频率模型被记忆带偏记忆质量差、优先级排序失效检查 core 是否被低价值 facts 淹没调高 importance 排序权重5.2 实测案例某电商问答 Agent 的“失忆”修复记录接下来分享一个典型的案例我给某电商团队的问答 Agent 做改造。这个 Agent 的原始形态就是裸会话用户问尺码推荐、退换货规则、订单进度基本每次都要重新解释一遍。用户二次复购时往往会说“上次说的那个黑色款还有吗”Agent 根本不知道“那个”是什么。改造的第一步是搭存储层。我先用本地 JSON 建目录结构core 里写死用户的尺码偏好、发货偏好facts 按月归档订单咨询记录。第二步是给 Agent 接上 save_memory 和 recall_memory 工具。策略是会话初始时recall_memory 拉取该用户的高优记忆拼入系统提示对话过程中出现用户偏好表达时调用 save_memory 写入。第三步是治理每周跑一次记忆报告把重复的订单咨询记录合并把三个月前的尾部数据转归档。改造后的效果可以做个直观对比改造前用户第二次进来问“上次说的那双鞋的 41 码还补货吗”Agent 回复“您说的是哪款鞋可以再描述一下吗”。改造后Agent 能检索到用户上次会话中浏览过某款鞋并询问过 41 码库存直接回复“这款鞋 41 码目前有现货需要帮您加入购物车吗”。这个案例最让我意外的不是检索本身而是记忆报告的价值。跑了三周之后报告发现这个 Agent 对“退换货时效”相关的记忆访问特别频繁但原配置里相关记忆的重要度权重偏低导致偶尔会遗漏。我们把这类记忆的 importance 权重调高再配合 top_k 扩容问题就消失了。这个经验说明记忆系统要能“被观察”否则你很难知道它在实际业务里哪里好使、哪里不好使。5.3 排查顺序建议如果记忆系统出了问题我建议按“由底到顶”的顺序排查先看存储有没有数据写入再看检索能不能召回最后看模型有没有在正确时机用工具。很多人一上来就调 prompt结果一查发现记忆根本没写进去白折腾半天。我之前排查一个“检索不到旧记忆”的问题发现是配置文件里的 time_decay_factor 设得太大把一个月前的记忆衰减到接近零分。把衰减因子从 0.3 调回 0.1问题立刻解决。有时候最不起眼的参数反而是最核心的坑。6. 最后再分享一个实战体会如果你问我现在重新搭一个记忆架构哪个环节最值得提前铺路我会毫不犹豫说是 schema 设计和目录规划。存储引擎可以后面换工具调用可以慢慢调但数据一旦入库想改 schema 就是牵一发动全身。早期多花半小时设计好目录和字段命名后面省下的返工时间是以天计的。另外记忆系统做完了不是终点要留运营入口。无论是记忆报告、用户可见的记忆管理页面还是后台对“什么记忆被高频访问”的分析都能帮你持续校准这套系统的质量。我第一次做的时候忽略了这两点结果上线后发现库里累积了不少脏数据又花了整整三天清洗。如果你正在搭类似的长期记忆方案尽量绕开这个坑。长期记忆这件事本质上是把“模型的聪明”和“系统的持久”拼在一起。模型负责语言理解和推理系统负责记录和检索两者各司其职AI 才能像人一样既会聊天又记得住聊过什么。希望这套三步思路能帮你在自己的 Agent 项目里少走点弯路。