1. 智能体失忆的真实代价上下文窗口不是记忆库只是一张工作台先说一个我实际撞上的场景。团队里有个基于 OpenClaw 跑的智能体负责整理客户反馈、生成周报、跟踪需求状态。前两三轮对话一切正常它能准确说出上周三那位用户提到的权限问题还没关闭。等跑到第二十几轮它开始含糊其辞把两个不同项目的需求混在一起再往后它甚至礼貌地反问您之前提过这类问题吗。不是它变笨了是它的记忆被新内容挤出了上下文——也就是大家常说的AI 失忆。这其实不是玄学。大模型的上下文窗口无论做多大终究是工作台不是仓库。工作台上只能摊开有限的材料新材料放上来旧材料就被扫到地上。你在台上摆了一张旧需求单丢了它无从判断对错。长期记忆架构要解决的就是地上那些被扫走的材料如何被有选择地捡回来、归好类、下次要用时能准确递回台上。更麻烦的是上下文漂移对话越长注意力越分散模型对早期信息的引用权重越低。哪怕你的旧信息还残留几个字在里面模型也更倾向根据最新提问编一个看似合理的回答。这种漂移不同于单纯超限它更难察觉因为大多数场景里它不会直接报错只是答案慢慢变得不准。所以靠加大窗口或者把历史全塞进 system prompt都解决不了记忆问题。前面的方案治标后面的方案会很快被 token 成本压垮。真正靠谱的做法是把记忆从上下文里抽离出来做成独立的三层架构采集层、存储层、注入层。OpenClaw 这类智能体框架恰好提供了一套可插拔的执行环境让我不用从零去搞多轮对话状态机可以把精力集中在记忆本身的工程化上。下面我就按当时的落地顺序拆一拆这套三步走的长期记忆架构每一步到底在做什么、配置怎么定、哪些地方最容易翻车。2. 第一步划分记忆边界——先决定记什么再讨论怎么存2.1 记忆不是一个大箩筐按用途拆成四类我先犯过一个典型错误试图把智能体见过的所有句子都扔进存储。跑了几天后库里面什么都有问它正事反而答得支支吾吾——因为无关信息把召回结果污染了。后来我把记忆按用途拆成四类每一类采用不同的采集和保留策略记忆类型典型内容保留策略召回场景用户画像称呼习惯、语言风格、关键偏好长期保留可覆盖更新每次对话开场事实记录项目状态、某个结论、审批结果长期保留合并去重对应任务被重新提及事件流水某次操作的日期、报错信息、临时结论短期保留定期归档摘要排查类、回溯类问题决策记录为什么选了方案A不选方案B长期保留与事实记录关联方案讨论、需求变更这个分类不是拍脑袋。它的核心逻辑是不同记忆的保鲜期和消费方式不一样。用户画像几乎每次都该被回忆起来事件流水则只有当事后复盘时才需要精确到那天报了什么错决策记录则是重看当时语境就能避免反复纠结。2.2 采集规则在流程节点上设置记忆钩子确定了分类之后下一步是采集动作。不是每句话都值得记而是要在关键节点设置记忆钩子。在 OpenClaw 里我主要通过任务流程的开关位来触发记忆操作比如一条任务状态发生变化从进行中变为已完成——触发事实记录更新用户明确表达偏好以后默认用中文回复——触发用户画像写入一次工具调用返回了异常结果——触发事件流水写入多轮对话后生成了结论性内容——触发决策记录写入。以任务状态变化为例伪代码大概长这样def on_task_status_changed(task_id, old_status, new_status, extra): if new_status in (completed, blocked, cancelled): memory_api.write({ type: fact, subject: task_id, summary: extra.get(summary), status: new_status, updated_at: now(), }) if new_status blocked: memory_api.write({ type: event, subject: task_id, level: warning, detail: extra.get(reason), created_at: now(), })这里有个关键点写入动作要跟业务流程绑定而不是跟模型输出绑定。所以触发条件尽量落在确定性的流程节点上别让记忆采集本身变成一个靠大模型自觉的额外任务。2.3 过度保存是另一种失忆去重、压缩、过期记忆系统的第一原则不是记得多而是记得准。存了一堆重复记录之后召回结果会被同一信息的高频出现带偏反而让真正关键的异动信息沉底。我做三件事来控制保存质量主体去重以 task_id / 用户 ID / 项目 ID 为聚合键。同一主体下的新增记录先和已有记录做一次相似度判断相似度超过阈值就直接覆盖而不是追加。信息压缩事件流水超过 50 条时把更早的 30 条用一次摘要任务压缩成一段历史背景存回事件库。原始明细可以放进归档层不参与常规召回。过期失效事件流水默认 30 天有效用户画像则只保留最近确认过的那一版。过期不是必须删而是打上inactive标记在召回排序里直接降权。这个机制的价值在项目跑了两个月后才真正体现出来记忆库体积没有爆炸式增长而且召回出的第一条记录往往就是当前最有用的那一条。2.4 落地模板一条记忆记录至少要有这些字段我在 OpenClaw 里把记忆的记录格式统一成一个 JSON 结构{ id: mem_20250304_001, type: fact, subject: task/PRD-223, created_at: 2025-03-04T10:15:0008:00, updated_at: 2025-03-04T10:15:0008:00, active: true, content: { summary: 移动端权限申请流程已确定采用后端鉴权方案, detail: ... }, source: { session_id: ..., node: decision_point }, tags: [mobile, auth, decision] }字段名不重要重要的是这套结构能支撑后续三类操作按 type 区分召回策略、按 subject 做去重聚合、按 active 标记做权重排序。一旦这些基础字段缺失后面第二步做索引、第三步做注入时都会非常别扭。3. 第二步持久化与召回——用结构化 语义化两条腿走路3.1 先存储本地再考虑扩展不少教程一上来就推荐上矢量数据库我不太认同。记忆系统的第一步诉求是可靠、可查、可备份不是支持十万条并发检索。像 OpenClaw 跑在单机上本地存储完全够用。我当时用本地 KV 存储 定期快照备份的方式跑了两周零事故才逐步引入更复杂的索引层。选择存储介质时建议优先考虑三个条件写入延迟足够低别让记忆写入拖慢主流程支持结构化过滤按 type、subject、tag 过滤和模糊查询备份恢复简单出问题能秒级还原现场。结构化存储解决的是我记得有件事但记不清关键词的问题。比如用户问上周那个权限问题后来怎么处理的——通过 typefact、subject 包含权限、updated_at 在最近 7 天这三个过滤条件就能快速锁定几条候选记录。3.2 记忆分层热记忆、温记忆、冷记忆存储上我按调用频次把记忆分成三层热记忆当前对话和任务需要用到的记录缓存在内存里会话结束即释放温记忆近期活跃、可能再次使用的记录存在主存储里支持高速检索冷记忆历史归档压缩存储只在显式回溯时读取。这个分层的好处是检索时不用每次都全量扫描。先查热记忆没有结果再降级到温记忆。绝大多数场景下热记忆就能覆盖需求只有做历史复盘时才去翻冷记忆。分层降级式检索比单一大库捞针要高效得多。3.3 召回策略三种方式混合别只迷信语义向量召回模块是记忆系统里最容易看起来高级、用起来虚的部分。我实测下来纯向量召回偏差很大尤其是当你用一句话去查一个事实型记忆时相似度排名第一的可能根本不是你要的那条。我建议同时维护两类索引召回时做加权融合结构化索引按 type、subject、tags、status 做精确匹配。这类索引返回的结果几乎不会错只是返回数量可能偏少语义索引把 content 部分做成向量在没有明确的过滤条件时按语义相似度召回时间衰减权重事件流水类记忆时间越接近当前权重越高事实记录和用户画像则相反只要 active就不随老化降权。召回结果最终按结构匹配权重 x 0.6 语义匹配权重 x 0.3 时间权重 x 0.1这样的经验权重去排序。正好前两步已经把结构化字段设计好了这一步只是把它们用起来。3.4 写回问题不让记忆库变成垃圾场持久化层的另一个大坑是重复写入。AI 助手在对话中经常会重复类似的指令比如用户每隔几天说一次记得用表格回复。如果你每次都写入用户画像时间一长同一偏好的多条记录互相打架召回排序完全被搅乱。我的对策是先查后写写一个记忆条目前先在结构化索引里按type subject content 摘要做一次查重。相似度超过 0.85就走更新路径而不是新增路径。底层用简单的余弦相似度即可不用上重模型def write_memory(record): existing search_structured( typerecord[type], subjectrecord[subject], top_k3 ) for e in existing: sim cosine_similarity(record[content], e[content]) if sim 0.85: update_record(e[id], record) return insert_record(record)这个先查后写的习惯直接让我的记忆库从每周膨胀 120% 降到了 20% 左右召回率反而更稳了。4. 第三步注入循环——把记忆精确放回上下文中存储做得再好如果记忆不会在合适的时机回到提示词里这套架构就只是只写不读。第三步才是决定用户体验的关键什么时候注入、注入多少、怎么处理冲突。4.1 注入时机开场注入、任务注入、冲突注入我设计了三个注入时机覆盖大多数场景。开场注入发生在对话最开始时。把用户画像、近期的决策记录、与当前话题相关的活跃事实作为背景资料附加到系统提示词里。这种方式成本最低适合面向固定用户的助理型智能体。任务注入则是当用户发起的请求命中某个 subject 时再临时召回相关记忆。比如用户问现在的权限方案是什么系统先用结构化索引查出 subject 包含权限的最新记录把结果注入到当前这轮请求里。冲突注入针对的是用户提到某个事但当前系统状态与记忆不一致的场景。这时候需要把记忆和现场状态同时放到上下文里让模型意识到矛盾并主动向用户确认而不是自作主张覆盖数据。4.2 预算控制给记忆分配 Token 上限而不是无限装把所有召回结果全塞进上下文的后果比不注入更糟糕相关记忆被淹没在大量背景材料中模型反而无法分辨主次。我的做法是先定预算再取舍。以一条 2,000 token 的回复上下文为例我会把记忆注入控制在总 token 的 15%~20% 左右也就是 300~400 token。在这个预算内按结构化匹配分 语义分 时间分的顺序取 top N 条记录每条记录还要做一次压缩用户画像只保留 1 条摘要不超过 80 token事实记录只保留subject status summary三个字段去掉 detail事件流水只保留时间 事件类型 一句话结果。如果某条记录的 detail 特别长但结构匹配分又很高就先注入摘要版本并提示模型如需详细信息可要求展开查看。这样既保住了核心记忆又不会把模型窗口塞满。4.3 冲突解决旧记忆和新事实打架时怎么办这是长期记忆里最微妙的部分。比如上周记忆库写着方案确定用后端鉴权这周现场状态变成了计划更改为前端实现。如果只注入旧记忆模型会拿旧信息跟用户对峙如果只注入新状态那记忆库的历史价值就没了。我给记忆记录加了版本链同一 subject 下每次更新都保留 previous 字段指向旧版本。注入时同时把最新版本和上一版本的差异描述放进去让模型知道存在变化、旧方案已废弃、新方案生效中。这样 AI 在回答时就能避免自相矛盾。更简化一点的版本链结构{ id: mem_20250304_003, type: fact, subject: PRD-223/auth-scheme, active: True, content: { summary: 已切换为前端实现, detail: ... }, prev: { content: { summary: 采用后端鉴权方案 }, superseded_at: 2025-03-04T10:15:0008:00 } }有了版本链冲突注入的实现就简单了只要最新记录带 prev 字段就把历史方案 切换时间 新方案一起送入上下文AI 自然能按要求回答问题。5. 实测中的意外坑早期接入阶段容易翻车的三个真实问题5.1 记忆召回过多反而拖慢响应也拖低了准确率第一次把召回上限调高时我以为记得越多越聪明。结果测试中模型输出质量明显下降——它开始引用大量不相关的旧背景回答措辞变得含糊、保守。原因是注入过多记忆后模型分辨不出哪条是当前任务真正需要的。后来我在召回模块里加了一个相关性门槛结构匹配分低于 0.5 的记录直接丢弃语义分低于 0.45 的也丢弃宁可少召回也不要召回一堆混淆信息。实验下来召回数量减少了 60% 多回答准确率反而提升了。5.2 记忆写入时机不当数据被过早覆盖第一次做先查后写时我按 subject 去重结果把事件流水也聚合掉了。比如同一天内发生了三次权限校验失败按 subjectsummary 去重后三次失败被压成一条记录细节全丢了。排查问题时根本看不出故障频率。教训是去重策略要和记忆类型绑定。用户画像和事实记录可以做覆盖式更新事件流水必须保留原始多条只做时间窗口聚合不能做内容覆盖。5.3 输出格式绑定太死模型续写时记忆格式被污染有一个隐蔽的坑记忆条目内容包含纯文本时还好一旦包含 JSON 格式的片段模型在续写时可能把记忆字段和回答混在一起甚至在回答里输出残留的 JSON keys。这跟提示词模板的严格程度直接相关。我最终的方案是在注入时先把记忆内容包装成参考信息块区分于用户问题同时在提示里明确要求模型不要引用记忆的字段名只引用信息的意思。这样可以大幅减少格式污染。6. 这套架构还能往哪个方向扩展三步架构把采集、存储、召回、注入四个环节串成了闭环。目前我只能算跑通了 80% 的场景——日常对话、任务跟踪、状态回溯都够用。剩下 20% 集中在两个方向跨会话的事业主线记忆。现在记忆还是按对象拆开的跨多个任务的长期偏好整理需要更强的语义聚合能力。比如用户经常在涉及安全类话题时要求谨慎保守这种跨任务偏好可以自动提炼成更高层的用户画像。记忆的可解释性。现在我能知道系统把某条记忆注入了某个回答但没法直观看到为什么是这条而不是那条。下一步我可以把召回时的分数和排名输出到调试面板方便复盘错误回答时定位是采集问题、索引问题还是注入时机问题。记好一个原则记忆系统不是越复杂越好而是越可控越好。每一步调整都要能量化——多存了哪类数据、召回命中率变了多少、token 开销变了多少拿数据说话AI 才不会稀里糊涂地失忆。