Agent Memory Management

为什么需要 Memory

LLM 原生没有记忆

大语言模型本质上是类似 y = f(x) 的函数

其中 x 是用户输入,模型参数 ABC 在训练结束后就固定了,不会因为输入的改变而改变

因此原生 LLM 没有任何记忆能力

我们之所以觉得大模型"有记忆",是因为采取了上下文注入的方式:把历史对话 S1S2......直到最新的输入 Xn 拼成一个很长的序列丢给 LLM

LLM 凭借注意力机制"看到"历史记录,从而看似有记忆。

上下文窗口的局限性

即使采取了上下文注入的方式,存在两个问题:

问题 说明
存储空间有限 对话轮次越多,输入序列越长,资源负载越重,最终可能导致 LLM 无法执行
注意力扩散 上下文过长时,LM 无法把注意力正确放在关键内容上,导致幻觉或答非所问

因此需要限制上下文窗口(Context Window)

目前业界主流采用 200K tokens 作为窗口大小------这个数值是通过大量实验得出的平衡点:一方面支持足够的上下文,另一方面避免注意力涣散


朴素方案:Sliding Window

原理:当窗口填满时,丢弃旧内容,移入新内容

缺陷:以前的内容大概率不如新内容重要,但很容易举出反例

比如用户在第一轮对话中做了自我介绍、设置了个性化偏好(如"请用中文回答"),一旦被滑动窗口划走,这些关键信息全部丢失。


主流方案一:基于数据库(类 RAG)

对话记录本质是一串文本,与公司文件库没有本质区别。天然适合用传统 RAG(检索增强生成)的方法处理:建立数据库 → 存储切分后的文本块 → 检索 → 加载回上下文。

存储流程

  1. 切块(Chunking):如果历史消息很长(如几千字),可以按段落或按字数切分
  2. 添加元信息:提取 topic、用户偏好等语言信息,一并嵌入到 chunk 中
  3. 插入数据库:使用 Elasticsearch 等数据库,支持关键字搜索(BM25)和向量搜索(Vector Embedding),甚至混合搜索

检索流程

检索时主要有两种套路:

方案 A:止取(不经过 LLM)
  • 将用户 query 直接 embedding 成向量
  • 在数据库中进行比对检索(关键词搜索 + BM25 评分)
  • 优点:速度快,不需要额外消耗 token
  • 缺点:无法理解语义,对复杂查询的召回效果有限
方案 B:经过 LLM(ReAct 模式)
  • 由 LLM 分析用户 query,生成更合适的搜索方案(确定关键词等)
  • 从数据库检索到一堆文档后,让 LLM 做 reasoning 判断内容是否足够
  • 如果不够,调整优化 query,重新检索(refine)
  • 优点:语义理解能力强,检索更精准
  • 缺点:消耗更多 token 和时间

最终处理

无论哪种方案,检索得到的 chunk 都被插入到上下文 Context Window 中,再附上 query,一起交给 LLM 处理。


主流方案二:基于 Markdown(蒸馏压缩)

这是 Claude Code 使用的方法,被很多人归为业界标准。但核心痛点是"写代码",该方案有天然的优势,需要具体问题具体分析。

三层记忆结构

第一层:Memory(长期记忆)

特点:跨 session 永远生效,永久加载到上下文窗口。

典型内容

  • 用户编号(Profile)
  • 用户偏好(User Preference),如"生成内容时尽可能少辅助信息,多用代码回答"
  • 全局约束(Constraints),如"删文件时必须提示我"
第二层:Topics(专题记忆)

特点:按 topic 划分,每个 topic 是一个独立文件。

典型场景 :用户让 agent 写数据库接入代码,会涉及 topic database_deployment,从中提取结构化信息:

  • type:例如 MongoDB
  • version:例如 8.0
  • constraints:约束条件

更新机制 :当内容发生变化时(如 version 从 8.0 升级到 8.1),在 topic 文件中记录 Historical 信息,便于回溯和查找 bug。这样 LM 就能意识到旧记忆可能已过时。

加载机制:只有当当前对话涉及某个 topic 时,才会把对应 topic 内容加载到上下文窗口中。

第三层:Transcript(兜底层)

原生的原始对话记录,保存在 message 文档中。作用:万一前两层都命中不到相应信息,可以从原信息中回溯查找。

注:从性能上看,Transcript 的查找效率不如第一种 RAG 方法。但若能在前两层命中关键内容,效果往往更好。

