
1. RAG 和 MemoryAgent 到底该用哪个最近在技术社区里RAG检索增强生成、Memory记忆机制、Agent智能体这三个词频繁出现在一起。很多开发者一开始接触时都会产生一个很自然的困惑这三者是不是同一个东西如果我要做一个 AI 应用到底该选哪个先说个实际场景。我早期做知识库问答时第一个方案是直接把几十篇资料全部拼进 Prompt 里送给大模型结果很快发现两个问题一是上下文窗口被塞满经常触发长度限制二是资料一多模型容易把细节记混回答正确率明显下降。当时为了图省事我甚至试过把资料“喂”给模型做微调但数据更新一次就要重新训练一次维护成本太高。后来换成了 RAG才解决“知识随时更新”和“答案可溯源”这两个核心问题。但项目继续往后做新的麻烦又来了用户会在一次会话里连续问多个问题系统需要记住前面聊过什么甚至有一些操作类需求比如“查一下订单、算一下总金额、再生成一份摘要”光靠“检索 回答”根本做不了。这时候我才意识到RAG 只是拼图中的一块真正落地还需要 Memory 和 Agent 一起来配合。本文会把这三种技术的边界、各自解决的问题、组合方式讲清楚并给出一套可以直接运行的最小示例。为了照顾不同阶段的读者我会先解释概念再拆原理最后给完整代码和排查思路。无论你是刚开始接触大模型应用开发还是已经在做项目选型这篇文章都可以当作一份参考笔记。2. 环境准备与版本说明在动手写代码之前先把实验环境说清楚。本文以常见的 Python 技术栈为例核心是 LangChain 生态 FastAPI 向量数据库。版本不需要完全一致关键是理解思路和配置方式。我本地的实验环境如下依赖项说明操作系统macOS / Linux / Windows均支持Python3.10 以上LLM APIOpenAI 兼容接口或本地 Ollama / vLLM 部署的模型向量数据库Chroma本地运行适合示例或 Qdrant框架LangChain 0.3 系列如果采用本地模型方案可以用 llama.cpp Qwen2 7B 这类开源模型来跑 RAG 场景整体链路是文档加载 → 解析 → 切块 → 向量化 → 存入向量库 → 召回 → 生成。这套流程后面会详细拆解。先创建一个项目目录规划好文件结构mkdir rag-memory-agent-demo cd rag-memory-agent-demo项目结构建议如下rag-memory-agent-demo/ ├── requirements.txt ├── config.py ├── rag_engine.py ├── memory_module.py ├── agent_runner.py ├── app.py └── data/ └── demo_docs/ └── product_manual.md安装依赖pip install langchain langchain-openai langchain-chroma chromadb fastapi uvicorn如果你的环境网络受限也可以把向量库换成本地文件形式。下面开始分模块讲解。3. RAG、Memory、Agent 核心原理拆解3.1 RAG让大模型学会“先查资料再回答”RAG 的完整名称是 Retrieval-Augmented Generation中文一般叫检索增强生成。它的核心思路并不复杂大模型本身有“记忆”但这份记忆停留在训练完成的那一刻而且对于私域数据公司内部文档、产品手册、个人知识库完全一无所知。RAG 的做法是在模型回答问题之前先从外部知识库中检索出与问题最相关的内容再把这些内容作为参考上下文和问题一起交给模型。一个完整的 RAG 流程通常包含下面几个步骤文档加载从 PDF、Word、Markdown、HTML、数据库、API 等来源读取原始数据。文档解析清洗格式去除无关信息把正文提取出来。文本切块把长文档切成多个小块chunk块与块之间可以有少量重叠。向量化用 Embedding 模型把每个 chunk 转成向量。存储把向量和原始文本一起存入向量数据库。召回用户提问时先把问题转成向量再在向量库里做相似度检索取 Top-K。重排可选对召回结果做精排过滤掉不相关的内容。生成把问题和召回内容拼成 Prompt交给大模型生成回答。为什么需要切块因为大模型上下文窗口有限而且“块”太大会带来更多噪音太小又会丢失上下文。常见的做法是设置chunk_size500、chunk_overlap50也就是每个块 500 个字符相邻块之间重叠 50 个字符。切块策略本身是 RAG 项目里非常关键的一个调优点后面我们会单独讨论。3.2 Memory让对话和任务拥有“短期记忆”和“长期记忆”Memory 解决的是“模型记不住上下文”的问题。大模型接口本身是无状态的每次调用都是独立的。用户上一句说“我叫张三”这一句问“我叫什么名字”如果应用层不保存之前的对话模型根本不知道。在 Agent 系统中Memory 通常被分成几类类型说明典型实现短期记忆Short-term Memory当前会话的对话历史用于维持上下文连贯内存中维护一个消息列表长期记忆Long-term Memory跨会话保存用户偏好、关键事实、历史决策存入向量库 / 数据库运行时检索工作记忆Working Memory当前任务执行过程中的临时中间结果Agent 运行时的状态变量在 LangChain 中最简单的 Memory 可以用ConversationBufferMemory或ConversationSummaryMemory。前者直接保留所有历史消息适合短对话后者会用模型把历史压缩成摘要适合长对话能够节省 token。3.3 Agent从“被动回答”变成“主动干活”Agent智能体的本质是让大模型具备“计划 工具使用 执行循环”的能力。普通 RAG 系统只能回答“是什么”Agent 则进一步回答“怎么办”它可以调用外部工具比如搜索、计算、查数据库、调 API然后根据结果继续决策直到完成目标任务。一个经典的 Agent 循环ReAct 模式是这样工作的接收用户目标。模型思考Thought当前需要做什么。决定动作Action调用哪个工具参数是什么。观察结果Observation拿到工具返回内容。继续循环直到模型认为任务完成给出最终回复Final Answer。LangChain 里可以用create_react_agent或AgentExecutor来构建。如果你使用的是 OpenAI 的 Function Calling 模型也可以通过 bind_tools 的方式让模型自主决定调用哪些函数。3.4 一句话总结三者分工到这里三者的边界已经比较清楚了RAG 负责“知识”让模型能查到外部资料回答更准确、更可溯源。Memory 负责“记忆”让模型能记住上下文、用户偏好、历史状态。Agent 负责“行动”让模型能规划步骤、调用工具、完成多步任务。实际项目中三者并不是互斥的反而经常组合在一起。一个完整的智能问答系统通常是 RAG 作为知识底座Memory 在中间维持对话连续性Agent 在最上层做任务调度和工具编排。4. 完整实战构建一个 RAG Memory Agent 问答系统这一节我们来写一个可运行的最小应用。为了演示方便我直接使用内存向量库和简单的工具函数不依赖过重的外部服务。4.1 先实现一个完整的 RAG 问答模块首先写一个rag_engine.py它负责从文档构建知识库并提供检索回答能力。# 文件路径rag_engine.py from langchain_community.document_loaders import TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings from langchain_chroma import Chroma from langchain_openai import ChatOpenAI from langchain.chains import create_retrieval_chain from langchain.chains.combine_documents import create_stuff_documents_chain from langchain_core.prompts import ChatPromptTemplate PERSIST_DIR ./chroma_db def load_and_split_docs(doc_dir: str): 加载目录下的所有文本文件并切成块。 import os all_docs [] for fname in os.listdir(doc_dir): if fname.endswith(.md) or fname.endswith(.txt): loader TextLoader(os.path.join(doc_dir, fname), encodingutf-8) all_docs.extend(loader.load()) splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50, separators[\n\n, \n, 。, , , , ] ) chunks splitter.split_documents(all_docs) print(f共切分为 {len(chunks)} 个文本块) return chunks def build_vector_store(doc_dir: str): 构建向量库并持久化到本地。 chunks load_and_split_docs(doc_dir) embedding OpenAIEmbeddings(modeltext-embedding-ada-002) vector_store Chroma.from_documents( documentschunks, embeddingembedding, persist_directoryPERSIST_DIR ) return vector_store def get_retriever(): 从本地加载向量库返回 retriever。 embedding OpenAIEmbeddings(modeltext-embedding-ada-002) vector_store Chroma( embedding_functionembedding, persist_directoryPERSIST_DIR ) return vector_store.as_retriever(search_kwargs{k: 4}) def create_rag_chain(): 构建完整的 RAG 问答链。 llm ChatOpenAI(modelgpt-4o-mini, temperature0) retriever get_retriever() prompt ChatPromptTemplate.from_messages([ (system, 你是一个严谨的智能助手。请根据以下资料回答问题。 如果资料中没有相关信息请直接回答“资料中没有相关内容”不要编造。 参考资料 {context}), (human, {input}) ]) combine_docs_chain create_stuff_documents_chain(llm, prompt) return create_retrieval_chain(retriever, combine_docs_chain)代码里主要有几个关键点RecursiveCharacterTextSplitter会按层级分隔符切分文本优先尝试\n\n不行再按\n、句号、空格递归切分尽量保证每个块语义完整。Chroma是一个轻量级向量数据库适合本地学习和原型验证。生产环境可以替换为 Qdrant、Milvus 等。create_retrieval_chain会自动完成“问题 → 召回 → 拼 Prompt → 生成回答”的流程。在data/demo_docs/下放一个示例文档product_manual.md# 产品手册演示用 ## 产品价格 标准版价格为 299 元/年专业版价格为 999 元/年。 企业版需要联系销售定制报价。 ## 退款政策 自购买之日起 7 天内可以无理由退款。 超过 7 天仅支持换购其他版本不支持现金退款。 ## 技术支持 标准版提供 9:00-18:00 的在线工单支持。 专业版和企业版提供 7x24 小时电话支持。构建向量库并测试# 文件路径build_db.py from rag_engine import build_vector_store if __name__ __main__: build_vector_store(./data/demo_docs)运行后你会看到类似下面的输出共切分为 6 个文本块说明文档已经成功切块并写入向量库。接下来写一个简单的测试脚本# 文件路径test_rag.py from rag_engine import create_rag_chain if __name__ __main__: chain create_rag_chain() result chain.invoke({input: 专业版多少钱}) print(result[answer])预期输出专业版价格为 999 元/年。4.2 给对话加上 Memory 模块RAG 只能回答单次问题如果用户接着问“那退款政策呢”系统并不知道“那”指的是刚才的购买场景。这时候就需要 Memory。先写一个memory_module.py维护会话内的消息历史并使用摘要式记忆来控制 token 消耗。# 文件路径memory_module.py from langchain.memory import ConversationSummaryBufferMemory from langchain_openai import ChatOpenAI def create_memory(max_token_limit: int 500): 创建一个对话摘要记忆。 - 短对话保留原始消息。 - 长对话当 token 超过 max_token_limit 时自动压缩成摘要。 llm ChatOpenAI(modelgpt-4o-mini, temperature0) memory ConversationSummaryBufferMemory( llmllm, max_token_limitmax_token_limit, return_messagesTrue, memory_keychat_history, input_keyinput ) return memory def save_context(memory, user_input: str, ai_output: str): 手动保存一轮对话上下文。 memory.save_context({input: user_input}, {output: ai_output}) def load_memory_variables(memory): 取出记忆变量便于后续注入 Prompt。 return memory.load_memory_variables({})在实际项目中生产环境的 Memory 通常需要做持久化把消息存到 Redis 或数据库中。这里为了演示清晰先使用进程内内存。4.3 用 Agent 串联工具检索、记忆、计算、查询下面的示例展示的是如何用 Agent 让模型决定“何时调用 RAG 检索工具、何时使用记忆、何时执行计算”。我们定义两个工具search_knowledge_base检索知识库和calculate做数学计算。# 文件路径agent_runner.py from langchain.agents import create_tool_calling_agent, AgentExecutor from langchain_core.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI from langchain_core.tools import tool from rag_engine import create_rag_chain from memory_module import create_memory # 工具 1知识库检索 tool def search_knowledge_base(query: str) - str: 从产品知识库中检索相关信息回答关于产品、价格、政策等问题。 chain create_rag_chain() result chain.invoke({input: query}) return result[answer] # 工具 2数学计算 tool def calculate(expression: str) - str: 计算数学表达式例如 23*4。 try: # 注意这里仅做示例生产环境不要直接 eval 不可信表达式 return str(eval(expression, {__builtins__: {}}, {})) except Exception as e: return f计算失败: {e} def run_agent(user_input: str, memory): 运行 Agent 主循环。 模型会根据用户问题自主决定调用哪个工具。 llm ChatOpenAI(modelgpt-4o-mini, temperature0) prompt ChatPromptTemplate.from_messages([ (system, 你是智能助手可以根据问题调用工具。 工具选择规则 - 查询产品、价格、政策等知识类问题使用 search_knowledge_base。 - 纯数学计算问题使用 calculate。 - 其他问题直接回答。), (placeholder, {chat_history}), (human, {input}), (placeholder, {agent_scratchpad}) ]) agent create_tool_calling_agent(llm, [search_knowledge_base, calculate], prompt) executor AgentExecutor(agentagent, tools[search_knowledge_base, calculate], verboseTrue) response executor.invoke({ input: user_input, chat_history: memory.load_memory_variables({}).get(chat_history, []) }) return response[output]这里用到了 LangChain 的 Tool Calling Agent。模型在收到用户问题后会判断该调用哪个工具并把工具返回结果作为观察值继续推理直至生成最终答案。4.4 用 FastAPI 封装成 Web 服务最后用 FastAPI 把所有模块串起来实现一个可交互的 HTTP 接口。# 文件路径app.py from fastapi import FastAPI from pydantic import BaseModel from agent_runner import run_agent from memory_module import create_memory # 每个会话维护一个 memory这里简单用内存字典保存。 sessions {} app FastAPI(titleRAG Memory Agent Demo) class ChatRequest(BaseModel): session_id: str message: str class ChatResponse(BaseModel): session_id: str reply: str memory_length: int app.post(/chat, response_modelChatResponse) def chat(req: ChatRequest): if req.session_id not in sessions: sessions[req.session_id] create_memory() memory sessions[req.session_id] reply run_agent(req.message, memory) # 保存对话历史 memory.save_context({input: req.message}, {output: reply}) return ChatResponse( session_idreq.session_id, replyreply, memory_lengthlen(memory.load_memory_variables({}).get(chat_history, [])) ) app.get(/health) def health(): return {status: ok}启动服务uvicorn app:app --reload --port 8000测试接口curl -X POST http://localhost:8000/chat \ -H Content-Type: application/json \ -d {session_id: s1, message: 专业版一年多少钱}再调用一次验证记忆是否生效curl -X POST http://localhost:8000/chat \ -H Content-Type: application/json \ -d {session_id: s1, message: 我刚才问的是什么}如果 Memory 生效第二次的回答应该能回忆起第一次的问题内容。5. 技术选型面对不同场景应该选 RAG、Memory 还是 Agent当你准备设计一个新应用时可以先问自己三个问题用户的核心需求是“获取信息”还是“完成任务”回答是否需要基于外部私域文档是否需要跨多轮对话记住用户偏好根据答案可以按下面的决策逻辑来做技术选型。5.1 只做知识库问答选 RAG如果你的应用只解决“回答准确问题”这一件事例如企业内部的规章制度问答、产品手册智能客服那么 RAG 是最优先的选择。它的优势在于文档更新成本低直接替换向量库中的内容即可。回答可溯源能告诉用户“根据哪份文档中的哪句话”。不需要复杂的任务规划工程实现简单。RAG 的典型应用包括文档问答机器人、企业知识库、法律条款检索、医疗资料问答等。5.2 需要连续多轮对话在 RAG 基础上加 Memory如果用户会连续追问例如用户专业版多少钱用户那企业版呢用户第一个支持 7x24 小时电话支持吗第二个问题里的“企业版”需要结合前文理解。这时就要在 RAG 之上加入 Memory把之前几轮的对话内容注入到 Prompt 中让模型知道“第一个”指的是专业版。实现上有两种选择简单场景用ConversationBufferWindowMemory保留最近 N 轮。长对话场景用摘要式记忆或者把历史消息向量化按相关性召回。5.3 需要自动执行任务必须引入 Agent以下场景光靠 RAG Memory 是远远不够的“帮我查一下订单状态如果超时未发货就发起退款申请。”“把这篇文档翻译成英文并总结成 3 个要点发到我的邮箱。”“分析这份销售数据找到最近三个月增长最快的品类。”这些任务的关键特征是需要调用外部系统、需要多步决策、需要处理中间状态。Agent 的价值正在于此把大模型从“问答引擎”升级为“任务调度中心”。5.4 组合架构参考一个成熟的智能助手最终的架构往往是三者的组合用户输入 │ ▼ Agent 入口任务分类与规划 │ ├── 需要外部知识 → RAG 检索工具 ├── 需要记住上下文 → Memory 模块 ├── 需要查数据/算数据 → 工具调用 │ ▼ 最终回复Agentic RAG就是近来非常热门的架构方向不再把 RAG 当成一个固定流程而是让 Agent 在对话过程中动态决定“要不要检索、检索什么、怎么利用检索结果”。6. 常见问题与排查思路在实践 RAG、Memory、Agent 的过程中下面几个问题出现的频率最高。6.1 检索不到相关内容问题现象常见原因解决思路回答“资料中没有相关内容”但文档里其实有切块粒度过大或过小调整 chunk_size 和 chunk_overlap检索结果总是不相关Embedding 模型效果不佳换更强的 Embedding 模型或改用重排Rerank文档格式复杂PDF 表格、图片解析后内容缺失增加文档解析环节使用 OCR 或结构化解析工具查询词与文档用词不一致存在同义词或口语化表达增加查询改写先用小模型把问题转换成检索词排查时可以先把向量库中的内容直接打印出来确认文档是否成功入库。再检查召回结果的相似度分数分数普遍偏低说明 Embedding 或切块策略需要调整。6.2 回答不准确如果检索到的内容是相关的但模型依然答错大概率是 Prompt 设计问题。常见做法在 system 提示词中明确“如果资料中没有答案就回答不知道”。让模型在回答中标注引用来源索引。设定temperature0或一个很低的值减少输出随机性。6.3 上下文超限 / 显存溢出大型文档检索返回多个 block 后生成的完整 Prompt 可能超过模型上下文限制。如果设置chunk_size过大同时召回 4 个块可能会导致超限。解决思路降低k值减少召回数量。对检索结果做重排只保留最相关的 1-2 个 chunk。使用摘要式 Memory 替代完整对话历史。对于本地部署场景如果遇到out of memory优先检查并发请求数量、模型显存占用和请求队列长度。6.4 Agent 执行工具超时Agent 调用工具时如果外部服务响应慢整个循环会被拖慢。LangChain 中可以为工具增加超时限制也可以在 Agent 提示词中说明“如果工具长时间无响应直接告知用户稍后重试”。问题现象常见原因解决思路Agent 一直调用同一个工具不结束工具返回内容未包含决定性信息改进工具返回格式增加错误码或明确结论工具报错但 Agent 不知道异常信息未传入观察结果在工具内部捕获异常并返回可读错误信息执行链路过长模型多轮试错在 Prompt 中限制最大步骤数量6.5 记忆混乱如果多个用户共用同一个 Memory或者同一用户跨了多天记忆可能会出现串台。生产环境必须按用户维度隔离记忆并考虑长期记忆的持久化。对于敏感信息例如用户身份证号、银行卡信息不要明文存放在记忆里。7. 最佳实践与工程建议7.1 RAG 工程化要点切块策略要结合文档结构。Markdown 可以按标题层级切PDF 可以按段落切代码文档可以按函数切。元数据必须保留。每个 chunk 都应该记录来源文件、页码、章节标题方便回答时做引用溯源。召回后可以加一道重排。单纯靠向量相似度会漏掉部分语义相关但词面差异大的文档重排模型能显著提升准确率。线上知识库更新时采用增量索引而不是全量重建。文档变更时只需要更新对应批次的数据。7.2 Memory 管理注意事项短期记忆按会话维度保存设置过期时间。长期记忆建议只保存“关键事实”不要把所有对话都倒进向量库。定期压缩和清理对于超过 N 天的历史消息可以做摘要归档。注意隐私边界涉及个人数据的记忆必须做脱敏和授权管理。7.3 Agent 的安全边界Agent 能调用工具意味着它能执行操作安全隐患也随之而来。生产环境必须做到最小权限原则。Agent 访问数据库时使用只读账号调用支付接口时必须经过二次确认。工具白名单。不要让 Agent 自由调用所有系统命令只暴露明确设计好的 API。人工审批关键操作。涉及删除、下单、转账等高风险操作应设计“待人工确认”的中间状态。日志全记录。Agent 每一步的 Thought、Action、Observation 都要落日志便于审计和回放。7.4 生产可观测性与评估构建 RAG 应用不是“能回答就行”要建立一套可量化的评估体系。至少要关注三个维度维度指标说明检索质量RecallK正确答案是否在召回结果中生成质量Groundedness回答是否忠于检索到的资料有没有编造引用溯源Citation Accuracy回答中的引用来源是否真实存在建议定期抽取一批测试问题人工标注标准答案跑一个自动化评估流程。只有数据上持续提升才能保证系统上线后效果稳定。8. 总结与下一步学习路线本文围绕 RAG、Memory、Agent 三者的关系做了系统性梳理梳理了它们各自解决什么问题、在什么场景下使用、如何组合配合并通过一个 FastAPI LangChain 的示例演示了从文档入库、向量检索、对话记忆到 Agent 调用工具的基本链路。从热词趋势来看RAG 实战、Agent 开发、企业级 RAG 的应用痛点是目前社区讨论最密集的方向。建议初学者按以下路线继续深入先把 RAG 基础链路吃透文档加载 → 切块 → 向量化 → 检索 → 问答。再研究切块策略优化和重排策略理解如何提高检索精准度。学习 Agent 的开发框架例如 LangChain 的 Tool Calling或 Dify 这类低代码平台。深入 Memory 设计与状态管理尝试接入 Redis、向量数据库做持久化。最后做一个小型完整项目把 Agentic RAG 从理论落到实际应用中。如果你正在做智能客服、知识库问答或多步骤任务系统建议从最小可行版本开始先把单一链路跑通再逐步叠加能力。实践永远是最好的学习方式欢迎动手试试遇到具体问题可以在评论区一起讨论。