免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

RAG还是Memory?先分清知识检索与状态记忆的关键差异

RAG还是Memory?先分清知识检索与状态记忆的关键差异 最近几次技术交流里我被问得最多的一个问题就是Agent 到底该用 RAG 还是 Memory是不是有了 RAG 就不需要 Memory 了还是反过来先做 Memory知识库可以放一放这个问题之所以让人纠结是因为很多团队的 Agent 已经跑起来了但效果总是差一口气。问产品手册里的内容回答得还算靠谱可只要对话稍微一长或者用户换了一种说法Agent 就像失忆一样——要么答非所问要么把上一轮刚确认过的信息推翻。这时候有人去调 RAG 的切块策略有人去加 Memory 模块还有人直接上 Agentic RAG。折腾一圈效果却不一定变好。我的判断是RAG 和 Memory 根本不是同一层的东西它们解决的问题也不一样。把两者放在一起二选一本身就可能说明我们还没定位到真正的病灶。真正关键的是先搞清楚你的 Agent 到底在哪一个环节断裂了。1. 先别急着选这个问题的前提可能就错了1.1 为什么 RAG 和 Memory 总被放在一起比较表面上看RAG 和 Memory 确实有相似之处它们都会给大模型“多塞一些信息”都能缓解幻觉都跟上下文有关。于是很多人在描述需求时会把它们混着说——“Agent 记不住东西那就上 RAG 吧”“RAG 效果不好是不是该换 Memory”。这里有一个很常见的思维误区把“上下文”当成一个统一的筐。但实际上模型生成时需要的上下文至少来自三条完全不同的路径外部知识产品文档、规章制度、行业资料这些内容模型在训练时没见过或者见过但已经过时。需要从外部文件里找回来。当前会话状态用户上一轮说了什么、你已经答应过什么、任务执行到哪一步这些信息只存在于这次对话内部。跨会话偏好与经历用户长期关注什么、上次帮你处理过什么、你总结过哪些结论。这些信息需要跨 session 保留。RAG 解决的是第一条路径。Memory 解决的是第二条和第三条路径。把这三条路径统一成一个“要不要记忆”的问题从一开始就问偏了。1.2 一个反直觉的判断它们不是同一层的东西我倾向于把 RAG 理解成一种推理时的外部检索机制把 Memory 理解成一种状态持久化与调取机制。两者最本质的区别是RAG 是“读”外部语料每次请求都是一次全新的检索它不做状态累积。Memory 是“写”和“读”Agent 自身的历史带有明确的时序和状态含义。用生活里的例子类比RAG 更像是你临时去图书馆查资料不管你来过多少次每一次查书都是按当下的问题重新找。图书馆不会记住你昨天借过什么也不会因为你昨天查过某个主题今天就自动把相关章节摆到你桌上。Memory 则更像你自己的笔记本它会记录这个任务做到哪一步、对方在意什么、上次讨论得出过什么结论。下一次打开本子你能接着上次的进度往下走。所以 RAG 和 Memory 并不互斥。真正的问题不是“该用哪个”而是“你的 Agent 缺的是哪一层”。对比维度RAGMemory核心目标从外部知识库取回相关证据保留并恢复 Agent 自身的历史状态数据来源文档、网页、数据库、非结构化文件会话历史、任务状态、用户画像、历史结论发生时机每次推理时按查询触发检索会话中持续写入在需要时调取典型操作向量检索、重排、引用溯源写入、更新、过期、读取、摘要压缩失败表现检索不到相关片段或引错了文档回答与之前矛盾、上下文遗漏或记忆污染典型问题不知道“这个知识”不记得“刚才的事”或“这个人是谁”2. RAG 的本质把外部知识变成可检索上下文2.1 RAG 真正解决的是“知识缺口”不是“记忆问题”RAG 的全称是检索增强生成。它的核心思路是在模型生成之前先从外部知识源里检索出与问题相关的片段把这些片段作为参考内容塞进 prompt再让模型基于这些内容作答。它解决的是大模型最典型的一个短板模型内部的知识是训练时固化的专业文档、企业内部资料、最新政策它不可能都知道。你问一个通用大模型最新的内部流程它大概率会一本正经地编一个答案因为它的参数里根本没有这个信息。RAG 的作用不是让模型“记住”而是让模型在回答的那一刻“看得到”正确资料。这也是为什么它特别适合企业知识库、产品问答、合规问答这类场景答案必须来自指定的文档而不是模型自由发挥。2.2 一个最小 RAG 系统里真正决定效果的四个环节很多人以为 RAG 就是“把文档丢进向量数据库然后查一下”实际上一个可直接使用的 RAG 系统至少要经过四个环节文档加载与解析切块Chunking向量化与存储检索、重排与引用生成这几个环节里最容易让新手栽跟头的是切块。切块策略直接决定了后续检索的精度。如果你的文档是规范的企业手册、制度文件按章节、标题层级来切通常比固定 500 字一刀切要靠谱。因为固定长度切块很容易把“问题”和“答案”切成两段导致检索时只命中一半内容。更合理的做法是先按文档结构切分出语义单元比如标题、段落、列表再对过长的单元做二次拆分。拆分时可以设置一个 overlap让相邻片段重叠一部分避免关键信息卡在切缝里。向量化和存储阶段要特别注意embedding 模型和业务语料的匹配问题。通用的 embedding 模型对日常文本效果不错但遇到大量专业术语、缩写、中文企业表达时检索质量可能明显下降。常见的实践是先准备一批真实问题跑一轮检索看看 top-k 结果是否相关再决定要不要换领域适配的 embedding 模型。从工程角度看一个最小可运行的 RAG 流程可以这样理解# 常见流程示意具体实现需结合你的框架和向量库 docs load_and_split_documents(your_files) # 加载 切块 vectorstore build_vectorstore(docs, embedding_model) # 向量化存储 retriever vectorstore.as_retriever(search_kwargs{k: 4}) # 检索配置 context retriever.invoke(question) answer llm.invoke(assemble_prompt(question, context))这里的关键不是代码行数而是每一步都值得单独验证解析出来的文本是不是干净的切出来的块是不是有独立含义检索回来的片段是不是真的能回答问题2.3 RAG 的边界它不负责记住你上一轮说了什么很多人对 RAG 失望是因为拿它去解决了一个它根本不该解决的问题。RAG 的每次检索都是独立的它不会因为你之前问过“报销流程”这一轮就问“那发票呢”时自动把上一轮里的“报销流程”作为检索上下文。它只会按当前这一句话去查。如果 Agent 没有把对话历史拼进检索查询里RAG 就会显得“断片”。这就是为什么在多轮对话场景里RAG 通常需要配合会话状态的维护。否则你加再多的知识库Agent 依然会在连续对话中失去方向。注意如果对话一长就答非所问先别急着调切块参数。你遇到的很可能不是检索问题而是上下文和记忆问题。3. Memory 的本质Agent 的状态、经历与自我一致性3.1 对话记忆、工作记忆、长期记忆别混为一谈RAG 容易被笼统理解Memory 更容易。因为在 Agent 开发里“Memory”这个单词被塞进了太多含义。我建议至少把 Memory 拆成三个层级工作记忆Working Memory当前任务执行过程中的临时状态比如正在填写的表单、已经收集到的参数、任务执行到第几步。这部分通常只需要在本次任务内有效。会话记忆Conversation Memory当前对话的历史记录包括用户说过的话、Agent 回答过什么、已经确认的约束。它负责维持多轮对话的一致性。长期记忆Long-term Memory跨会话保留的信息比如用户的偏好、历史项目结论、Agent 在多次任务中积累的经验。它让 Agent 在下次出现时“还认识你”。很多团队的问题在于所有历史都堆在一起没有分层。结果就是短期对话里塞进了几个月前的旧结论把当前任务带偏或者更常见的是长期记忆里存了大量临时状态越用越乱。3.2 实现 Memory 不是“把历史拼接起来”那么简单最简单粗暴的 Memory 实现是把所有对话历史全部拼进 prompt。这在测试阶段可行但对话一长就会出问题token 成本爆炸上下文窗口是有限的历史越长留给推理和检索的空间越小。关键信息被稀释模型面对几千行历史时很难准确识别哪一条是当前最相关的约束。旧信息干扰新决策用户上一轮说的是 A这一轮改成了 B如果 history 里 A 和 B 都存在模型可能会犹豫甚至答错。更常见的工程方案是分层设计保留最近几轮完整对话作为短期记忆把更早的历史做一轮摘要压缩再抽取出需要长期保存的用户偏好或任务结论单独存进记忆库。需要时通过向量检索把最相关的历史记忆取回来而不是全量塞进去。这里涉及到一个搜索引擎里也会遇到的热词memory channel。通俗说就是把不同类型的记忆分开管理比如一个 channel 存对话摘要一个 channel 存用户画像一个 channel 存任务状态。Agent 在决策时可以根据当前需求只读取相关 channel而不是什么都看。3.3 Memory 一旦做错比没有 Memory 更危险这一点经常被低估。RAG 写错了最多是检索回来的片段不准Memory 写错了是会“污染后续所有交互”的。举个例子Agent 在一次对话里误解了用户的意思把“用户希望每周自动生成报表”写进了长期记忆。接下来每一次对话Agent 都会带着这条错误信息行动。用户要反复纠正甚至直接弃用。更隐蔽的问题是记忆过期。用户三个月前的偏好可能现在已经不适用了。如果长期记忆没有时效机制Agent 就会拿旧结论回答新问题表现甚至不如一个没有记忆的 Agent。所以Memory 的设计重点不只是“怎么存”还包括写入校验什么信息值得写入长期记忆什么信息只是临时状态。时效与淘汰每条长期记忆是否带时间戳多久未被使用后应该被弱化或删除。用户控制用户能不能查看、修改、删除 Agent 存下的关于自己的信息。冲突处理新信息与旧记忆不一致时以谁为准。如果你发现 Agent 的回答“越用越怪”很多情况下不是模型变笨了而是 Memory 层写入了错误的记忆并且没有淘汰机制。4. 不是二选一而是分层配合Agentic RAG 的正确打开方式4.1 Agent 决策时如何判断该检索还是该回忆当 Agent 同时具备 RAG 和 Memory 之后真正的问题变成了每一步它应该去查资料还是应该回忆历史还是直接回答这就是 Agentic RAG 要解决的核心问题。它和传统 RAG 的区别在于传统 RAG 是“每次必查”Agentic RAG 是“按需查”。Agent 会根据当前问题、已有上下文、记忆中的信息自主决定是否检索、检索什么、以及是否要改写检索查询。一个比较实用的判断逻辑是这样的如果问题涉及外部事实、专业文档、最新资讯 → 走 RAG 检索。如果问题依赖之前的对话内容、用户偏好、任务状态 → 走 Memory 调取。如果问题既需要文档知识又需要结合历史上下文 → 先调取记忆再用记忆补充后的意图去做检索。换句话说Memory 负责回答“我们刚才聊到哪里”RAG 负责回答“这个问题的事实依据是什么”。两者服务的对象不同但最终都汇入同一个 prompt。4.2 一个可直接参考的混合流程在实际项目里我比较推荐的流程是这样的用户输入进入 Agent。Agent 先读取工作记忆和当前会话摘要明确“现在在做什么、已经知道什么”。判断当前问题是否需要新知识。如果需要就带着会话上下文改写检索查询执行 RAG。检索结果回来后结合记忆中的历史约束一起组装 prompt交给模型生成。生成结束后判断本轮的对话内容里有没有值得写入长期记忆的信息。如果有走写入校验流程而不是无条件全存。这个流程看起来简单但它和“一上来就堆功能”的区别很大。它实际上把决策权交给了 Agent同时给了 Agent 一套明确的判断标准。在技术选型上现在很多框架都已经内置了相关能力比如 LangChain 的 memory 模块、Spring AI 2.0 结合 Qdrant 做向量存储、Dify 这类低代码平台里的知识库和会话变量。还有一个值得关注的方向是 MCP它把外部工具和数据访问标准化了Agent 接入 RAG 和 Memory 的方式会更统一。选哪个框架不重要重要的是你的 Agent 是否能区分“该查”和“该记”。4.3 从单次用到工程化差的是日志、评估和治理很多 RAG 项目在演示时跑得通一上线就崩不是因为算法不行而是因为缺少工程化支撑。RAG 和 Memory 都属于“效果需要持续观察”的模块。你不能只跑通一次流程就宣布完成。至少需要补三样东西链路日志记录每次请求里模型到底检索到了哪些片段、调取到了哪些记忆、最后用了哪部分。这样出了问题才能回溯而不是猜。评估集准备一批真实问题包含“只需要知识库”“需要结合历史”“需要跨会话记忆”三种类型定期回归。评估的是最终回答质量而不是单个环节的指标。治理规则RAG 需要版本化的知识库和引用溯源Memory 需要写入权限、时效策略、删除机制。RAG 的引用溯源尤其重要。企业场景里回答必须能指出“这句话来自哪一篇文档、哪一段”否则一旦答错责任没法追溯。这也是检索增强体系里最容易被忽略、却最能体现专业度的部分。5. 实操判断框架五个问题帮你做决策5.1 先回答这五个问题如果你现在正在纠结“RAG 和 Memory 该用哪个”我建议你先别急着写代码先回答下面五个问题当前最明显的失败表现是什么是回答里出现编造的知识还是多轮对话里前后矛盾还是跨会话完全不认识用户这个失败发生在哪一层是“没有资料”是“忘了当前上下文”还是“没有长期状态”如果只加 RAG问题能解决多少能解决知识类错误但解决不了“记不住刚才”的问题。如果只加 Memory问题能解决多少能解决对话一致性但解决不了“不知道企业内部文档”的问题。你是否有办法验证加了之后真的变好了如果没有评估集和日志你只是在猜。回答完这五个问题大部分场景的结论会非常清楚。5.2 不同组合下的典型架构实际场景推荐组合原因企业内部文档问答单轮为主只需要 RAG用户问一句查一句不依赖历史状态多轮客服/任务型 Agent会话记忆 RAG既要知道答什么也要记得聊到哪个性化助手需要跨会话识别用户长期记忆 会话记忆 RAG需要记住身份、偏好和历史结论对话很短但知识覆盖很广RAG 足够的引用溯源核心风险是知识错误不是上下文丢失实验阶段效果还没评估先别加 Memory先加日志Memory 写错了会污染后续先确认链路可观测5.3 一些容易掉进去的坑切块策略一刀切。固定字数切块最省事但如果你的文档有明确的层级结构不要浪费它。按标题、表格、列表、代码块来切检索精度通常比纯长度切块高出不少。切完之后一定要抽样检查把每个片段单独拿出来看它是否还像一个“可理解的完整单元”。检索数量拍脑袋。top-k 不是越大越好。k 太小可能漏掉关键信息k 太大又会在 prompt 里塞进大量无关内容反而干扰模型。我一般建议从 k3 到 k5 开始结合实际评估集测试而不是一上来就拉满。只要知识库不要引用。知识库回答如果无法溯源几乎等于没有可信度。上线前一定要确认回答里能带上文档来源并且这个来源真的能对应到原文。Memory 写入没有门槛。最怕的就是“每个 session 结束时把所有东西都存进长期记忆”。长期记忆应该只保存有复用价值的结论和偏好而不是流水账。忽略隐私和权限。如果 Agent 服务多个用户Memory 必须按用户隔离。不同用户之间的历史信息串了这是安全事故不是效果问题。无评估就上线。我见过太多团队把 RAG 和 Memory 做完就宣布完成结果第二天就被用户问出明显错误。没有评估集你甚至说不清楚是检索的问题还是记忆的问题。6. 排查链路效果不好时先查哪一层6.1 现象 → 输入 → 环境 → 参数 → 工具边界无论是 RAG 还是 Memory出了问题都要按链路排查不要一上来就怀疑模型不行。我常用的排查顺序是看现象是“答非所问”是“前后矛盾”是“完全没检索到”还是“检索到了但答案不对”现象决定了方向。看输入文档加载后是否乱码切块后内容是否完整当前查询有没有把对话历史带进去如果查询本身缺了上下文后面的检索再准也没用。看环境依赖版本是否一致embedding 模型和向量库版本是否兼容本地部署的模型和后端之间有没有调用超时看参数切块大小、overlap、top-k、相似度阈值、摘要触发长度、记忆写入条件这些参数是否和你的数据量匹配。看工具边界当前框架或模型对上下文窗口的限制是多少向量库是否支持你要的元数据过滤框架是否限制记忆 channel 的数量6.2 RAG 效果差最容易出问题的环节现象优先排查项检索结果看起来相关但回答还是错看引用溯源答案是否真的基于检索片段切块是否把关键信息拆散了检索结果完全不相关看 embedding 模型是否适配业务术语看查询是否缺上下文看是否需要重排触发检索时很慢看向量库索引方式、文档总量、是否需要元数据过滤缩小范围回答“看起来像编的”看 prompt 是否明确要求“只能基于给定资料回答”看是否启用了引用约束6.3 Memory 异常更隐蔽也更难查Memory 的问题往往不是“没生效”而是“悄悄生效但生效错了”。如果 Agent 在对话中突然说出和当前用户无关的信息优先查长期记忆是否按用户隔离。如果 Agent 总是用旧结论回答新问题查记忆写入是否带时间戳是否缺少过期和弱化机制。如果历史一长就答错查是否全量拼接历史有没有做摘要压缩和关键信息抽取。如果 Agent 的回答越来越“奇怪”第一件事是把日志里命中的记忆记录打开看看模型到底读了什么。排查 Memory 问题时最好先关掉长期记忆只保留会话记忆跑一轮。如果问题消失说明是长期记忆写入或调取有误如果问题还在说明不是记忆层的问题。写在最后回到最开始的题目RAG 和 MemoryAgent 到底该用哪个我的答案很简单先选层再选模块。如果缺的是外部知识用 RAG如果缺的是状态连续性用 Memory如果两者都缺就分层配合。不要在还没有定位到问题层之前就急着堆功能。RAG 是让 Agent 在面对未知问题时“查得到”Memory 是让 Agent 在持续交互中“记得住、接得上”。它们一个管外部事实一个管内部状态本来就是搭档而不是对手。如果你现在手头正好有一个效果不达预期的 Agent我建议你先别改代码先花半天时间梳理上一轮它为什么答错了是因为没有资料还是因为忘了上下文把这个问题想清楚比多换一个框架管用得多。下一个阶段你要做的可能不是“二选一”而是把 RAG 的检索质量、Memory 的写入门槛、以及整个链路的日志和评估一起补齐。到那时候你会发现所谓“该用哪个”的问题其实早就消失了。
返回列表