从Naive RAG到Agentic RAG:智能检索增强生成的演进与实战

📅 2026/8/14 12:15:06
从Naive RAG到Agentic RAG:智能检索增强生成的演进与实战
1. 从“查字典”到“找专家”RAG技术的演进脉络如果你最近在折腾大语言模型应用那“RAG”这个词肯定已经听得耳朵起茧了。它就像AI应用开发里的“水电煤”成了构建靠谱智能系统的标配。但很多人对RAG的理解可能还停留在“把文档切碎、变成向量、存起来、然后搜一下”这个层面。这没错这是最基础的玩法业内通常称之为Naive RAG或者叫“朴素RAG”。它就像一个老实巴交的图书管理员你问一个问题它就去庞大的向量书库里找到最“像”你问题的几段文字然后原封不动地递给大模型让模型基于这些片段生成答案。这个模式解决了大模型“胡说八道”幻觉和知识陈旧的核心痛点立下了汗马功劳。但用久了你会发现这位“朴素”的图书管理员有点轴。比如你问“公司最新的差旅报销政策有什么变化”它可能会返回给你三份文档的片段一份是两年前的旧政策全文一份是今年新政策的第三章还有一份是财务部发的关于发票类型的通知。模型拿到这些信息后需要自己费力地去拼凑、对比、理解“变化”在哪里效果很不稳定。整个过程是单向、静态的检索和生成是割裂的两步。于是大家开始思考能不能让这个系统变得更“智能”一点能不能让检索过程本身也具备思考、判断和决策的能力这就是Agentic RAG智能体驱动的RAG诞生的背景。它不再是那个被动的图书管理员而更像一个拥有专业经验的“领域专家”或“侦探”。你提出一个问题这位专家会主动分析你的意图拆解任务决定去哪里找资料、用什么方式找、找到后如何验证和整合甚至会在信息不足时主动向你追问细节。Agentic RAG的核心是将大型语言模型本身的推理和规划能力注入到检索增强生成的每一个环节让“检索”成为一个动态、迭代、可决策的智能过程。从Naive RAG到Agentic RAG不是简单的版本升级而是一次设计范式的跃迁。前者关注的是“信息匹配”的精度和效率后者追求的是“任务达成”的可靠性和智能化。接下来我们就深入这个智能检索系统的内部看看它是如何一步步“进化”的。2. Naive RAG经典架构的基石与局限性在深入Agentic的复杂世界之前我们必须先扎实理解Naive RAG。它是所有高级RAG系统的地基其设计中的优缺点直接催生了后续的进化方向。一个典型的Naive RAG系统可以清晰地分为三个核心阶段索引、检索、生成。2.1 核心流程的三段论索引阶段的目标是把非结构化的原始知识如PDF、Word、网页、数据库加工成便于检索的格式。这个过程远不止是“切碎”那么简单。文档加载与解析使用像Unstructured、PyPDF2、Docling这样的库把各种格式的文件转换成纯文本。这里第一个坑就来了格式丢失。PDF里的精美表格、图片里的文字、扫描件处理不好就会变成乱码或直接缺失。我的经验是对于复杂文档最好采用“组合拳”比如用pdfplumber提取表格用pytesseract做OCR识别图片再自己写规则做信息缝合。文本分割这是影响效果最关键的步骤之一。你不能简单按固定字符数比如512个token来切。想象一下一个完整的操作步骤被拦腰切断或者一个定义句被分在两段检索效果会大打折扣。常用的策略有递归字符分割按段落、句子、换行符等自然分隔符进行递归分割尽量保证语义完整性。滑动窗口在固定大小的块上使用重叠窗口避免信息在边界丢失。比如块大小500token重叠100token。基于语义的分割用更小的模型如sentence-transformers计算句子间的相似度在语义变化大的地方进行分割。这更智能但计算成本也高。我的实操心得没有银弹。我通常会对文档类型做分析。技术手册适合按章节/子标题分割会议纪要适合按议题分割长篇文章可以尝试滑动窗口。一个黄金法则是分割后的块应该能够独立回答一个潜在的问题。你可以用一些假想问题来检验。向量化与存储将文本块通过嵌入模型转化为向量存入向量数据库。选型是关键嵌入模型别只盯着OpenAI的text-embedding-ada-002。开源模型如BGE-M3、Snowflake Arctic Embed、Nomic Embed在MTEB等基准测试上表现非常亮眼且数据隐私可控。选择时一定要用你自己领域的数据做测试看模型在你关心的任务如相似性搜索、检索上的表现。向量数据库Pinecone、Weaviate、Qdrant、Milvus是主流选择。对于快速原型ChromaDB轻量易用对于生产级海量数据和高吞吐Milvus或Qdrant更合适。需要关注其是否支持过滤metadata filtering、多向量搜索等高级功能。检索阶段是查询发生时的工作。系统将用户问题同样向量化然后在向量库中进行相似性搜索通常是余弦相似度或点积返回Top-K个最相关的文本块。注意这里最大的误区是认为“相似度最高最相关”。语义相似度模型可能无法理解“反义词”或“否定”关系。例如问题“哪些产品不支持7天无理由退货”可能与描述“支持7天无理由退货”的文本有高相似度因为关键词高度重叠但这会返回完全相反的答案。生成阶段是最简单的部分。将检索到的Top-K个文本块作为上下文连同用户问题一起构造成提示词Prompt提交给大语言模型让其生成最终答案。典型的Prompt模板是“请基于以下上下文信息回答问题。如果上下文不包含答案请说‘根据已知信息无法回答’。上下文{context} \n 问题{question}”。2.2 朴素架构的“阿喀琉斯之踵”尽管流程清晰但Naive RAG在实战中暴露出一系列棘手问题我称之为“七宗罪”检索精度不足“找不到”仅靠语义相似度无法处理多义词“苹果”是水果还是公司、指代消解“他说的那个方法”指哪个、复杂逻辑查询“找出A和B都满足但C不满足的条件”。上下文窗口浪费“塞垃圾”Top-K个块可能包含大量重复信息或无关细节挤占了宝贵的上下文窗口导致模型无法聚焦关键信息甚至因无关信息干扰而生成错误答案。缺失全局信息“见木不见林”检索到的都是局部片段模型可能无法理解文档的整体结构、核心论点或叙事脉络。比如要总结一篇论文的贡献只给几个方法细节的片段是远远不够的。静态检索缺乏交互“一锤子买卖”一次检索定生死。如果第一次没找到系统就“放弃”了不会根据初步结果调整搜索策略。无法处理多跳问题“只跑一趟腿”对于需要串联多个信息源才能回答的问题例如“张三的经理的老板是谁”Naive RAG通常无能为力。它一次性检索缺乏分步推理和迭代检索的能力。对噪声敏感“脆弱”检索结果中只要混入一个高度相关但事实错误的片段比如社区里有人写错了答案就可能导致模型产生“幻觉”因为它倾向于相信提供的上下文。缺乏验证与溯源“说不清”虽然提供了引用片段但模型生成答案时是否真的严格依据了这些片段有没有偷偷掺杂自己的知识或臆测这个过程缺乏透明度和可控性。正是这些痛点推动着RAG技术向更智能、更动态的方向演进。而解决这些问题的钥匙就在于引入“智能体”的思维。3. Agentic RAG引入“智能”与“决策”的新范式Agentic RAG不是一个具体的工具或框架而是一种设计范式。其核心思想是将大型语言模型作为一个具有推理和规划能力的“大脑”智能体来动态地指挥和控制整个RAG流程。检索不再是一个孤立的预处理步骤而是成为了一个由LLM驱动的、可迭代、可决策的子任务。3.1 智能体核心能力解构在这个范式下LLM智能体需要具备以下几种关键能力任务规划与分解面对一个复杂查询智能体首先不是直接去搜而是像人类专家一样先“理解”和“拆解”问题。例如用户问“如何为公司的新产品‘星海’设计一个整合营销方案”。智能体可能会将其分解为“1. 查找公司‘星海’产品的核心卖点与技术文档。2. 检索过往类似产品的成功营销案例。3. 查找当前目标市场的用户画像分析报告。4. 汇总公司现有的营销渠道和预算规范。” 每一步都是一个更具体、更易检索的子任务。工具调用智能体需要知道“用什么工具”去完成每个子任务。工具不仅包括向量数据库检索还可以是关键词搜索在传统全文检索引擎如Elasticsearch中查找。数据库查询用SQL查询结构化数据。API调用获取实时信息如天气、股价、新闻。计算器进行数值计算。代码解释器执行数据分析或生成图表。甚至调用另一个RAG系统针对特定知识库进行检索。反思与迭代这是Agentic RAG超越Naive RAG的灵魂。智能体拿到初步检索结果后会进行自我评估“这些信息足够回答子问题了吗信息之间有没有矛盾我是否需要换个关键词或换个数据源再查一次” 基于反思它可以调整查询词、切换检索工具、或者决定进行多轮检索直到收集到满意、一致的信息。信息合成与验证收集齐所有子任务的信息后智能体不是简单拼接而是进行交叉验证、去重、梳理逻辑关系最后合成一个连贯、准确、完整的最终答案。它需要注明每部分信息的来源实现可追溯。3.2 主流实现模式剖析目前社区和实践中主要涌现出几种典型的Agentic RAG实现模式1. 自适应检索型这是最直接的一种增强。系统不是固定返回Top-K个结果而是让LLM参与决定“怎么搜”和“搜多少”。查询重写/扩展LLM分析原始问题将其重写为更利于向量检索的形式或生成多个相关的查询词进行多查询检索。例如将“怎么养好一只小奶猫”重写为“幼猫喂养指南”、“新生小猫护理注意事项”、“0-6个月猫咪饮食健康”。自适应检索深度LLM根据问题的复杂性动态决定检索多少个片段K值。简单问题可能K3就够了复杂综述性问题可能需要K10。甚至可以引入递归检索先检索少量片段如果LLM判断信息不足则触发新一轮检索。混合检索路由系统拥有多种检索器向量检索、关键词检索、图数据库检索等。LLM作为“路由器”分析问题类型决定调用哪个或哪几个检索器。例如事实性问答用向量检索精确术语匹配用关键词检索关系查询用图检索。2. 多智能体协作型这是更复杂的架构模拟了一个专家团队。针对一个复杂任务系统会虚拟出多个具有不同角色的智能体。角色示例调度智能体负责接收用户原始任务进行任务分解和规划。检索专家智能体专门负责执行各类检索任务精通不同数据源和检索语法。分析智能体负责对检索回来的信息进行批判性分析、对比和验证。合成智能体负责将分析后的信息整合成最终答案并确保文风一致。工作流程调度智能体将子任务分发给检索专家检索专家将结果交给分析智能体分析智能体评估后可能要求检索专家重新查找最后将净化后的信息交给合成智能体。整个过程中智能体们通过“工作空间”或消息队列进行通信和协作。LangGraph、CrewAI等框架非常适合构建此类系统。3. 迭代式问答与主动追问型这种模式将RAG变成了一个交互式、对话式的探索过程。过程用户提出初始问题。系统进行检索并生成一个初步答案但同时会评估答案的置信度或信息的完整性。如果发现信息有缺口、存在多种可能、或问题本身模糊系统会主动向用户提出澄清性问题。例如“您问的‘高性能’具体是指计算速度还是内存带宽”“关于XX事件的报告您是需要2023年的还是2024年的”。根据用户的反馈系统再次进行更精准的检索和生成。如此循环直至产出令人满意的答案。这极大地提升了复杂问题解决的准确性和用户体验。4. 构建实战从零搭建一个Agentic RAG系统原型理论说了这么多我们来点实际的。我将带你用LangChain和LangGraph框架搭建一个具备自适应检索和多跳推理能力的Agentic RAG系统原型。这个系统将能回答类似“公司里负责‘星海’项目的团队经理他的直属上级是谁”这样的问题。4.1 环境准备与工具选型首先明确我们的技术栈框架LangChainLangGraph。LangChain提供了丰富的RAG组件和智能体工具LangGraph则擅长描述和控制有状态的、循环的智能体工作流。大模型选择Qwen2.5-7B-Instruct的API版本或本地部署。它推理能力强对中文支持好且指令遵循能力出色非常适合做智能体的“大脑”。注此处仅为示例实际可根据资源选择GPT-4o、DeepSeek或GLM-4等。嵌入模型选用BGE-M3。它支持多语言在检索和重排序任务上表现均衡并且可以输出密集向量、稀疏向量和ColBERT向量为未来扩展混合检索留有余地。向量数据库使用ChromaDB因其轻量、易用适合原型开发。生产环境可替换为Qdrant。知识源我们模拟一个公司内部知识库包含员工信息表employees.csv、部门结构表departments.csv和项目文档若干PDF。# 环境安装假设已安装Python 3.10 pip install langchain langchain-community langgraph chromadb pypdf sentence-transformers # 如果需要使用Qwen API pip install dashscope # 如果使用本地Qwen模型 # pip install transformers torch4.2 构建智能体工作流我们的目标是构建一个能处理“多跳查询”的智能体。工作流设计如下接收问题用户输入问题。规划与分解由LLM判断是否需要多步检索。如果需要分解出第一个子问题。工具调用与检索根据子问题类型选择合适工具检索员工表检索项目文档进行查询。反思与迭代LLM分析检索结果判断是否已回答当前子问题以及是否需要提出新的子问题。合成答案当所有必要子问题都被解答后LLM综合所有信息生成最终答案。我们用LangGraph来实现这个有状态的工作流。from typing import TypedDict, List, Annotated import operator from langchain_core.messages import HumanMessage, SystemMessage from langchain_qwen import ChatQwen # 假设使用Qwen API from langchain_community.vectorstores import Chroma from langchain_community.embeddings import HuggingFaceEmbeddings from langgraph.graph import StateGraph, END from langgraph.graph.message import add_messages from langchain_community.document_loaders import CSVLoader, PyPDFLoader from langchain_text_splitters import RecursiveCharacterTextSplitter # 1. 定义状态结构 class AgentState(TypedDict): messages: Annotated[List, add_messages] # 对话消息历史 original_question: str # 原始问题 current_subquestion: str # 当前正在处理的子问题 retrieved_context: List[str] # 累积检索到的上下文 final_answer: str # 最终答案 step: int # 当前步骤 # 2. 初始化核心组件 llm ChatQwen(modelqwen2.5-7b-instruct, api_keyyour-api-key) # 加载并索引知识库此处简化实际需分别处理CSV和PDF embedding_model HuggingFaceEmbeddings(model_nameBAAI/bge-m3) # ... 假设我们已经有了一个填充好的向量库 vectorstore # vectorstore Chroma.from_documents(documents, embedding_model, persist_directory./chroma_db) vectorstore Chroma(persist_directory./chroma_db, embedding_functionembedding_model) # 3. 定义工具函数 def retrieve_from_vectorstore(query: str, k: int 5) - str: 从向量库检索相关文档片段 docs vectorstore.similarity_search(query, kk) return \n\n.join([doc.page_content for doc in docs]) def query_employee_db(query: str) - str: 模拟查询员工数据库这里简化为一个函数 # 实际应连接数据库执行SQL这里返回模拟数据 if 张三 in query: return 员工姓名张三 职位高级工程师 所属部门产品研发部 经理李四 elif 李四 in query: return 员工姓名李四 职位研发经理 所属部门产品研发部 上级王五 elif 王五 in query: return 员工姓名王五 职位技术总监 所属部门技术中心 else: return 未找到匹配的员工信息。 # 4. 定义智能体节点函数 def planner_node(state: AgentState) - AgentState: 规划节点分析问题决定下一步 messages state[messages] # 系统提示词引导LLM进行任务分解 system_prompt 你是一个智能信息助理。你的任务是分析用户问题判断是否需要通过多步检索来回答。 如果需要请生成第一个需要回答的子问题。请只输出子问题本身不要输出其他解释。 如果原始问题可以直接回答请输出“FINAL”。 planner_prompt [ SystemMessage(contentsystem_prompt), HumanMessage(contentf原始问题{state[original_question]}\n当前已收集的信息{state[retrieved_context]}) ] response llm.invoke(planner_prompt) decision response.content.strip() if decision.upper() FINAL: state[current_subquestion] FINAL else: state[current_subquestion] decision state[step] 1 return state def retrieval_node(state: AgentState) - AgentState: 检索节点根据子问题调用工具检索 sub_q state[current_subquestion] if sub_q FINAL: return state # 简单的路由逻辑如果问题包含“员工”“谁”“经理”等查员工库否则查向量库 if any(keyword in sub_q for keyword in [员工, 谁, 经理, 上级]): context query_employee_db(sub_q) else: context retrieve_from_vectorstore(sub_q) state[retrieved_context].append(f【子问题】{sub_q}\n【相关信息】{context}) return state def reflector_node(state: AgentState) - AgentState: 反思节点评估信息是否足够决定继续还是结束 if state[current_subquestion] FINAL: state[current_subquestion] READY_TO_ANSWER return state # 让LLM判断是否还需要继续追问 reflection_prompt f 基于当前收集到的信息 {chr(10).join(state[retrieved_context])} 针对原始问题“{state[original_question]}”我们是否已经获得了足够的信息来合成最终答案 如果已经足够请回复“SUFFICIENT”。 如果还需要更多信息请提出下一个需要解决的关键子问题。 response llm.invoke([HumanMessage(contentreflection_prompt)]) decision response.content.strip() if decision.upper() SUFFICIENT: state[current_subquestion] READY_TO_ANSWER else: # 将LLM提出的新子问题作为下一轮的开始 state[current_subquestion] decision state[step] 1 return state def answer_node(state: AgentState) - AgentState: 答案合成节点生成最终答案 synthesis_prompt f 请严格根据以下提供的信息回答原始问题“{state[original_question]}”。 如果信息不足请明确说明哪些部分无法确定。 信息 {chr(10).join(state[retrieved_context])} 请给出完整、准确的答案 response llm.invoke([HumanMessage(contentsynthesis_prompt)]) state[final_answer] response.content state[messages].append(HumanMessage(contentstate[original_question])) state[messages].append(AIMessage(contentstate[final_answer])) return state # 5. 构建并编译工作流图 workflow StateGraph(AgentState) # 添加节点 workflow.add_node(planner, planner_node) workflow.add_node(retriever, retrieval_node) workflow.add_node(reflector, reflector_node) workflow.add_node(answer, answer_node) # 设置边和条件流转 workflow.set_entry_point(planner) workflow.add_edge(planner, retriever) # 关键条件边。从反思节点出来根据状态决定是继续检索还是去生成答案 def decide_after_reflection(state: AgentState): if state[current_subquestion] READY_TO_ANSWER: return answer else: return planner # 返回规划节点开始新一轮“规划-检索-反思” workflow.add_conditional_edges( reflector, decide_after_reflection, { answer: answer, planner: planner } ) workflow.add_edge(retriever, reflector) workflow.add_edge(answer, END) # 编译图 app workflow.compile() # 6. 运行测试 initial_state { messages: [], original_question: 负责‘星海’项目的团队经理他的直属上级是谁, current_subquestion: , retrieved_context: [], final_answer: , step: 0 } # 假设我们的知识库中项目文档提到“星海”项目由“张三”负责而员工表中有张三及其经理的信息。 result app.invoke(initial_state, config{recursion_limit: 10}) # 限制递归深度 print(最终答案, result[final_answer]) print(检索历史, result[retrieved_context])这个原型展示了Agentic RAG的核心循环规划 - 执行检索- 反思 - 再规划。当面对“星海项目经理的上级”这个问题时智能体可能会先规划出子问题1“‘星海’项目的负责人是谁”从项目文档中检索出“张三”然后反思发现需要知道张三的上级于是规划出子问题2“员工张三的经理是谁”从员工数据库中检索出“李四”最后合成答案“星海项目的团队经理是李四”。4.3 关键配置与调优心得提示词工程是灵魂planner_node和reflector_node的系统提示词System Prompt直接决定了智能体的“思考方式”。你需要精心设计明确告诉它扮演什么角色、输出格式是什么、决策逻辑是什么。多迭代几次提示词效果天差地别。控制循环与超时必须设置递归深度限制recursion_limit或超时机制防止智能体陷入“思考死循环”。例如同一个问题反复检索却无法推进时应强制跳出并提示用户。工具描述的准确性在更复杂的系统中你需要用自然语言清晰地向LLM描述每个工具的功能、输入和输出格式。LangChain的tool decorator和bind_tools方法能很好地完成这一点。状态管理AgentState的设计至关重要。它需要包含所有必要的历史信息以供后续节点决策。确保状态简洁且包含所有上下文。评估与监控Agentic系统比Naive RAG更难评估。除了答案准确性还要关注其推理步骤的合理性、工具调用的正确率和循环次数。建立一套评估体系至关重要。5. 工程化挑战与未来展望将Agentic RAG从原型推向生产会面临一系列严峻的工程挑战。1. 延迟与成本Naive RAG通常只需一次检索一次生成。Agentic RAG涉及多轮LLM调用规划、反思、生成和可能的多轮检索延迟和API成本会成倍增加。优化策略使用小模型进行规划/路由用7B甚至更小的模型处理任务分解和工具选择只在最终答案合成时使用大模型。缓存对常见的子查询结果进行缓存。异步与并行当子任务间没有依赖时让多个检索工具并行执行。设置超时和回退当智能体循环超过一定次数或时间自动降级到Naive RAG模式或直接返回当前最佳结果。2. 稳定性与可靠性LLM作为决策核心其输出的不确定性是最大风险。它可能规划出不合逻辑的步骤或选择错误的工具。缓解措施结构化输出强制要求规划节点输出JSON等结构化数据便于程序解析和校验。验证层在关键决策点如工具调用前加入规则验证或轻量级模型验证。完备的异常处理为智能体的每一个可能“犯错”的地方设计兜底方案。3. 评估与测试如何评估一个动态系统的好坏需要多维度的评估集端到端答案准确性最终答案的正确性。推理过程忠实度智能体的推理步骤是否基于提供的信息是否合理。工具使用效率调用工具的次数是否必要是否选择了最优工具。人工评估环路将复杂case加入人工评估集持续优化提示词和工作流。未来我认为Agentic RAG会沿着以下几个方向深化更轻量与专用化会出现为特定领域如法律、金融、医疗优化的、开箱即用的Agentic RAG解决方案它们内置了领域知识和工作流降低使用门槛。与知识图谱深度融合将向量检索与图谱检索深度融合智能体可以更好地理解实体间的关系进行更复杂的推理。长期记忆与学习智能体能够记住与用户的交互历史学习用户的偏好提供越来越个性化的服务。标准化与模块化像LangChain这样的框架会进一步抽象出通用的Agentic组件让开发者像搭积木一样构建智能检索系统。从Naive RAG到Agentic RAG我们正让检索系统从一个被动的“资料库”转变为一个主动的“智能协作者”。这条路充满挑战但也正是其魅力所在。它不再仅仅是关于如何找到信息而是关于如何像人类一样带着思考和目标去探索信息并最终解决问题。