首页 / 资讯中心 / 文章详情

AI长期记忆系统Mindbase:从分层到遗忘的完整设计实践

AI长期记忆系统Mindbase:从分层到遗忘的完整设计实践 ★ FEATURED ARTICLE
你有没有遇到过这种情况同一个AI助手上个星期刚刚解释过的事情这周又得从头解释一遍。你把偏好告诉它下次会话它依然对你一无所知。大模型本身是一个无状态的推理引擎它不负责持久化任何信息——每一次新会话都是全新的开局。做智能助手的人都会撞上这堵墙助手可以很聪明却永远像“初次见面”。靠把上一次会话的摘要拼进本次提示词前缀能缓解这个问题但解决不了根本矛盾。摘要会越积越长吞掉大量上下文预算旧摘要和新事实混在一起模型分不清哪些已经过时如果用户中途改了主意旧信息反而会把模型带偏。所以一个真正可用的长期记忆系统核心难点不是“记住”而是“记忆本身的可管理性”。Mindbase 这个名字我的理解是把 AI 的记忆做成一个独立的基座而不是嵌在某个应用里的临时变量。围绕这个目标我断断续续做了两期迭代踩了不少坑。这篇文章就把整个设计过程从头拆一遍记忆怎么分类、怎么写入、存在哪、怎么检索、怎么遗忘。适合正在做对话机器人、智能助手、客服系统或者正在纠结“怎么让 AI 记住用户偏好”的朋友参考。我会尽量把每个选择的“为什么”讲清楚而不是只丢结论。1. 为什么AI需要长期记忆Mindbase要解决什么问题1.1 先看清问题根源上下文不是记忆很多人在设计记忆功能时第一个直觉是把上下文窗口当记忆用。这其实混淆了两个概念上下文窗口是推理时的“工作台面”它决定模型这一轮能看见多少信息而长期记忆是“仓库”它决定哪些信息值得被反复取出来放到台面上。上下文窗口有两个天然缺陷。第一它有容量上限塞不下长期积累的全部信息第二会话一结束窗口里的内容就没了。你可以把每次对话想象成一场即兴演出模型演技很好但下台就忘词。所谓长期记忆系统本质上是在舞台后面加了一个后台团队负责记录、整理、归档然后在合适的时机把需要的“台词卡”递回到舞台上。Mindbase 要解决的核心问题就是把这套后台流程工程化。它不只是加一个“记忆数据库”而是做完整的生命周期管理哪些信息值得记录如何从对话中提取怎样存储才能既快又准什么时候该把记忆送回对话以及什么时候该遗忘。1.2 四个具体的设计目标可持续积累记忆越存越多但检索精度不能跟着下降。如果存了一万条之后反而找不到该找的那条这个系统就是负资产。按需唤醒不是每轮对话都要把全部记忆搬出来而是根据当前问题召回最相关、最重要的部分。可更新、可纠正、可遗忘用户搬家了、换工作了、改主意了旧记忆必须能更新而不是堆在那里互相打架。成本可控记忆的写入、检索和存储都会带来模型调用和硬件开销不能让记忆功能反过来拖垮整个应用。这四个目标听起来是常识但真做起来全部满足非常难。我见过不少项目只做了“积累”和“召回”忽略了“更新”和“遗忘”结果一两个月后系统就开始胡说八道。所以设计一开始就要把生命周期想完整而不是先上线再补课。2. 记忆分层区分事件、事实、技能和场景上下文2.1 四种记忆类型与保留策略设计的第一个决定不是选数据库也不是选向量模型而是先定义“记忆到底是什么”。什么都不分类就往库里塞很快就会被检索噪音淹没。参考认知科学里常见的记忆分类我把 AI 的记忆拆成四类记忆类型含义典型例子保留策略事件记忆某时某地发生的具体事情上周四开过项目评审会用户上周提到要搬家蒸馏后进入长期原始日志短期保留语义记忆关于用户和世界的稳定事实用户在某行业工作对坚果过敏喜欢简洁回复长期保留支持更新程序记忆完成任务的偏好与约束汇报时先给结论翻译时保留英文术语长期保留作为行为规则工作上下文当前正在进行的任务状态正在填写注册资料第三步本会话刚确认的方案会话内有效结束即清理这四类的边界不是死的。比如“用户下周三搬家”听起来像事件但“用户从 A 市搬到 B 市”对长期影响来说是语义事实。我的处理方式是事件记录的是“发生了什么”语义记录的是“状态变成了什么”两者都写但用途不同。事件回答“上次提到过什么”这类问题语义回答“这个人长期是什么状态”这类问题。2.2 原料层与记忆层的分离同时在数据层面必须区隔两层内容原始会话日志完整对话文本短期留存除非有调试需要否则不参与检索。蒸馏后的记忆条目从日志中提取出来、结构化程度较高的记录进入长期库。为什么要多此一举做蒸馏因为原始对话直接存下来再向量化检索时会把语气词、闲聊、冗余表达全部搅进来而且很多记忆在对话当下根本没有明确表述要等整个会话回看才抓得住。这和我们人脑记不住连续录像、只打包关键场景是同一个道理。每条蒸馏后的记忆我要求必须带上来源标识和发生时间。来源标识看起来只是一个小字段但后面真出问题时没有它等于考古。这是 Mindbase 第一个踩坑点早期版本我为了省事忽略了这个字段后来用户反馈“系统记错了我的需求”我根本没法定位到底是哪次对话产生了这条错误记录只能全部删掉重来。3. 写入链路从原始对话到可检索记忆的加工过程3.1 触发机制不是每句话都值得记住记忆写入的第一步是判断“什么时候该写”。如果每句话都写系统很快就会被无意义内容淹没如果只在对话结束统一抽一次中途那些闪光的细节又容易在摘要过程中丢失。我的做法是双通道设计快通道用户明确要求“记住”“以后注意”“帮我记一下”时当场写入。这类请求不能拖延用户期待下一次对话立刻生效。慢通道每轮对话结束后在后台异步跑一次整段对话的提取任务负责挖掘隐含偏好和关键事件。慢通道的结果不是即时必需的可以排队处理用户完全感知不到系统正在“做笔记”。隐含触发的信号我总结了几类比较可靠的偏好词喜欢、讨厌、习惯、通常、尽量、新实体首次出现的人名、项目代号、地点、时间安排“下周”“月底”“三点”、纠正表达“不对是 A 不是 B”。这些信号不要求全部命中只要命中一个就进入候选提取队列。3.2 信息抽取让模型输出结构化记忆抽取这一步我用的是“让模型填表”的思路。给一个低温度的生成配置要求输出严格的结构化 JSON。下面是一个有代表性的返回示例{ memory_type: episodic, summary: 用户确认下周把项目汇报提前到周三并更换了评审人, entities: [项目汇报会, 周三, 评审人], importance: 4, occurred_at: 2025-06-20, conflict: false }抽取提示词的核心规则只有几条只提取明确表达的内容不臆测用户没说过的话同一实体出现属性变化时标记冲突拿不准重要程度时默认给低分避免系统被低质量记忆污染。严格限制格式非常重要否则后面解析 JSON 的代码会天天崩。3.3 去重与冲突处理抽取出来的结果不能直接入库必须先做去重和冲突检测。去重我用两层判断。第一层是实体匹配如果两条记录的实体列表高度重合再比较摘要的嵌入向量余弦相似度。相似度超过 0.9 我就认为是近似重复把其中一条合并进另一条更新访问次数。合并比硬删安全因为用户可能换了种说法表达同一个事实。冲突处理更讲究。用户说 A 地址过了两天改口 B 地址再过三天又改回 A。如果只维护一条记录来回覆盖你根本看不出哪条是最终态。Mindbase 的做法是给每条记忆保留状态字段和版本号新信息写入时把旧记录标记为 superseded新记录置为 active。这样既保留历史轨迹又保证检索时优先看到最新状态。3.4 嵌入与入库嵌入生成前我会把类型、摘要、实体列表拼接成一个标准文本再送进嵌入模型def write_memory(user_id, record, embedding_model): text_to_embed f{record[type]}|{record[summary]}|{record[entities]} vec embedding_model.encode(text_to_embed) insert_memory_record(user_iduser_id, recordrecord, embeddingvec)这里有一个我在实际项目中栽过的坑写入和查询必须用同一个嵌入模型连版本都要一致。中途换了模型新旧向量不在同一个语义空间里检索质量会肉眼可见地崩掉。如果确实要换必须安排存量向量重算任务否则线上会呈现一种“什么都存了但什么都搜不到”的诡异状态。4. 存储选型向量索引加结构化元数据的混合方案4.1 三种常见方案的取舍存记忆不只是存向量。记忆需要按类型过滤、按时间排序、按重要度圈选还要支持事务性更新。对比过几种方案之后我整理了一张选型表方案适合场景优势明显短板专用向量数据库海量、多租户、千万级记忆检索性能好专门优化 ANN复杂过滤和事务弱需要引入额外服务关系数据库 向量扩展中小规模、需要 SQL 管理事务、过滤、备份一体化超大规模向量搜索性能吃亏本地嵌入式库 本地向量索引桌面 / 移动单机应用零部署一个文件搞定多端同步和数据共享不方便Mindbase 第一版落在了“关系库 向量扩展”这个组合上。理由很实际个人助手场景的记忆量级大概在几千到几十万条关系库在这个量级完全够用记忆管理需要大量元数据过滤比如“最近三个月、类型为事件、重要度不低于 3”这种查询用 SQL 表达远比赛手写过滤舒服。选型不必一步到位能支撑两个月的迭代就是好方案等真到了多租户百万级再剥离向量检索也不迟。4.2 核心表结构下面是 Mindbase 记忆表的核心结构字段比较多但每个都有用途CREATE TABLE memory_items ( id TEXT PRIMARY KEY, user_id TEXT NOT NULL, mtype TEXT NOT NULL, summary TEXT NOT NULL, content TEXT, entities JSONB, importance INTEGER NOT NULL DEFAULT 3, status TEXT NOT NULL DEFAULT active, source_id TEXT, created_at TIMESTAMP, updated_at TIMESTAMP, last_accessed TIMESTAMP, access_count INTEGER DEFAULT 0, embedding VECTOR(768) );几个字段需要特别说明。mtype让不同类型走不同的保留和检索策略而不是一锅炖status是生命周期状态active、superseded、archived 三种source_id追溯原始对话access_count和last_accessed用来计算后面的召回排序权重。importance我限制为 1 到 5 的整数避免模型给出太复杂的连续分不好解释。4.3 索引与向量规范向量字段上建 HNSW 索引元数据字段按使用频率建普通 B-tree。一个容易忽略的细节是向量入库前必须做 L2 归一化查询时同样归一化之后算余弦相似度才稳定。如果不归一化向量的模长会把语义相似度带偏排名就会不靠谱。嵌入维度方面普通场景 384 到 768 维就够用了。维度越低占用越小检索越快维度太高可能过拟合噪音而且存储成本线性上升。刚开始不必追求大模型的高维向量先用够用的维度跑通流程观察召回效果再调整。5. 检索机制相似度、重要性与上下文预算的组合排序5.1 两类召回常驻记忆与按需召忆检索不是只有“拿当前问题去搜”这一种模式。我采用了两类召回常驻记忆重要度不低于 4 的关键事实比如严重过敏、紧急偏好、关键客户身份每次对话系统主动带上不需要用户问。这类记录数量必须严格控制在个位数否则就成了噪音。按需召忆每轮对话开始前用“当前消息 最近两轮摘要 当前意图标签”作为查询做混合检索。举一个常见例子用户问“今天天气怎么样”按需召回不该把“周三前需交付某报告”顶上来即使两边嵌入向量有点重叠。这时候元数据过滤和重要度缩放就起作用了——非工作相关意图把“交付”类事件整体压低。5.2 混合排序公式与参数调优召回候选集先过一道相似度阈值门槛低于 0.4 的不要避免无关记忆进来凑数。通过门槛的记录再按下式计算综合分score 0.50 * cosine_sim 0.25 * (importance / 5) 0.15 * recency_boost 0.10 * log(access_count 1) / log(max_access 1)recency_boost我用了指数衰减函数recency_boost exp(-0.05 * days_since_last_access)这组参数的含义是语义相似度仍然是第一权重但重要度能帮真正关键的记忆“插队”访问频率帮助当前活跃任务保持热度近期访问过的记录也会得到小幅加持因为它在最近刚刚被证明有用。参数没有放之四海而皆准的答案我建议上线后跑一周真实流量看排名结果再手动校准。排序之后还要做一步“记忆预算裁剪”。无论候选有多相关我给记忆注入设了一个上限最多注入 8 条或总共不超过 1200 个 token。记忆不能抢走用户问题本身的表达空间否则模型会变成“复读机”满口“我记得你说过”非常不自然。5.3 注入格式与语气控制注入到提示词里的记忆要格式化让模型一眼认出“这是历史记录不是当前指令”。我的格式大概是[长期记忆] 以下是系统中已记录的信息可能不完全准确请以用户当前表述为准 [2025-06-12 重要] 用户希望汇报先给结论再展开细节 [2025-06-18 事件] 与A同学确认两周后发布版本评审人改为Q [2025-06-20 事实] 用户的新办公室改到园区B座每条记忆带时间和类型标签方便模型判断新旧和性质。最关键的是那句“可能不完全准确以用户当前表述为准”。没有这句话模型会对旧记忆格外固执用户都改口了它还揪着旧信息不放。6. 遗忘与整合让记忆系统长期稳定运转的清理策略6.1 衰减与归档遗忘是记忆系统的分水岭一开始我只顾着“多写”结果第三个星期问题就来了检索结果越来越杂同一个用户的旧地址和新地址同时出现模型被互相矛盾的信息搞晕。能删、会忘、会合并才是记忆系统真正成熟的分水岭。Mindbase 的衰减规则很简单重要度为 1 且 60 天没有被访问的记录、重要度为 2 且 90 天没有被访问的记录状态置为 archived。归档不是删除检索时不查归档记录但用户想回看半年前的事依然能在管理页面找到。这样既保住了回查能力又不污染日常召回。6.2 冲突消解不要永远相信最后一条冲突消解我前面提过处理关键细节是“后写不直接覆盖”。正确做法是依据置信度和出现次数新值比旧值多出一次以上且时间更新才把旧值标记为 superseded如果只是单一一句“不对”我会先保留旧值同时把新值也写上并标注 conflict 状态留给后续整合任务裁决。这个设计救过我一次。用户先是说“周五有空”第二天又改口“周五不行了”第三天又确认“还是周五吧”。如果每次都直接覆盖最后只会留下模棱两可的一条保留痕迹之后整合任务才能看出“周五”才是最终稳定的答案。6.3 周期整合与层级压缩整合任务每周在低峰时段跑一次。它做两件事一是把同一实体、同一主题的事件记忆合并成一条摘要例如把六月中旬三次“讨论发布版本”的记录合并成“本周围绕发布版本讨论了三次最终结论是周三完成 beta”二是对超额重复的细节做剪枝。合并时原事件记录并不删除只标记为 merged。检索时优先返回摘要用户或模型想深挖时再向下一层展开。这里要设置层级上限我限制只做两层摘要防止“摘要的摘要的摘要”失去信息。整合任务用小型模型在空闲时段跑成本压力很小。6.4 用户必须拥有记忆的删除权记忆系统做得再准如果没有用户可见、可编辑、可删除的入口迟早会出现信任危机。Mindbase 提供了一个记忆管理界面用户能按类型和时间浏览记录能单条删除也提供“清空全部记忆”的选项。隐私维度上敏感记忆字段我做了加密存储并支持整库导出和物理删除。这不仅是为了合规更是一个很现实的原因如果用户感觉到 AI 在偷偷记自己的隐私但自己无法掌控他会选择不用这个产品而不是信任它。7. 实际踩坑记录与上线后的优化方向7.1 让我印象最深的三个故障嵌入模型切换导致检索暴跌。第一次把嵌入模型从 A 版换成 B 版没有重算存量向量。结果新旧向量不在同一个语义空间召回率肉眼可见下降。后来给向量加了模型版本字段并写了重算任务才算稳住局面。全量记忆注入导致“谄媚式”复述。早期不分权重地把二十条记忆塞进提示词模型动不动就引用“我记得你说过……”用户反馈很强硬。改成按重要度分档、只保留最相关 Top 5 后表现反而自然了。同步写库阻塞对话。第一版写入是同步的用户发一条消息系统要先做抽取再回复延迟直接爆炸。改成异步队列之后流畅很多。这再次印证记忆加工必须与对话主链路解耦用户不该等 AI 做笔记。7.2 五条落地建议先做召回精度再扩存储量。能精准找到对的那条记忆比能存一万条重要得多。每条记忆必须带来源、时间和重要度。没有这三个字段记忆出问题只能全库回滚。写入要有独立触发条件不要对每句话一视同仁全量捕获等于没捕获。排序要带门控和预算裁剪先过滤再排序排序后限制条数和 token。给用户遗忘权和管理入口否则系统再聪明也会让人不安。7.3 后续可以怎么扩展Mindbase 目前还是基于“条目 向量 元数据”的经典组合。往后有两个方向很有价值一是基于实体的知识图谱让“这次会议和上次会议有什么区别”这类跨记忆推理变成可能二是更精细的分层时间窗结合动态遗忘曲线让不同性质的记忆走不同的生命周期。这两个方向都需要大量真实使用数据来校准急不来。最后分享一点个人体会如果有朋友要照这个思路抄作业我的建议是先让它记住再让它学会不打扰。记忆系统做得再大、再智能如果用户每次对话都被无关信息干扰那依然是负分。另外一份可追踪、可删除的记忆远比一套炫酷的语义检索算法重要——先保证用户信任再谈智能。
阅读完成 · 觉得有帮助?
咨询建站