结构化维护方法

Markdown 本质上是纯文本文件,手动维护更新非常痛苦(如需要读取文件、定位行、删除内容)。

标准做法

  1. 加载时:将 Markdown 结构化为 JSON / Dict 数据结构
  2. 更新时:让 LLM 进行 distill(蒸馏压缩),按预定义的 key 生成结构化 Dict,逐项更新 Dict 内容
  3. 落盘时:将 Dict 重新渲染回 Markdown 格式输出

这样做既规范又稳定,避免 key 偏移的问题。


冰与火:Key 定义的 Trade-off

在 distill 过程中,最核心的不稳定点在于:key 是预定义的,还是让 LLM 自由生成

最冰端:Predefined Keys

  • 把固定的 key(如 profileuser_preferenceconstraints 等 20 个 key)写入 system prompt
  • 让 distill agent 按这 20 个 key 归纳总结
  • 优点 :非常稳固,即使 LLM 生成了同义词(如生成了 overview 而不是 profile),可以通过 merge 代码将其映射回正确 key,再丢回给 LLM 让它生成一模一样的 key
  • 缺点:不够灵活,可能无法覆盖新场景

最火端:LLM 自定义 Keys

  • 所有 key 都由 LLM 生成
  • 优点:更动态,可以适应新场景
  • 缺点 :不可控。例如第一轮 distill 生成了 overviewfocus,第二轮可能生成 profileconcentration,需要多轮次判断 overviewprofile 是否应该 merge,新 key 是 append 还是 update

业界中庸之道

取长补短,在中间状态平衡:

  • 预定义足够广泛的 key,让 LLM 不需要自造词
  • 也保留让 LLM生成新 key 的能力
  • 既保证稳定性,又保持灵活性

如何让 LM 知道存在哪些 Topics

需要解决一个问题:LM 怎么知道该加载哪个 topic

方法一:主动搜索

给 agent 一个 agent 去遍历所有 markdown 文件,列出有哪些 topic 可用。

方法二:轻量化写入 Memory

在 Memory 文件中维护一个轻量化的 key(如 known_topics),只写简短简介(因为 Memory 是永远加载的,不能太长)。LM 看到这个列表就知道有哪些 topic 可以加载,避免每次都做遍历操作。

两种方法对比:

方法 优点 缺点
主动搜索 全面 多一次 LLM 调用 + 多一次遍历,额外 token 消耗和时间开销
写入 Memory 减少调用开销 需要维护,且 Memory 会变长

总结

Memory 是 Agent 设计中的重中之重。好的 memory 设计几乎在很大程度上决定了 Agent 到底好不好用。

对比:

维度 数据库方案(IAG) Markdown 方案(Distill)
核心原理 把历史当文件,检索召回 把历史蒸馏压缩成结构化信息
优点 检索精准,支持混合搜索 结构化程度高,可回溯,Claude Code 在用
缺点 原生数据检索慢 distill 过程不稳定,key 定义有 trade-off
适用场景 需要精确匹配、关键词搜索 写代码、写文档等有明确 topic 的场景
相关推荐
searchforAI5 小时前
2026年AI笔记工具对比实测:NotebookLM、通义听悟、Ai好记怎么选?
人工智能·笔记·gpt·ai·whisper·音视频·语音识别
阳明山水5 小时前
LightGBM为何胜过Prophet做销量预测
人工智能·深度学习·机器学习·微信公众平台·微信开放平台
We Just Keep growing5 小时前
【MySQL进阶篇】—— 视图、存储过程、存储函数、触发器
数据库·mysql
硅谷秋水5 小时前
世界模型:架构、方法、推理与应用的综述(下)
人工智能·机器学习·计算机视觉·语言模型·机器人
硅谷秋水5 小时前
世界模型:架构、方法、推理与应用的综述(上)
人工智能·机器学习·计算机视觉·语言模型
隔窗听雨眠5 小时前
AI有没有自我意识
人工智能
春风野草5 小时前
第五章 记忆系统不是假装记住——3层记忆架构的坑与遗忘的艺术
人工智能·ai编程
ylscode5 小时前
谷歌发布 Gemma 4 12B:面向消费硬件的民主多模态人工智能
人工智能
人工智能培训5 小时前
打造行业知识图谱三步走
大数据·人工智能·机器学习·3d·知识图谱·agent