☰
RAG与Memory在AI Agent中的核心区别与协作机制解析
2026/10/26 22:43:49 网站建设 项目流程

在 AI Agent 开发中,RAG 和 Memory 是出现频率最高的两个词,也是很多方案评审会上最容易被混在一起讨论的两个概念。很多团队在启动第一个 Agent 项目时会问:到底应该用 RAG,还是应该给 Agent 加 Memory?这个二选一本身就会误导设计。RAG 负责把外部知识送到模型面前,Memory 负责让 Agent 在多次交互中保持上下文和状态。两者服务的不是同一层问题,不能互相替代,却可以在同一条 Agent 工作流里协作。下面会把两者的职责、配合方式、选型判断、落地细节、验证方法和排错路径展开讲清楚。

1. 先厘清:RAG 解决“模型不知道”,Memory 解决“状态记不住”

1.1 RAG 的本质是把“外部知识”接到模型外面

RAG 的全称是 Retrieval-Augmented Generation,中文通常叫检索增强生成。它在模型生成回答之前,先从外部知识库召回与用户问题相关的内容,把召回结果作为上下文片段和用户问题一起交给模型。模型不需要在参数中记住这些知识,也不需要为每次制度更新重新训练,只要知识库里的文档更新,检索结果就会变化。

一个典型的 RAG 链路包括文档加载、文档清洗、切块、向量化、写入向量库、用户提问时查询改写、向量召回、重排、拼接 Prompt。这个链路里最容易被低估的是文档切块和重排。并不是任意切一块文本再算向量相似度就能得到好答案,切块粒度、重叠长度、元数据完整度都会直接影响最终回答准确率。

理解 RAG 的关键点在于:它的数据来源是外部资料,读取时机在用户问题到来之后,核心目标是让模型看到它原本不知道的内容。如果用户问的问题在模型参数里已经存在,RAG 的价值会下降;如果问题依赖的是企业私有文档、最新政策或实时数据,RAG 几乎是必选项。

1.2 Memory 的本质是让 Agent 管理“状态和上下文”

Agent Memory 指的是 Agent 对交互过程的记录和状态管理能力。它至少包含三层:当前会话的短期记忆,比如最近几轮对话;跨会话的长期记忆,比如用户偏好、历史结论、任务上下文;以及工作记忆,比如当前执行到第几步、哪个工具已经返回结果、临时变量是什么。

需要注意,这个 Memory 是 Agent 的逻辑概念,不是 Java 进程里的内存。如果 Agent 进程报出OutOfMemoryError,通常不是“记忆模块太多”导致,而是程序设计上没有限制上下文体积或没有释放对象。把 Agent Memory 和服务进程内存混为一谈,是排查问题时最常见的误区之一。

Memory 的写入动作发生在 Agent 执行过程中,读取动作发生在下一步决策之前。它解决的是“模型看不到刚才发生了什么”的问题。没有 Memory 的 Agent 即使有很强的工具调用能力,也会在第三步忘掉第一步的结果。多步任务、工具调用、用户偏好维护,都依赖 Memory。

1.3 两者的差异不能靠“是不是向量检索”来区分

RAG 和 Agent Memory 都可能会用向量库,这是它们容易被混淆的另一个原因。但真正区分它们的是数据来源和读写时机:RAG 的语料来自文档知识库,通常在后台批量索引;Memory 的语料来自用户与 Agent 的实时交互,在一轮对话结束后增量写入。

维度RAGAgent Memory
核心问题模型不知道的知识Agent 记不住的上下文与状态
数据来源文档、网页、数据库、知识库对话历史、工具结果、任务中间状态
写入时机文档入库或更新时离线写入每轮对话或每个 Agent 步骤后在线写入
读取时机用户提问后按相关性召回每轮开始加载,或决策节点按需读取
典型存储向量库、倒排索引、混合检索KV 存储、数据库、向量库、内存对象
核心风险检索不准、引用无依据上下文膨胀、敏感信息长期驻留

