如何设计Agent的记忆模块

大模型 天生就有有记忆缺陷

就同HTTP请求一般,每次对大模型的请求,都是无状态的。

所以为了让大模型拥有记忆 ,就需要在每次请求里 面,携带上 他之前说过的话。从而模仿他的记忆,让他知道,自己是谁,为谁服务,服务什么,服务对象又有什么性格等等...

但是这就会遇到一个很严肃的问题。大模型的推理文本长度是有限 的。

也就是我们常说的上下文 。这就牵扯出 一个问题:

主流大模型的上下文长度也就1Mtoken左右。而国产大模型通常也就是256K左右。

这就意味着上下文长度是有限的 ,所以非常宝贵。

同时因为大模型的注意力机制的原因,上下文越长 ,推理的所需耗费 的几何倍上升 ,并且精度 也会越低

所以,记忆模块的设计,就至关重要!

为好奇的小伙伴,补充一下什么是注意力机制

他的核心就是自注意力机制 (Transformer),不再像RNN那样串行处理,而是一次性看待整段输入(可以并行处理)。
做法就是,对每个token 生成QKV 三个向量,计算出所有token的QK相似度得分 ,拿着这个相似度去和V做一个加权求和 。从而能让token和语境关联。
就相当于把苹果手机中的,苹果从原本的向量区间,拉到手机品牌向量区间那样。

一、记忆模块设计

在开始搭建记忆模块之初 ,最先做的并不应该是RAG!

而是在domain协议层,定下契约 。之后不论是写入、召回都会按照固定的格式进行。

通常记忆模块 会分四层
感知记忆 (当前的输入)、短期记忆 (上下文的压缩)、长期记忆 (沉淀后的记忆)、结构化记忆(存储的用户的习惯、爱好、目标等)。

而我在设计中,

我对所有的 memory 记忆类型 分为三种:

  • 结构化type。
  • 长期记忆
  • 上下文压缩后的摘要,服务与上下文恢复。

同时,为了保护用户隐私,我又分了三层。

  • self:用户个人隐私,像习惯、爱好、自己的上下文等。
  • org:组织级别的,拥有对应权限的人可以共享。
  • platform:平台运维级别的。

虽然有些功能,暂时不需要实现,但是协议是非常有必要提前定义好的。

二、记忆治理

第一部分,已经定义好类型权限 了。

但在入库前,更重要的就是定入库的规则。

我这里分为了两层:

  • 软规则:写进 prompt ,让 LLM 按照给定的规则去"理解和生成"。
  • 硬规则:负责最终"裁决和落库",像权限的过滤,字段的合法性校验等,尽可能的规避LLM生成的错误。

其中,软规则中的prompt更多是在告诉LLM。

  • 什么样的内容算高价值
  • 什么东西不能记
  • Fact、Document、摘要等等,给出来的东西应该是什么类型
  • 生成的是json格式
  • 等等...

硬规则 ,就是对生成的东西进行一次强校验。

就像权限范围TTL 等,都是需要自软规则 里面抽取出来,经过 一遍硬规则 的手。

确保一切没有问题。在入库。

我举个简单的例子:

比如用户说:

"以后请你回答时更简洁一点。我最近 30 天目标是刷 200 道题。"

LLM 可能提两个候选:

