Q:为什么我的聊天智能体聊到第十轮就"失忆",开头说的事全忘了?
A:大概率是把整段历史一股脑塞进上下文,token 撑爆后被截断,最早那几句先被丢掉。靠堆历史记不住关键信息,得单独抽一份"实体记忆"出来另存。我用问答体把这套方法讲清楚。
Q:什么叫实体记忆?跟塞历史有啥区别?
A:塞历史是把每一句原话都留着,又长又乱。实体记忆是只抽出"值得长期记住的事实",结构化存。比如用户说"我叫张磊,对花生过敏,住在杭州",我存的是:
姓名: 张磊 过敏源: 花生 城市: 杭州下次对话不用翻历史,直接把这几条注入 system prompt,模型就"记得"了。原话可以丢,事实留着。
Q:怎么判断哪句话该记?总不能每句都抽。
A:我的做法是每轮用户发言后,跑一次轻量抽取,让模型只回答"这句里有没有值得长期记住的用户属性/偏好/约束"。有就返回结构化字段,没有就返回空。判断标准我给它列了几类:身份信息、明确偏好、限制条件(过敏、预算、忌口)、已做决定。闲聊寒暄一律不记。
一个坑:别让它太勤快。我一开始没限制,用户随口说"今天有点累"也被存成了长期记忆,下次对话模型还关心人家累不累,挺出戏。后来加了一句"临时情绪、一次性状态不要记"才正常。
Q:用户改主意了怎么办?比如先说住杭州,后来说搬上海了。
A:这是实体记忆最容易出 bug 的地方。我用"同 key 覆盖":抽取出的字段如果 key 已存在,新值覆盖旧值,并留个时间戳。城市从杭州改上海,直接覆盖。
但有些字段不能覆盖只能追加,比如"买过的商品"。所以我把字段分了两类:单值(覆盖)和多值(追加)。这块没法偷懒,得按业务一个个字段定清楚。我那张配置表当时列了二十多个字段,填得手酸。
Q:记忆存哪?要不要数据库?
A:我没上数据库。每个用户一份 JSON,存在会话状态里,注入时拼成几行文本塞进 system。量不大完全够用。真到了用户量很大、要跨设备同步,再考虑外置存储不迟——别一上来就过度设计。
Q:整套怎么落地的?
A:我在一个拖拖拽拽就能配智能体工作流的平台上搭的:用户消息进来 → 抽取节点(判断+结构化)→ 写入记忆 → 下一轮回复前把记忆拼回 prompt。抽取那步调的模型 API 走讯飞星辰 MaaS,现成接口,没自己养模型。
记忆这事的精髓是"少而准",记十条准的,比记一百条糊的有用得多。