RAG 更像 Agent 的“外部图书馆”,Memory 更像 Agent 的“工作台和笔记”。查资料和记状态是两件不同的事。

2. 把 RAG 和 Memory 放进同一条 Agent 工作流

2.1 一次代答的完整数据流

在实际 Agent 系统中,一次用户请求很少只做一次模型调用。更常见的流程是:先加载当前会话和历史状态,再判断需不需要外部知识,然后调用工具或检索服务,最后生成回复并更新状态。

一个典型的数据流可以拆成以下步骤:

  1. Agent runtime 从请求中拿到user_id和session_id。
  2. Memory 管理器读取历史消息、用户画像和当前任务状态。
  3. 根据历史和当前输入,对用户问题做查询改写。
  4. 如果判断需要外部知识,调用 RAG 检索服务获取文档片段。
  5. 如果涉及工具调用,执行工具并把结果放入上下文。
  6. 把历史、上下文、检索片段、工具结果一起拼成 Prompt。
  7. 模型生成回复,或生成下一步动作。
  8. 对话内容、关键事实、任务进度写回 Memory。

在这个流程里,RAG 和 Memory 的位置不同:Memory 在回合开始前读取,RAG 在需要知识时才读取,工具结果又可能写回 Memory。这样不会出现“把所有知识都塞进记忆”或者“把所有历史都塞进知识库”的设计混乱。

2.2 为什么不能只靠“把所有历史都塞进 Prompt”

有人会问:既然模型上下文窗口已经很大,为什么还要单独设计 Memory?直接把历史消息和检索结果全部拼进 Prompt 不行吗?

可行,但不适合生产环境。上下文窗口再大,也有 token 成本上限。历史越长,无关信息越多,模型越容易忽略关键内容。企业场景下如果每个请求都带上全部对话历史加全部检索片段,接口延迟和费用都会快速上升。更严重的是,Agent 在执行多步任务时,真正需要的往往不是“完整聊天记录”,而是“这一步的状态”。

Memory 的职责是对上下文做压缩、抽取、筛选和持久化,而不是无脑拼接。比如上一轮已经确认了“预算 2 万”,下一轮就不必再把“预算 2 万”相关的所有原始聊天记录都塞进去,而是把它转成一条结构化事实字段。

2.3 最小代码结构:用 Python 演示两者如何协作

下面是一段用于说明数据流的伪工程代码,不涉及具体框架。它的重点不是语法,而是展示 Memory 和 RAG 在同一个 Agent 方法里的协作位置。

class Agent: def __init__(self, retriever, memory, llm): self.retriever = retriever self.memory = memory self.llm = llm def handle(self, user_id, session_id, user_input): history = self.memory.load_session(session_id) facts = self.memory.load_facts(user_id) rewritten = self.memory.rewrite_query(user_input, history) docs = [] if self.memory.need_external_knowledge(rewritten): docs = self.retriever.search(rewritten, top_k=5) prompt = self._build_prompt( query=user_input, history=history, facts=facts, documents=docs, ) answer = self.llm.chat(prompt) self.memory.append(session_id, user_input, answer) self.memory.update_facts(user_id, answer) return answer

关键点有三个:

  • rewrite_query会把用户问题结合历史上下文改写,避免直接拿“它”或“这个方案”去检索。
  • need_external_knowledge决定了是否需要调用 RAG,不是每个请求都必须走知识库检索。
  • append和update_facts必须在模型调用之后执行,确保写入的是这一轮的结果,而不是模型推理前的旧状态。

这就是 RAG 和 Memory 的协作位置:Memory 先提供上下文,RAG 再叠加外部资料,最后结果又写回 Memory。

3. 选型判断:什么场景先上 RAG,什么场景先上 Memory

3.1 先上 RAG 的场景

