
在 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 系统中一次用户请求很少只做一次模型调用。更常见的流程是先加载当前会话和历史状态再判断需不需要外部知识然后调用工具或检索服务最后生成回复并更新状态。一个典型的数据流可以拆成以下步骤Agent runtime 从请求中拿到user_id和session_id。Memory 管理器读取历史消息、用户画像和当前任务状态。根据历史和当前输入对用户问题做查询改写。如果判断需要外部知识调用 RAG 检索服务获取文档片段。如果涉及工具调用执行工具并把结果放入上下文。把历史、上下文、检索片段、工具结果一起拼成 Prompt。模型生成回复或生成下一步动作。对话内容、关键事实、任务进度写回 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_k5) prompt self._build_prompt( queryuser_input, historyhistory, factsfacts, documentsdocs, ) 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什么场景先上 Memory3.1 先上 RAG 的场景如果用户问题彼此独立答案主要来自文档并且不需要记住上一轮说了什么那么优先考虑 RAG。典型场景包括企业制度问答、产品说明书检索、法务条款查询、政策文件问答。这类场景的特点是用户问完一个问题得到答案后大概率会问另一个独立问题即使他连续问五个问题五个问题之间也没有强依赖。此时用 Memory 只会增加复杂度。只要做好文档切块、向量召回和引用溯源一个无状态的 RAG 问答服务就能满足需求。RAG 还适合需要引用来源的场景。用户在客服场景里会追问“这个依据在哪里”如果检索接口能返回doc_id、chunk_id、source等字段Agent 就可以在回答里带出出处降低模型编造概率。3.2 先上 Memory 的场景如果下一步动作依赖上一步结果那么 Memory 必须优先。典型场景是用户说“在我刚才说的预算内推荐一款”“继续处理上一个报销单”“把刚才生成的页面改成深色主题”。这些问题如果去掉历史上下文模型根本无法理解。Agent 的多步工具调用也强依赖 Memory。比如一个 Agent 需要先查订单编号再查物流状态最后生成汇总表如果它不保存“订单编号”这个中间值每一步都要让用户重新输入。此时即使外部知识很完备Agent 也会因为记不住状态而无法完成任务。3.3 两者都要上时先画数据流再写代码真实项目里RAG 和 Memory 经常需要一起用。比如客服 AgentMemory 负责记住用户是谁、之前沟通到哪一步、有没有确认过订单号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 不能只存字符串还要存字段名、来源、时间戳和状态。{