这道题其实在问一个很实际的问题:当[[Agent]]的记忆规模大到一定程度,怎么存得快、找得准、还不丢关键信息?本质上是在存储容量、检索效率和相关性之间找平衡。
我会把记忆分成三层。最顶层是工作记忆,就管当前对话的上下文,用[[KV Cache]]或者[[滑动窗口]],毫秒级访问,这个没什么好说的。中间是短期记忆,存当前会话的完整记录,放在Redis或者内存里,支持快速读写。最下层才是长期记忆,跨会话、海量数据,得持久化。
长期记忆我不会只用一种存储。我的做法是混合方案:[[向量数据库]]做语义检索,关系数据库做结构化过滤,对象存储放原始对话。举个例子,一个客服Agent处理退款请求,用户问「我上周那个订单怎么还没退?」,向量检索找到语义相似的退款记录,关系库过滤出这个用户ID和订单状态,对象存储里再拿完整的对话日志做上下文补充。这样三条路配合,比单用向量库准得多。
检索效率方面,索引层我会用[[HNSW]]或者[[IVF-PQ]]做[[近似最近邻]]检索,亿级向量能做到毫秒级。但有个前提:如果数据量不大,比如只有几十万条,那HNSW的构建开销反而比全量暴力搜索高,这时候还不如用[[Faiss]]的Flat索引。另外,分区策略很重要,按用户加时间窗口分片,避免每次全量扫描。如果分区不合理,比如所有用户混在一起,那检索延迟会线性增长,上线后直接崩。
召回策略我倾向于多路召回。向量语义召回是主力,但关键词召回不能丢,比如用户要查一个具体的订单号,向量可能找不到精确匹配,[[BM25]]反而管用。还有图遍历召回,基于实体关系扩展,比如用户提到「上次那个客服帮我处理过」,Agent就得从[[知识图谱]]里找到相关实体。
排序这块,我会用特征融合打分:语义相似度、时间衰减、重要性分数、交互频率加权求和。时间衰减用指数函数,近期记忆权重更高。重要性建模靠LLM打标,比如用户明确说「记住了」或者「重要」的事件,重要性分数就给高。但这里有个坑:如果用户反馈稀疏,重要性分数会失效,这时候我会退一步,用交互频率做替代,比如用户反复查询的订单,隐式说明很重要。
记忆压缩机制我特别看重。直接用原始对话检索,规模一大就扛不住。我会定期用LLM压缩成摘要,而且是分层摘要:原始对话、段落摘要、主题摘要,检索时自顶向下。比如先找到主题「退款流程」,再下钻到具体对话。前提是LLM压缩不能太频繁,否则成本太高,一般按日或按事件触发。
说到压缩,我其实更关注压缩后的信息损失。比如摘要可能丢失时间线细节,导致Agent判断失误。所以我会在摘要里保留时间戳和关键实体,必要时回退到原始对话。这个平衡点怎么找,我觉得跟业务场景强相关。
整体上,我更倾向把长期记忆看成一种分层缓存系统,而不是简单的数据库。工作记忆是L1缓存,短期是L2,长期是磁盘。检索时从L1往下找,写入时异步批量刷到长期。这样设计,冷启动时用预构建的用户画像,写入瓶颈靠内存缓冲队列缓解,一致性用最终一致就行。