如果用户问题彼此独立,答案主要来自文档,并且不需要记住上一轮说了什么,那么优先考虑 RAG。典型场景包括企业制度问答、产品说明书检索、法务条款查询、政策文件问答。

这类场景的特点是:用户问完一个问题,得到答案后大概率会问另一个独立问题;即使他连续问五个问题,五个问题之间也没有强依赖。此时用 Memory 只会增加复杂度。只要做好文档切块、向量召回和引用溯源,一个无状态的 RAG 问答服务就能满足需求。

RAG 还适合需要引用来源的场景。用户在客服场景里会追问“这个依据在哪里”,如果检索接口能返回doc_id、chunk_id、source等字段,Agent 就可以在回答里带出出处,降低模型编造概率。

3.2 先上 Memory 的场景

如果下一步动作依赖上一步结果,那么 Memory 必须优先。典型场景是:用户说“在我刚才说的预算内推荐一款”“继续处理上一个报销单”“把刚才生成的页面改成深色主题”。这些问题如果去掉历史上下文,模型根本无法理解。

Agent 的多步工具调用也强依赖 Memory。比如一个 Agent 需要先查订单编号,再查物流状态,最后生成汇总表;如果它不保存“订单编号”这个中间值,每一步都要让用户重新输入。此时即使外部知识很完备,Agent 也会因为记不住状态而无法完成任务。

3.3 两者都要上时,先画数据流再写代码

真实项目里,RAG 和 Memory 经常需要一起用。比如客服 Agent:Memory 负责记住用户是谁、之前沟通到哪一步、有没有确认过订单号;RAG 负责检索赔偿政策、售后流程、产品说明。二者缺一不可。

建议不要一上来就选 Agent 框架,而是先列数据来源:哪些信息来自用户输入,哪些来自历史状态,哪些来自外部文档,哪些来自工具返回结果。然后决定这些信息分别进入哪个模块。

请求类型判断依据推荐方案
单个独立知识问答答案完全来自文档RAG
多轮上下文问答需要上一轮信息才能理解Memory
按制度核对当前单据既有规则也有当前对象RAG + Memory
继续上次任务并查最新数据有任务状态也有实时数据Memory + RAG

在 Agent 项目里,Memory 通常要先于 RAG 落地。因为 Agent 的核心是执行任务,任务必须有状态。如果没有状态,只能算问答机器人,不能算 Agent。

4. Agent Memory 落地:先设计记忆模型,再谈长期记忆

4.1 短期会话记忆:用有限窗口管理上下文

短期记忆通常指当前会话内的上下文。实现时最简单的方式是维护一个消息列表,但这并不等于“把列表原样塞进 Prompt”。应该设置窗口上限,比如保留最近 20 轮,超出部分用摘要压缩。

一个可参考的策略:

  • 保留最近 5 轮完整原始消息。
  • 更早的消息滚动生成会话摘要。
  • 每一轮执行时,把摘要加最近消息一起送入 Prompt。
  • 摘要也要限制 token 长度,防止无限膨胀。

这样做的好处是既保留近期细节,又不会让模型失去长距离上下文。它的成本来自摘要更新,每次摘要更新都需要一次模型调用,因此不需要每一轮都重新摘要,可以按轮数或 token 阈值触发。

4.2 长期记忆:事实表、事件日志和向量记忆

长期记忆不是简单把历史消息永久保存,而是应该分类型管理。比较实用的分层方式如下。

记忆类型内容示例存储方式更新策略
工作记忆当前任务步骤、临时变量会话内对象每轮覆盖
情景记忆用户上次提过“预算只剩两万”向量库或数据库追加并去重
语义记忆用户偏好、公司部门结构化事实表字段覆盖或版本化
程序记忆常用工具调用流程配置、脚本、Agent 技能库版本管理

一条长期记忆记录可以设计成下面的 JSON 结构。它说明 Memory 不能只存字符串,还要存字段名、来源、时间戳和状态。

{ "

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询