json 复制代码
[
  {
    "type": "fact",
    "namespace": "user_preference",
    "key": "answer_style",
    "value": {"style": "concise"},
    "source_kind": "explicit_user_statement",
    "scope_hint": "self",
    "confidence": 0.95
  },
  {
	 "type": "fact",
	 "namespace": "oj_goal",
	 "key": "current_goal",
	 "value": {"goal": "200 problems in 30 days"},
	 "source_kind": "explicit_user_statement",
	 "scope_hint": "self",
	 "confidence": 0.91,
	 "ttl_hint": {
	   "mode": "duration",
	   "days": 30,
	   "reason": "用户明确说最近 30 天目标"
	  }
]
  • 先判断一下致信度,太低的话直接skip掉。
  • 然后根据LLM生成的,开始配置一下权限,在过滤一遍TTL等,最后入库。

三、上下文压缩,以及上下文恢复

现在定义了如何记忆类型、以及允许什么样的内容入库。

但是另一个影响对话质量的就是上下文的质量。

也就是说:

下一轮对话到来时,如何在有限的 token 预算里,把真正有价值的上下文重新恢复给模型。

技术上,我了解最粗暴的方式,就是滑动窗口 ,自动将越界的删除掉。

其次就是摘要压缩 ,对越界的内容进行压缩后,在携带。但是这样会导致精度问题。

后来就有了层次压缩 ,如:最近10轮的压缩,10~50轮的轻度压缩,更后方的重度压缩。

但是这会导致一些重要信息,被裁剪忽略掉。

所以后来又出现了重要性过滤。不在一味的按先后顺序。等等...

所以我这里做的是分层恢复 策略。

我会将上下文分为好几层进行控制:

第一层放:最新的决策和最近确认过的重要结论,优先级放到最高。

第二层放:当前还没有闭环的问题、待确定的问题。

第三层放:会话级别摘要,用来恢复长对话主线,而不是历史回放。

第四层放:已经沉淀出来的用户偏好、阶段目标、画像信息等。

第五层放:一下RAG召回的经验等。

第六层放:最近的几轮的对话内容。

其中,我把用户最近一次的问题,放到了最后。

因为我之前在读arXiv的一篇论文(读 "archive"),参考他上面的内容:

模型对长上下文的中间信息利用很不稳定,相关信息放到开头或结尾表现会更好。

有兴趣的可以瞅瞅:

四、RAG 切分入库

之前已经把协议、提示词、上下文的组成搞定。

但在,我规定的上下文组成的第五层中,是需要RAG召回的,这也就意味着,需要先切分入库

切分入库的质量越高,召回的质量就越高。

最简单的切分方式就是固定大小 切分,但是这样很死板,上下文语义会很不完整。

所以就有了语义切分 ,按照标点符号进行切分。

但有时,先表格、函数代码这些特殊情况,是无法进行语义切分 的,所以就需要对这些专项内容切分

其实还有成本更高的父子切分,就是你检索到子片的时候,会把与他相连的上下文一起带回。

而我的本项目,需求不高,所以做的是语义切分

  • 首先按段落切分
  • 如果越界了在按照符号切分。
    并且会保留相邻chunk的150个字符,用来维持语义。

最后在入qdrant与mysql的时。

我是以mysql作为真相数据源存document与元数据。

qdrant 里面存的是向量权限范围 用于筛选、和对应mysql的数据索引,用于去数据库中检索。

我在我的代码中也考虑过专项内容切分,考虑到了表格、代码,但是暂时还没有引入语法解析工具这种更高精度的切分。

五、混合召回策略

在上下文压缩的时候,我已经把需要召回的内容,表述的很明白。

但是那个时候为了表述清楚 ,内部的组成结构,所以我说的还是比较直白死板

通常我会先判断一下两个数组:
最近决策 :只有 key_points 不会空才加载。(这个是对话中的要点)
待完成内容 :只有 open_loops 不为空才加载,他的存在可以让上下文的连续性更丝滑。
对话压缩后的摘要 :长对话必备!
Fact格式化内容 :这个达到阈值才能被加载,比如用户性格爱好,最近有啥目标 等用户画像
RAG检索 :若检索出来了,需执行度高于阈值,且top前5。

最后就是一些tools信息,与用户最近一次的问题了。

六、我想说的话

本次整体是我自己手写搭建的。

目的就是为了深入理解记忆机制的底层原理

但是如果要在生产级别项目中,为了追求快速开发。

可以复用像 mem0,这种记忆框架。

相关推荐
louisliao_19811 小时前
Research Agent 示例(L3)
agent
optimistic_chen2 小时前
【AI Agent 全栈开发】提示词技巧(prompt)
java·人工智能·ai·prompt·agent
世rui睿3 小时前
RAG 知识库质检:三级 Gate 如何拦截垃圾知识
人工智能·agent
Trouvaille ~3 小时前
零基础入门 LangChain 与 LangGraph(九):LangGraph 收官——运行时上下文、流式输出、子图、与项目结构
数据库·langchain·agent·streaming·langgraph·ai应用开发·运行上下文
火车叼位3 小时前
planning-with-files 完全指南:从入门到高阶,规范你的 AI 编程智能体
agent·vibecoding
新知图书3 小时前
LangGraph 基础图创建思路
人工智能·agent·智能体·langgraph·langchian
山顶夕景4 小时前
【Agent】Openclaw架构(Gateway|subagent|工具过滤|Sandbox)
大模型·llm·agent·智能体·openclaw
深海鱼在掘金14 小时前
深入浅出 LangChain — 第一章:AI Agent 开发导论
typescript·langchain·agent
深海鱼在掘金14 小时前
深入浅出 LangChain — 导读
typescript·langchain·agent