资讯详情

Agentic RAG实战:从传统检索到多跳推理的知识库问答升级

📅 2026/10/21 3:45:02 | 华诺云谱 👁 阅读
Agentic RAG实战:从传统检索到多跳推理的知识库问答升级
我们内部有个知识库问答系统某天演示的时候有人问了一句为什么线上Nginx突然拒绝连接系统翻了半天资料最后给出一个读起来很像那么回事的答案把错误日志里的连接数超限那段搬了出来。可实际上知识库里躺着一篇监控告警说明、一篇网络策略变更记录、还有一篇负载均衡配置手册三份文档合起来才能拼出真正的原因。传统RAG回答不出这种问题不是它不够努力而是它的工作方式决定了它只能做一个一次查完就交卷的搜索引擎而不是一个会追着线索跑的调研员。Agentic RAG要解决的正是这个问题。它把RAG从检索-拼接-生成的被动流水线改造成一个由大模型自主决策、反复检索、逐步推理的主动过程。Agent决定先查什么、查不到再查什么、查到的信息和已有证据冲突时信谁。这篇文章我会先讲清楚传统RAG到底卡在哪里再拆解Agentic RAG的核心模块然后给出一套可以直接落地的代码实现最后把我实测中踩过的坑全部倒出来。适合两类人看一类是已经在做RAG、但对效果不满意想升级的开发者另一类是刚接触Agent概念、想知道这玩意儿到底能和RAG擦出什么火花的AI工程师。1. 为什么说传统RAG只是查资料Agentic RAG才是做研究1.1 传统RAG的标准流程与隐含假设传统RAG的经典流程现在基本被说烂了用户输入query系统把query向量化去向量库里做相似度检索取回top-k个文档片段拼进prompt让LLM一次性生成答案。整个过程是一条直线没有任何分叉和回头路。这条流水线背后其实藏着一个很强的隐含假设用户的问题只要查一次就能回答。这个假设在简单场景下成立比如公司年假政策是什么、XX接口的返回码含义这种单跳问题一次检索确实够用。但现实里的提问根本不是这种形状真实用户会把复杂问题拆得七零八碎甚至问题本身就是模糊的比如为什么新上线的功能经常超时、这个月收入为什么比上个月少了两成。这些问题不是单靠相似度召回的。功能超时可能是代码发布、数据库连接池、外部依赖抖动、链路追踪日志多个来源交织的结果收入下降可能涉及订单量、客单价、退款率、促销策略好几个维度。传统RAG拿一个孤立的query去做一次向量匹配本质上是在拿一把钥匙开好几把锁开不开是常态。1.2 三个绕不开的硬伤我把传统RAG在实际业务里的毛病总结成三个每一个都是Agentic RAG的出发点。第一个硬伤查询表达和知识库语言之间存在语义鸿沟。用户说网站卡爆了知识库里写的是高峰期CPU使用率超过阈值触发熔断字面上像语义上差很远。向量检索对这种口语化表达有宽容度但宽容度有限一旦知识库专业性很强口语query的召回质量会断崖式下降。第二个硬伤无法应对多跳推理Multi-hop。很多业务问题的答案分散在多份文档里需要先查A文档得到一个中间线索再拿这个线索去查B文档。传统RAG没有中间态的概念它压根没有按图索骥的能力。上面的Nginx例子正是典型你需要先知道连接拒绝和连接数限制有关然后去查限流策略再查阈值配置最后才能定位到变更记录。第三个硬伤生成阶段没有查证闭环。LLM给了答案但没人校验这个答案到底是不是基于检索内容得出的也没有机制去追问检索到的片段互相矛盾怎么办。结果就是模型在最后一步自由发挥产生忠实性幻觉——检索到了正确信息生成阶段却给你编点别的东西。这三个硬伤不是通过调参数能解决的它们嵌在RAG的架构里。想改得先动架构这就是Agentic RAG出现的原因。1.3 顺便说清楚Agentic RAG不是什么网上有不少人把Agentic RAG和在RAG外面包一层Agent框架画等号这是最常见的误解。Agentic RAG不是给RAG加一个聊天机器人外壳也不是简单地让Agent去调用一个RAG接口。真正的Agentic RAG是把检索行为本身拆分成Agent可以自主决策的动作序列。Agent不再是一个被动的问答器而是一个主动的信息收集者。它手里拿着好几张牌向量检索是一个工具、关键词/全文检索是一个工具、SQL查数据库是一个工具、调用某个API查实时数据又是一个工具。Agent决定什么时候出牌、出哪张牌、出了牌得到的结果怎么影响下一轮动作。打个比方。传统RAG是一个只会在图书馆前台问一次路的读者管理员告诉他去三楼左转第二排书架他走过去拿一本书就回来交差。Agentic RAG是同一个读者他到了三楼发现那本书被人借走了他会自己跑到检索台查借阅记录发现隔壁分馆还有一本然后打车过去顺便在途中看到一本相关的工具书也一并拿回来最终给出一份交叉验证过的材料。这个区别决定了整个系统设计的风格。传统RAG的系统设计是把检索做得更快更准Agentic RAG的系统设计是让决策更合理、让动作更可控。2. Agentic RAG的架构拆解把检索从步骤变成工具2.1 核心心智模型LLM作为决策器检索器作为可调用工具Agentic RAG架构的底座是ReAct模式Reasoning Acting。在这个模式里LLM不再是最终生产答案的那个角色它同时是决策器和生成器。它先分析当前已有的信息决定下一步动作然后调用对应工具工具返回结果后它把新信息和旧信息放在一起继续推理直到它认为自己有足够证据生成最终答案。这个循环跑起来之后整个RAG系统的控制流不再是写死的而是由LLM在运行时动态决定的。你可以把Agent理解为一位主厨RAG组件是案板上的各种刀具和食材主厨不是机械地按菜谱执行而是根据台面上的食材新鲜度、火候状态、上菜速度实时调整操作顺序。对应到代码层面这种模式需要一个工具注册表和一个循环控制器。工具注册表告诉Agent你有哪些工具可用、每个工具是干什么的、参数是什么格式循环控制器负责执行推理-调工具-观察结果-再推理这个循环直到触发终止条件。工具注册表的定义质量直接决定Agentic RAG的上限。你要是只给Agent一个向量检索工具那它本质上还是普通RAG只不过多绕了几圈。一个合格的Agentic RAG系统最少应该有两个以上互补的检索工具向量检索负责语义相似召回关键词搜索负责精确匹配必要时再加一个结构化查询工具负责查数据库。工具之间的差异性越大Agent的决策空间就越大系统应对复杂查询的能力也就越强。2.2 路由模块什么时候查、查哪里不是用户说了算Agentic RAG里的第一个关键决策点是路由。用户丢过来一句话Agent要先判断这个问题需不需要检索如果需要是查向量库、查全文索引、还是查数据库这个判断不是语义分类器那种简单的事。用户可能问今年的OKR是什么这种明确问题直接查文档就行可能问帮我看看上个月的报表这种问题需要查数据库做聚合还可能问你觉得我该怎么办这种开放式问题说实话检索文档的意义不大不如直接生成建议。把这三类问题全部丢进同一个向量检索引擎是很多RAG系统效果差的根源。我在生产环境里常用的路由策略是混合决策先让一个小模型或者同一个LLM的低温度模式做意图分类分类粒度不需要太细三类就够——需要精确检索、需要语义检索、无需检索。拿到意图之后再决定用哪条链路。这样做的成本很低但能非常有效避免那种用户问了个简单问题、系统却去翻了一堆不相关文档的尴尬。路由还有一个更细的维度路由到哪个知识域。企业知识库经常按业务线分开存储运维文档、产品文档、HR政策、财务制度各管一摊。如果全部塞进一个向量索引检索时容易串味如果Agent先用分类模型判断问题属于哪个域再做检索精度会有明显提升。这个操作在工程上叫分域路由实现并不复杂但效果立竿见影。2.3 查询改写与多跳追问自己把问题掰开揉碎路由解决去哪儿查的问题查询改写解决查什么的问题。传统RAG对用户原始query直接做向量化口语化问题、指代问题那个系统第二版方案、上下文不完整的问题召回质量都很差。Agentic RAG的处理方式是把查询改写当成一个独立的工具调用Agent根据自己的判断把用户的query改写成更适合检索的形态甚至拆分成多个子查询分别检索然后再把结果合并。我在实践中发现查询改写有两个方向特别值得做。第一个是指代消解和上下文补全。用户说它的报错信息很奇怪Agent需要从对话历史里找到它指的是哪个服务用户说和上个问题一样的环境Agent要把环境具体化为测试环境的K8s集群。把这些信息补进query检索效果会好上一大截。第二个方向是多角度拆解。一个复杂的业务问题Agent把它拆成三到四个独立子问题每个子问题做一次检索最后把证据汇总。比如这个季度留存率下降的原因Agent会拆成本季度留存率数据变化趋势、最近产品功能变更记录、客服反馈高频问题汇总三个查询分别检索三块知识库。这个拆解过程看起来简单实际上很考验LLM的推理能力模型对业务领域理解越深拆得越准。拆解之后还要有个合并和去重的步骤。多轮检索回来的文档片段经常有重叠直接全部塞给生成器不仅浪费token还会稀释重点。我通常会在最终生成前加一个重排Rerank环节把多轮检索回来的候选文档做一个统一的re-rank只保留最相关的top-5文档进入最终prompt。这一步让整个系统的最终答案质量有质的提升。2.4 自我反思和信源验证让引用可被审查如果只做到多轮检索查询改写这还不够因为Agent可能在错误的路径上越走越远。Agentic RAG区别于普通带检索功能的多轮对话的关键在于它加入了自我反思Self-reflection机制。具体来说Agent在拿到检索结果后不是立刻拿去生成答案而是先做一次质量评估这些文档和当前问题相关吗、它们之间有没有矛盾、目前的证据链完整吗还缺什么这个评估结果会决定下一步动作继续检索、换一个角度检索还是直接输出答案。反思机制在工程上有多种实现方式我用的比较多的是结构化验证提示词。在每轮循环的最后要求LLM输出一个JSON格式的验证结果包含两个字段sufficient表示证据是否足够missing表示还缺什么信息。如果sufficient为falseAgent就把missing字段作为下一轮检索的目标。这个设计把反思从想法变成了可执行的代码逻辑也让整个系统的行为变得可观测——你能看清楚Agent每一步在做什么、为什么这样做。信源验证是另一个容易被忽略的点。企业在内部知识库场景下对答案的可信度要求非常高。我在系统里加了一个强制约束最终答案中的每一条关键结论必须标注来源文档ID和段落位置。这个约束需要在prompt里明确要求同时在解析层做出校验——如果答案里出现了没有标注来源的结论系统直接把答案丢掉重新生成。这一步的意义不只是防幻觉更重要的是让用户敢于使用这个系统。用户看到答案里带着文档编号和引用标记他可以在原始文档里核验——信任感就是这么建立起来的。内部工具不像C端产品那样追求一步到位用户更在意你说的话我能查证。3. 手写一个最小可用的Agentic RAG3.1 准备工作依赖与基础组件前面讲的都是架构概念这一节直接上代码。我会分两版实现第一版是一个不依赖任何Agent框架的最小循环方便你理解核心逻辑第二版是基于LangGraph的状态机版本适合直接上生产。完整代码我会拆开讲每一段都说明为什么要这么写。先准备基础依赖。假设你有一个已经建好的向量库用任何主流的向量数据库或者本地库都可以我把关键类抽象出来# 核心数据结构 dataclass class AgentState: messages: list # 对话历史 query: str # 当前检索目标 evidence: list # 已收集的检索证据 iteration: int # 当前迭代轮数 missing_info: list # 反思环节认为缺失的信息 final_answer: str # 最终生成的答案 dataclass class RetrievalResult: content: str # 文档内容 source_id: str # 来源文档ID score: float # 相关度分数 metadata: dict # 其他元信息页码、章节等# 工具注册表所有Agent可用的检索工具 class ToolRegistry: def __init__(self): self.tools {} def register(self, name, description, fn): self.tools[name] { description: description, function: fn } def list_tools_for_context(self): # 把工具描述格式化成适合放入LLM prompt的文本 return \n.join([ f- {name}: {info[description]} for name, info in self.tools.items() ]) def call(self, name, **kwargs): return self.tools[name][function](**kwargs)这里把工具注册表单独抽象出来是生产环境里的推荐做法。工具越来越多的时候你不可能把每个工具的调用逻辑都胶水代码一样粘在Agent里有一个注册中心方便统一管理工具的scheme、权限和参数校验。3.2 核心循环代码ReAct逻辑的落地接着是Agent的核心循环。这一版代码逻辑刻意保持精简但完整跑通了路由-改写-检索-反思-再检索-总结的闭环def agentic_rag_loop( query: str, registry: ToolRegistry, llm: ChatOpenAI, max_iterations: int 5, top_k: int 5, ) - str: 最简版Agentic RAG核心循环 # 初始化Agent状态 state AgentState( messages[], queryquery, evidence[], iteration0, missing_info[], final_answer ) while state.iteration max_iterations: state.iteration 1 # 第一步决策下一步动作 decision llm.invoke( _build_decision_prompt( state.query, state.evidence, registry.list_tools_for_context(), state.missing_info ) ) # 期望LLM返回一个JSON结构化决策 decision json.loads(decision.content) if decision[action] search: # 第二步执行检索 result registry.call( decision[tool], querydecision[search_query], top_ktop_k ) state.evidence.extend(result) state.messages.append({ role: system, content: f调用了{decision[tool]}查询{decision[search_query]}获得{len(result)}条结果 }) elif decision[action] reflect: # 第三步反思当前证据是否足够 reflection llm.invoke( _build_reflection_prompt(state.query, state.evidence) ) refl json.loads(reflection.content) state.missing_info refl[missing] if refl[sufficient]: break elif decision[action] answer: # 第四步生成最终答案 final llm.invoke( _build_answer_prompt(state.query, state.evidence) ) state.final_answer final.content break # 兜底循环结束仍未生成答案则强制生成 if not state.final_answer: final llm.invoke(_build_answer_prompt(state.query, state.evidence)) state.final_answer final.content return state.final_answer这个核心循环的逻辑分四步先让LLM决定动作用哪个工具再执行检索拿到证据然后反思证据够不够、缺什么最后在证据充分时生成答案。循环的终止条件有两个一个是Agent自己判断证据足够然后break另一个是达到max_iterations上限由代码兜底。兜底逻辑很重要没有它你会经常看到Agent陷入死循环白白烧token。_build_decision_prompt这个函数是整个循环的灵魂它决定Agent能不能做出高质量决策我贴上我整理过的版本def _build_decision_prompt( query: str, evidence: list, tool_list_text: str, missing_info: list ) - str: return f 你是一个智能检索Agent负责通过多次检索回答用户问题。 ## 当前用户问题 {query} ## 已收集的证据 {evidence if evidence else 暂无这是第一次检索} ## 当前缺失的信息 {missing_info if missing_info else 未知先做初步检索} ## 你可以使用的工具 {tool_list_text} ## 决策要求 请根据以下情况选择动作 1. 如果还没有检索过或者缺失信息明确的话选择 search并填写 - tool: 选择哪个工具 - search_query: 本次检索的具体查询内容可以是对原始问题的改写 2. 如果已有一定证据但感觉还不够选择 reflect并输出 - sufficient: true/false - missing: 列出还缺的信息点 3. 如果已有足够证据选择 answer直接生成最终回答。 只输出一个JSON对象格式如下不要输出其他任何内容 json {{ action: search, tool: vector_search, search_query: 改写后的最优检索查询 }}### 3.3 用LangGraph把逻辑状态化 最小循环版本演示了核心逻辑但真正上线还需要更好的可观测性和控制力。LangGraph比LangChain的直链式编排更适合这个场景核心在于它把Agent的状态转移显式建模为一张图每一步的状态变化都可以被记录和回放。 python from langgraph.graph import StateGraph, END from typing import TypedDict, Literal class WorkflowState(TypedDict): query: str current_query: str evidence: list route: str iteration: int final_answer: str def route_node(state: WorkflowState): 路由节点判断问题类型决定走哪条链路 route route_classifier(state[query]) if route vector: return {route: vector} elif route keyword: return {route: keyword} else: return {route: answer} def search_node(state: WorkflowState): 检索节点根据路由结果选择工具 if state[route] vector: results vector_search(state[current_query]) else: results keyword_search(state[current_query]) return {evidence: state[evidence] results} def reflect_node(state: WorkflowState): 反思节点判断证据充分性和缺失信息 reflection reflect_chain.invoke({ query: state[query], evidence: state[evidence] }) if reflection[sufficient]: return {iteration: state[iteration], final_answer: READY} return { current_query: reflection[next_query], iteration: state[iteration] 1 } def answer_node(state: WorkflowState): 答案生成节点 final answer_chain.invoke({ query: state[query], evidence: state[evidence] }) return {final_answer: final} # 构建工作流图 workflow StateGraph(WorkflowState) workflow.add_node(route, route_node) workflow.add_node(search, search_node) workflow.add_node(reflect, reflect_node) workflow.add_node(answer, answer_node) workflow.set_entry_point(route) workflow.add_edge(route, search) workflow.add_edge(search, reflect) workflow.add_conditional_edges( reflect, lambda state: answer if state[iteration] max_iterations or state[final_answer] READY else search ) workflow.add_edge(answer, END)用LangGraph写的好处有三个。第一状态转移条件conditional edge变成显式代码不会因为Agent自言自语飘了而失控。第二每一步的输入输出都落在state对象里方便记录log和做审计。第三可以直接用LangGraph的checkpoint机制持久化状态系统崩了能恢复这也是生产环境的硬需求。3.4 关键参数怎么定温度、top-k、max_iterations很多做RAG的人不太在意参数但Agentic RAG里参数影响的是行为边界不是模型性能调不好会出一堆诡异问题。温度参数要分层设置。路由和反思这类决策节点用低温0~0.2这要求确定性查询改写节点可以稍微高一点0.3~0.5让改写有一点创造空间最终答案生成节点视应用场景而定客服类问答建议0.3以下内容创作类可以放到0.7。top_k要根据知识库质量和查询类型动态调整。单跳简单问题top_k3足够多跳复杂问题时每轮检索只需要3~5条新证据即可靠多轮去累积信息量而不是指望一轮检索拿回一个大杂烩。我第一次做这个系统时把top_k设成10结果每轮都塞给反思节点一大堆重复信息泛化和冗余问题很严重。max_iterations设3~5之间。我见过不少人把这个值设成10或者20理由是让Agent有更充分的探索空间。实际上超过5轮的循环90%都是无效信息收集要么Agent在不停地换说法检索同一个东西要么它已经在错误的推理路径上越走越远。设个3~5的上限配合suffient判断尽早exit的机制反而会让Agent收敛得更快。还有一个容易被忽略的参数检索返回的chunk大小。Agentic RAG场景下Agent自己会拼接多轮证据所以单条chunk不需要太长200~300个token足够太长反而稀释信息密度、增加token消耗。这一点和普通RAG比较不同普通RAG往往希望chunk长一点保真题Agentic RAG则更看重每轮检索的信息精度。4. 常见问题与排查技巧实录4.1 Token消耗爆炸账单看不得Agentic RAG最大的槽点就是贵。有一次我做一个复杂的多跳问题系统跑了4轮检索每轮都带着全部历史证据重新调用LLM一次问答下来烧掉了几万token折算成费用吓人一跳。排查思路要先确认钱烧在哪了。用LangGraph的话给每个节点加上token计数器看每个节点消耗了多少。我实际遇到的情况是80%的token消耗在每轮都重复发送历史证据上——每次调用LLM时都把所有已收集的evidence打包送进去而evidence越长下一轮调用的prompt就越长形成指数增长的势头。解法有三个方向。第一限制evidence总量超过一定长度就截断最老的证据或者用摘要压缩旧的证据第二检索结果先做rerank再进prompt只保留最相关的片段第三把反思和路由这类决策节点换用更小的模型比如几分之一价格的轻量模型因为这些节点对推理能力的要求远低于生成节点不需要每次都上大模型。实测第三点省得最多决策节点的token量大换成小模型后整体成本能降三到五成。4.2 检索循环出不来或者来回横跳另一个高频问题Agent在几轮循环里反复执行相同或类似的检索每轮都说信息不足需要继续查找但检索词变化很小根本是在原地打转。这种问题多半由反思节点的缺什么信息判断过于模糊导致。LLM在反思时偷懒输出missing: [更多相关细节]这种空话那下一轮决策自然无从下手只能重复相近的检索词。解决办法是收紧反思节点的prompt要求它必须指出具体的、可命中的缺失信息比如缺少XX文档中关于XX配置的说明而不是缺少更多资料。代码层面还可以加去重逻辑记录每轮检索的search_query如果新的query和之前某轮的query相似度超过阈值直接强制进入answer流程不给它反复横跳的机会。这个硬规则在极端情况下的效果比任何prompt工程都可靠。4.3 中间推理引入新幻觉比传统RAG更糟这个坑最隐蔽。传统RAG的幻觉主要发生在最后生成环节Agentic RAG多了一个风险源Agent在中间推理时做出的判断本身可能就是错的。比如它把连接拒绝当成权限问题去检索后面每一步都在错误的框架里打转最终答案错得理所当然而且因为有多轮检索的证据铺垫看起来比传统RAG更可信反而更危险。应对办法是把Agent的推理过程也纳入校验范围。具体做法有两个一是在路由和检索决策时让LLM输出决策依据reason字段不只输出动作二是最终生成前加一道证据一致性校验——把每一条最终结论和它引用的文档片段做相关性打分分数低于阈值的结论直接标注为无法从证据中推断或者要求Agent重新生成。更根本的预防手段是给Agent设置领域边界。在系统提示词里明确写清楚如果你发现检索到的信息与当前问题领域明显不匹配请停止检索并告知用户这个问题可能不在知识库覆盖范围内。这个兜底约束能把Agent从错误路径上拉回来比事后修复节省大量成本。4.4 评估怎么做流程和结果分开考核很多人问我Agentic RAG用什么评估指标我给的答案是别拿传统RAG那套指标硬套。传统RAG的golden set是给定query、期望top-k命中某些文档但Agentic RAG每轮检索行为是动态的你没法也没必要预设它应该检索哪些文档。硬套的结果是你会发现系统各种表现不佳但那只是评估方式不对。我建议三层分开评估。第一层是流程健康度平均迭代轮数、工具调用分布、反思节点sufficient为true的比率、检索到answer的平均步数。这些指标反映Agent的决策效率和稳定性是最需要监控的。第二层是结果质量用答案相关的指标比如忠实度答案是否基于证据、答案相关度、信息完整性。推荐用Ragas这类工具或者人工打分结合抽样评估样本量不需要很大100条典型问题就够看出变化。第三层是成本效率每次有效回答的平均token数总token数 / 有效回答次数。这一项直接关系着你敢不敢大规模上线建议和流程健康度联动看——如果每轮迭代token都在往上走说明Agent在空转流程健康度一定有问题。我个人的经验是先把第三层的预算红线设好再优化第一层的流程指标最后才去追求第二层的答案质量。Agentic RAG是一个跑得越多才越准的系统先让它稳定高效地跑起来再谈把答案打磨得多漂亮。结尾做Agentic RAG这段时间我最大的体会是它的难点压根不在算法和模型上——那部分反而是最可以抄作业的真正磨人的是Agent的行为管理。你要在给Agent足够的自主权和确保Agent不跑偏之间反复找平衡。prompt写得松一点它就天马行空乱查一气写得紧一点它又退化成带路由的传统RAG失去了多跳推理的能力。我目前实践下来比较顺手的心态是把Agent当一名新入职的实习生把RAG工具当成他能用的工作台把反思机制当成他的日报制度。日报要写但不是为了形式而是为了能让别人随时审查他今天做了什么、为什么这么做。你可以让他自由安排工作顺序但每完成一步都需要能说清楚这一步的依据是什么。这套思路理顺了Agentic RAG离可用、可控、可信也就不远了。最后再分享一个小的落地建议别一开始就设计一个满配的Agentic RAG系统。先拿最简单的路由二次检索上线跑两周看看数据和用户反馈再逐步加查询改写、加反思机制、加信源验证。每加一个模块都要能说出它解决了哪个具体的业务问题。Agentic RAG的新颖确实吸引人但真正让它在业务里活下去的永远是看得见的效果增量和控得住的成本。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