Agentic RAG生产级改造:从单次检索到多步智能决策的落地指南 去年聊 RAG大家还挤在“Embedding 模型选哪个、TopK 怎么设、文档怎么切”这些入门问题上。到了今年再聊问题已经悄悄变成了另一副模样同样一堆文档为什么有的系统只会“查一下就答”有的系统却会在答案不够时自动换个查法、拆出子问题、对比多份材料再下结论。这种从“单次检索”升级成“多步智能决策”的 RAG 形态就是 Agentic RAG。这篇是 Agentic RAG 系列的第 2 篇上一篇讲的是怎么把基础链路跑通这一篇直接聊生产级改造解决什么问题、零件怎么拆、代码怎么写、成本怎么控、坑怎么避。适合正在做知识库问答、智能客服、数据分析助手以及想把 RAG 从 Demo 推向真实业务的工程师和算法同学。我会把能落地的细节都写出来也把那些文档里不写的东西一并说完。1. Agentic RAG 到底改了什么三个“传统 RAG 搞不定”的场景1.1 传统 RAG 的三个硬伤先泼一盆冷水。传统 RAG 的链路看起来没问题文档切块、向量化、召回、拼接、让大模型生成答案。但只要你把它扔到真实业务里很快就会碰到三堵墙。第一堵墙是“问题拆不开”。用户真实提问往往是复合型的比如某公司内部知识库收到一个问题“华东区三季度销量掉得最狠的品类是哪个它到底是受物流影响还是受价格策略影响跟华北区比差异有多大”传统 RAG 只会拿着这句话去向量库做一次相似度检索召回的全是提到“华东”“销量”“物流”的碎片模型很难自己把问题拆成“先定位品类→再找影响因素→再做区域对比”三个步骤。结果就是答案听起来像模像样实际根本没有覆盖完整问题。第二堵墙是“一锤子买卖错了不回头”。第一次检索结果差后续没有补救机制。我见过不少系统用户在页面上怎么问都答不对但把同样的问题稍微改写一下、换个措辞再问答案就对了。这说明问题不在生成模型而在检索前面少了“探测和纠错”的环节。第三堵墙是“只会翻文档不会用工具”。业务系统里除了文档还有 SQL 数据库、时间序列接口、权限系统、内部知识图谱。传统 RAG 是文本库专用的但真实世界的答案往往要跨多个数据源才能拼出来。让一个只读文档的 RAG 去回答“按当前库存某款物料能撑几天”它做不到。这三堵墙指向同一个结论检索这件事得从“一次查询动作”升级成“一连串有策略的决策动作”。1.2 Agentic RAG 的核心循环观察、决策、行动Agentic RAG 并不是什么神秘的新架构它本质上是把大模型 Agent 的能力与检索增强结合起来。大模型不再是“收到问题直接答”而是进入一个循环观察当前状态 → 决定下一步动作 → 执行动作 → 看到结果 → 再次决定。这个循环里检索器、重排器、数据库查询、网页搜索、知识图谱查询全都被封装成可调用的“工具”。模型自己判断该调用哪个工具、按什么顺序调用、结果不够用怎么办、什么时候该停止并给出结论。打个比方。传统 RAG 像图书馆管理员你念完一句话他跑去拿一本书回来Agentic RAG 更像一个分析师他会先确认需求、把问题拆成几个子问题、分别查阅资料、发现两个材料说法矛盾时再查第三份、实在查不到就直接告诉你“这部分我还找不到可靠依据”。这种设计带来的直接收益是复杂问题可以按步骤求解检索质量差时能做二次检索并且可以跨工具组合出答案。代价则是调用次数变多、延迟变高、成本线性上涨。所以 Agentic RAG 不是把简单 RAG 完全替换掉而是应该作为一套“能上能下”的系统简单问题走快速通道复杂问题才进入多步循环。1.3 它适合谁不适合谁我做了几个项目之后总结出来一个判断标准如果你的用户问题大多是“某名词是什么意思”“某文档里怎么写的”传统 RAG 就够了别上 Agent徒增成本如果问题是“综合 A 和 B 去推断 C”“对比多个区域/多个时间段”“信息不足时需要继续追问”那传统 RAG 大概率会让你在质检环节吃尽苦头这时候再上 Agentic 改造。还有一个典型的适合场景是“工具装配型 RAG”文档只是数据来源之一旁边还有结构化数据接口和业务 API。Agent 能根据问题决定查文档还是查数据库甚至先查文档拿到实体、再拿着实体去查数据库。2. 核心零件拆解路由、改写、检索工具、反思与记忆2.1 查询侧的“前置处理”重写与路由多数人做 Agentic RAG 喜欢先把注意力放在工具调用上我反而建议先检查两条前置链路查询改写和路由。这两步决定了后续所有动作的质量。查询改写要解决的是“用户的一句话不适合直接拿去检索”。口语化的表达、指代不明的说法、跨越多种语言的混杂表达都需要先被整理成更适合检索的形式。举个例子上一轮聊了某报表下一轮用户问“那它上个月的情况呢”这里的“它”如果不做指代消解直接检索会完全跑偏。我的做法是在对话入口后挂一个改写模型输入是“历史对话摘要 当前问题”输出是“改写后的独立检索查询”。这里的工程细节是改写模型不需要用最强模型一个几十亿参数的开源模型就能做得很好关键是温度设低一点、输出格式用强约束。我给过一个模板“请把用户问题改写成适合搜索引擎和向量数据库检索的查询句只输出改写结果不输出解释。保留时间、地点、指标名等关键实体。”实测这样写比泛泛地“改写一下”效果稳定得多。路由则是下一步过滤。路由模型判断当前问题应该走哪个通道简单事实问题走“轻量单跳 RAG”、对比分析问题走“多跳检索工作流”、需要实时数据的问题走“SQL 文档混合通道”、完全跟知识库无关的闲聊走“直答通道”。路由的控制有三种常见形式让模型输出结构化 JSON、让模型调用一个专门的“选择工具”、或者用一个分类模型直接做 Softmax。我现在的项目里用的是结构化 JSON 输出因为可解释性强出了问题能直接查日志。路由的成败关键有两个。一是要给每个通道写清楚“什么时候用它、什么时候别用它”的描述最好还带上反面案例二是要设置置信度阈值比如路由模型输出“多跳检索”的概率小于 0.7 时默认回退到轻量 RAG。不然会出现糟糕的后果一个“什么是某某算法”的简单问题被路由丢进了一个要调用三四个工具的多跳流程白白花掉十几倍 token 和时间。2.2 检索侧的工具化改造不只是把向量库包一层很多人以为把向量检索封装成一个函数就叫“检索工具”这是不够的。工具化改造的关键在于让模型能够理解这个工具的能力边界、输入输出格式、以及返回结果怎么被使用。一个合格的检索工具定义至少要包含这几段工具名称、一句话说明、适用场景、不适用场景、输入参数列表、输出结构。我见过太多失败的案例工具描述只写“检索相似文档”模型根本不知道这个工具搜的是什么库、返回的是片段还是完整文档、能不能用来找结构化数据。结果模型乱调一气。检索工具内部也要做文章。我建议把重排环节放进工具内部而不是放在 Agent 外部。流程是向量召回 Top 100 → 交叉编码器重排取 Top 10 → 拼装成带“文档来源原文片段相关性分数”的结构返回给模型。这样模型看到的检索结果不是一堆裸片段而是带着旁证材料的证据块。另外我强烈建议在检索工具里做“双模式检索”。第一种是精确模式阈值高、TopK 小适合回答事实性问题第二种是探索模式阈值低、TopK 大适合回答综述型、对比型问题。Agent 可以自己根据问题类型选择调用哪一种模式这样做比单一阈值硬切效果好得多。实现也不难就是在工具参数里加一个mode字段。2.3 反思与记忆让 Agent 能自我纠错Agentic RAG 和普通 RAG 拉开差距的一个核心机制是“反思”。反思节点的职责是在 Agent 给出答案之前先拿答案跟检索到的证据做一次核对判断是否存在无中生有、证据不足、与既有事实矛盾等情况。如果发现不对Agent 可以选择重新检索、换一种检索策略、或者坦白承认无法回答。我见过的反思实现有两种建议根据你的预算选。轻量版是“生成后反思”先生成一版回答再用一个评判模型打分分数低于阈值就触发第二轮检索。重量版是“生成前反思”检索完先让模型判断“这批证据是否足以回答问题”不足就直接重新规划检索而不是先生成答案再返工。重量版效果更好但多了一次大模型调用成本也更高。记忆机制同样不可绕过。Agentic RAG 的应用场景往往有明确身份边界。这里有两层记忆要处理短期记忆记录当前问题拆出来的子任务、已经尝试过的检索路径、已经排除掉的方向避免同一个检索动作反复执行长期记忆则保留历史会话中的用户偏好、实体关系、业务规则让 Agent 在多次对话里保持一致的口径。我自己调试时遇到过最难受的死循环Agent 发现证据不足于是再次检索同一个关键词又拿到同样的结果再抱怨一次证据不足然后又检索。问题就是短记忆里没有“这个关键词已经查过了”的记录。后来我在状态里加了一个searched_queries列表每次检索前都检查一遍是否重复循环问题立刻缓解。3. 实操从基础 RAG 升级到 Agentic RAG3.1 编排框架选型为什么我推荐“状态图”思路开始动手之前先选编排框架。目前行业里做 Agentic RAG 主要有三种思路一是用表达式链把固定的检索步骤串起来这种方式适合流程永远不变的情况但这恰恰是 Agentic RAG 最不希望的二是在自定义的 ReAct 循环里手动控制工具调用灵活但状态管理混乱一旦要加子问题分支代码很快变成一坨意大利面三是状态图思路把整个流程建模成“节点 边”节点执行具体动作边根据状态跳转循环和分支都是图结构的一部分。我推荐第三种尤其在有复杂条件分支和循环需求的时候。因为可观测性最强每步停在哪个节点、状态里多了什么字段都清清楚楚。下面示例我用的是一个常见的“图编排框架”语法具体框架不同 API 有差异但逻辑是通用的定义状态 → 定义节点函数 → 连接边 → 编译执行。3.2 最小可用版本的状态设计与节点实现先定义状态。状态是整个流程的“随身笔记本”每个节点都能读写from typing import TypedDict, List, Optional class AgentState(TypedDict): question: str # 原始问题 rewritten_query: Optional[str] # 改写后的查询 route: Optional[str] # 路由结果 sub_questions: List[str] # 拆解出的子问题 search_results: List[dict] # 检索证据集合 searched_queries: List[str] # 已经查过的 query防重复 answer: Optional[str] # 最终答案 iterations: int # 循环计数 status: str # running / done / failed然后定义几个核心节点。第一个是改写节点它把原始问题和历史摘要整理成检索查询第二个是路由节点决定走哪个分支第三个是检索节点负责调用混合检索工具第四个是反思节点检查证据充分性最后是生成节点输出答案。def rewrite_node(state: AgentState) - AgentState: # 用大模型做改写示例省略 API 细节 new_query llm_rewrite(state[question], dialogue_history) state[rewritten_query] new_query return state def route_node(state: AgentState) - AgentState: route route_llm(state[rewritten_query] or state[question]) state[route] route return state def retrieve_node(state: AgentState) - AgentState: query state[rewritten_query] or state[question] if query in state[searched_queries]: # 防止重复检索 return state docs hybrid_search(query, modeexplore) state[search_results].extend(docs) state[searched_queries].append(query) state[iterations] 1 return state图构建的写法重点在于“条件边”。路由节点根据state[route]决定下一步是走轻量单跳、还是走子问题分解、还是直接回答反思节点则根据证据充分性决定是回到检索节点还是前进到生成节点from agent_workflow import StateGraph graph StateGraph(AgentState) graph.add_node(rewrite, rewrite_node) graph.add_node(route, route_node) graph.add_node(retrieve, retrieve_node) graph.add_node(reflect, reflect_node) graph.add_node(answer, answer_node) graph.set_entry_point(rewrite) graph.add_edge(rewrite, route) graph.add_conditional_edges(route, route_branch, { simple_rag: retrieve, multi_hop: decompose, direct: answer }) graph.add_conditional_edges(reflect, should_continue, { retry: retrieve, synthesize: answer }) graph.add_edge(answer, END)这里有一个很实用的约束循环必须有终止条件。我在should_continue里检查iterations 4就直接返回answer哪怕证据不足也让生成节点回退到“基于现有材料回答并标注不确定”。宁可给一个低置信度的答案不能让系统卡死在流程里。3.3 Prompt 设计才是效果上限代码框架定完之后真正拉开效果差距的是 Prompt 设计。我做了几个项目后的体会是Prompt 是 Agentic RAG 效果的上限模型和检索只是地板。每个节点都应该有自己的专用 Prompt。路由节点的 Prompt 要给出每个通道的描述、示例问题和输出格式改写节点的 Prompt 要强调“不要增删事实”反思节点的 Prompt 要引导模型检查“证据是否说了这句话、证据是否自相矛盾、证据是否只能部分支持结论”生成节点的 Prompt 要强调“只能使用检索返回的证据禁止用自己的知识补全引用必须带来源编号”。给个实用的反思 Prompt 骨架你现在是质检员。请检查以下回答是否完全被检索证据支持。 如果存在“证据不支持”“证据矛盾”“关键信息缺失”三类问题 请输出 REFLECT_AND_RETRY 并说明缺什么 如果证据足够输出 ACCEPT。 注意不确定时不强行通过。我还建议在工具描述里写明“反面触发条件”。例如检索工具描述里写“当用户问题涉及实时价格、库存、数据库联合查询时不要调用本工具应该调用 SQL 查询工具。”这比只写正面描述效果好得多模型对“什么时候不调用”的认知往往比“什么时候调用”更重要。4. 生产落地成本、延迟、评估一个都不能少4.1 成本与延迟控制Agentic RAG 最大的生产阻力不是效果而是成本和延迟。一次复杂问题的多跳流程可能要调用 5 到 10 次大模型接口再加上多次向量检索和重排。相比单次 RAG成本上浮 3 到 10 倍延迟从一秒级涨到五秒甚至十几秒。这让很多团队做完 Demo 之后卡在上线前。我的成本控制三板斧第一板斧是“路由降级”简单问题永远走轻量通道。我在线上系统里加了一个统计面板结果发现接近 60% 的问题其实是“某某是什么”“某文档第几节怎么说”这些完全不需要 Agent 循环。路由模型把它们拦下来走单跳 RAG整体成本直接砍掉一半。第二板斧是“小模型做中间步骤”。改写、路由、甚至反思都可以用轻量模型完成把最强的模型只留给最终答案生成。我试过把一个 7B 级别的模型用来做路由和改写效果跟顶级模型差异不大但成本和延迟都大幅下降。第三板斧是“缓存”。改写结果做精确缓存一模一样的问题直接跳过改写检索结果做语义缓存相近问题在短时间内复用同一批证据块。延迟优化的核心是并行化。子问题分解后多个检索任务可以并行执行上游等待时间会从“串行累加”变成“单步最大耗时”。用异步调用把三个子问题的检索并发跑整体延迟大约能下降 40% 到 60%。4.2 三层评估指标如何搭Agentic RAG 的评估不能只看“回答得好不好”太笼统。我习惯拆成三层检索质量、流程质量、生成质量。检索质量沿用传统的 RecallK、MRR、Hit Rate主要看“该召回的证据有没有被找回来”。流程质量要看工具调用有效率“调了多少次工具”“有没有重复调用”“子问题完成率”“循环收敛率”。生成质量要看事实一致性、回答相关性、引用准确性。事实一致性是 Agentic RAG 最容易爆的指标因为多跳流程中一个环节的信息被模型“自由发挥”最后生成的答案可能整体流畅但局部错误。具体做法是准备一个黄金评测集从真实用户日志里抽取种子问题手工标注正确答案和支撑证据再扩展成几百条覆盖简单/复杂/歧义/无答案四类问题的评测集。跑完一批改动后用脚本统计三层指标再人工抽检 20 条看典型案例。工具调用次数和无效检索率这类流程指标在一些开源评估组件里也能自动算但生成质量的判定我建议用“强模型 规则”双重校验不能只信单一打分模型。4.3 日志与可观测性Agentic RAG 的调试难度比传统 RAG 高一个量级因为问题可能出在任意一个环节改写改歪了、路由判错了、检索结果不行、反思没拦住幻觉。没有可观测性排查就是瞎子摸象。我要求线上系统必须记录以下几类日志每次调用大模型的输入输出和 token 数、每个工具的执行时间与返回摘要、每次循环的决策路径、以及最终答案引用的证据 ID 列表。有了这些才能快速定位一个坏案例到底是在哪一步变坏的。这里一个常被忽略的坑是光记录不行还必须把“决策路径”可视化。否则一条 8 步的执行链路靠翻 JSON 日志能把你逼疯。我现在的做法是执行完把链路整理成文本树展示“问题 → 路由结果 → 子问题A → 检索K条 → 反思结论 → 最终答案”出现问题直接看树比翻日志高效得多。5. 常见问题排查与避坑实录5.1 问题排查速查表把我在不同项目里遇到频率最高的问题整理成了一张表基本能覆盖上线初期的绝大多数状况症状常见原因处理方式Agent 反复调用同一个检索工具状态里没有记录已查过的 query反思节点反复触发同一动作在状态里维护searched_queries列表检索前检查重复简单问题被丢进复杂多跳流程路由描述不清晰或置信度阈值设置过高给路由加反面示例低置信度回退到轻量 RAG答案内容流畅但与文档矛盾反思节点只做“走流程”而没真正判断证据一致性加强反思 Prompt强制模型逐条核对证据引用延迟偶尔飙升到 15 秒以上子问题串行检索把子问题检索改成并发执行工具调用报错但 Agent 继续硬编答案工具异常没有进入状态流转给工具调用加 try/except异常时返回结构化错误信息触发重试成本一天跑下来吓人所有问题都走 Agent 全流程路由前置简单问题走单跳小模型承担中间步骤加强缓存检索结果跟问题完全不沾边改写后的 query 引入了错误实体检查改写环节输出必要时约束改写只做语句整理禁止新增内容5.2 我踩过的三个典型的坑第一个坑是工具描述写得太“教科书”。我一开始给检索工具写的是“Retrieve relevant documents based on the query”结果模型什么场景都调它把实时数据的问题也往文档库里怼。后来我把描述改成“用于从企业内部知识库中查找非结构化文本资料不适合用来查询实时库存、价格、订单状态此类数据请调用 SQL 查询工具”。效果立刻改善工具误调率降了一大截。第二个坑是“反思节点形同虚设”。一开始的反思节点只是让模型“判断是否通过”模型为了省事经常一路 ACCEPT幻觉流到用户面前才发现。后来我改成强制模型输出“支持证据列表 缺失证据列表”必须具体指出缺什么、哪个结论没有被覆盖才允许 ACCEPT。这一改质检效果明显提升但也暴露出另一个问题反思太严格导致大量问题进入重试成本和延迟上来不少。最后我加了权衡策略——只有涉及数值、对比、因果判断的问题才启用严格反思纯常识问答不启用。第三个坑是“多智能体过度设计”。我看过一些项目把检索、重排、生成、反思各拆成一个独立 Agent还搞了“Agent 之间的消息通信”。听起来很酷实际调试成本几何级上升。我的经验是Agentic RAG 优先做“单 Agent 多工具”工具之间用状态共享而不是消息通信。只有当任务边界足够清晰、比如“对话管理”和“数据查询”完全分属两个系统时才值得拆多 Agent。最后的个人体会一个 Agentic RAG 系统从能跑通到能上线中间的差距几乎全在控制控制循环次数、控制成本、控制模型自由发挥的空间、控制工具调用的边界。我个人的建议是不要一上来就做一个庞大的多智能体系统而是先把“改写→路由→检索→反思→生成”这条最小链路跑明白用日志观察每条问题到底卡在哪一步然后逐步加能力。我们团队现网稳定运行的版本核心节点不算多但每一步都有明确的进入和退出条件每个工具都有反面触发描述每条答案都能回溯到证据。做到这个程度用户感受到的就不是“模型变聪明了”而是“这个系统终于知道自己什么时候该停下来、什么时候该换个方式再试一次”。