Appearance
短期记忆就是当前对话的上下文,所有的历史消息,system prompt,工具调用结果都在里面,直接存在context window里,llm每次推理都能看到
长期记忆是跨会话持久化的知识,比如用户偏好、项目上下文、过往的决策记录,这些数据存在外部存储里,比如向量数据库、文件系统等,需要的时候注入到context里面
短期记忆的管理策略
context window总归是有上限的,一个复杂的编程任务聊一会,加上工具调用很容易就突破限制,这个时候就要做压缩compaction,常见的有三种
- 滑动窗口,只保留最近n轮对话,最简单但会丢失早期重要上下文
- 摘要压缩,让LLM对历史对话生成一段摘要替换原始信息,LangChain的ConversationSummaryMemory就是这个思路
- 选择性保留,根据消息的重要性打分,重要的原文保留,不重要的压缩或者丢弃
生产环境一般是组合使用,比如system prompt和最近5轮对话原文保留,更早的历史做摘要压缩,工具调用结果只保留关键片段
长期记忆的存储和检索
长期记忆的核心问题是存什么和怎么搜
存储内容一般分为三类
- 事实性知识
- 经验性知识
- 项目上下文,代码结构,技术栈选型记录
检索方式主流是混合检索
- 关键词检索
- 向量检索(语义匹配)
两者的结果做rerank
短期记忆到长期记忆的自动转化
一个关键设计模式是Memory Flush(记忆刷盘)
当对话接近压缩阈值的时候,系统先触发一次llm调用,让模型把当前会话中的关键信息(决策、代办、偏好)等,提取出来写到持久化存储里,然后再做压缩
这样即使历史消息被压缩或丢弃,关键信息还能通过长期记忆检索回来
另一种设计是会话结束时自动归档,系统把本次会话内容持久化成记忆文件,实现短期记忆到长期记忆的自然过渡
MemGPT把这个机制做的更极致,它直接让LLM自主管理自己的记忆,模型可以主动决定把什么存到长期记忆,什么时候从长期记忆里检索,什么时候更新或删除旧记忆,本质上把记忆管理也做成工具调用
常见的坑
- 长期记忆写入太频繁会导致噪音过多,检索质量下降,要做去重和过期清理,比如30天没被检索命中的记忆自动降权
- embedding模型换了之后,旧的向量全部作废,需要重新索引,生产环境要在记忆数据里同时存原文,方便后续迁移
- 短期记忆的压缩策略如果太激进,模型可能会出现失忆的表现
context window快满了,如何决定哪些消息要压缩,哪些要保留
- 最简单的判断就是这条消息对当前任务有没有用,system prompt一定保留,最近3-5轮对话保留,工具调用结果只保留摘要,对于更早的消息,可以让llm去打分,低于5分就丢掉,5-8分的压缩成摘要,8分以上原文保留,LangChain的ConversationSummaryBufferMemory就是类似的思路,维护一个token上限,超了的就把最早的消息做摘要
向量检索召回的内容不相关怎么办,明明存了相关记忆但是搜不到
- embedding模型的语义理解能力不够,换一个更好的模型,比如维度更高
- 存储的文本粒度不对,可能粒度太粗了,要做chunk切分,一般500-1000token 一个chunk,带100token的重叠
- 纯靠向量检索不够,还要加个全文检索做混合检索,BM25对精确关键词检索比向量匹配效果好
MemGPT让LLM自己管理记忆和人工设计记忆管理策略相比,哪个更靠谱
各有适用场景
- 人工设计的策略确定性强,可控性好,适合生产环境里对可靠性要求高的场景,比如客服系统、企业知识库
- MemGPT的自主记忆管理灵活性更强,模型可以根据对话内容动态决定什么,搜什么,适合开放域的个人助手场景,但是MemGPT每次记忆操作都要额外消耗token
- 目前生产环境用的更多的还是人工策略+少量自动化,比如会话结束的时候自动归档,压缩的时候自动提取摘要
如果用户隔了一个月回来继续老项目,怎么帮agent快速恢复上下文
- 靠长期记忆做冷启动,用户开始新会话的时候,系统先从长期记忆里检索跟当前项目相关的所有记忆条目,按照时间和相关性排序,取top10-20,同时把上一次会话的摘要也加进去
- 关键是长期记忆存的时候要打好标签、项目名、时间戳、内容类型这些都要有,不然检索出来全是垃圾