RAG 系列(十七):Agentic RAG——让 Agent 主导检索过程

RAG 系列(十七):Agentic RAG——让 Agent 主导检索过程 Pipeline RAG 的沉默失败前面十几篇一直在优化一件事:怎么让检索结果更好。更好的分块、更精准的排序、更聪明的问法、CRAG 纠偏、Graph RAG 关系遍历……但有一件事始终没变:无论检索结果好不好,都会被传给 LLM 生成答案。Pipeline RAG 的流程是线性的、固定的:问题 → 向量检索 → top-4 文档 → LLM 生成它没有一个步骤回头问:“这次检索到的内容,真的足以回答问题吗?”结果是什么?当知识库没有相关内容时,LLM 拿着 4 篇不相关的文档,要么生成幻觉答案,要么说"根据参考资料无法回答"。系统不知道自己失败了,只是"安静地"交出了一个错误答案。这是 Pipeline RAG 的沉默失败。Agentic RAG 的核心思想Agentic RAG 做了一件事:给系统加上能动性(agency)。具体体现在三点:1. 检索是工具,不是固定步骤向量检索、图谱遍历、网络搜索——不是"都用"或"固定用一种",而是根据问题类型动态选择。问事实问题用向量检索,问关系问题用图遍历,问时效性问题用网络搜索,问常识问题直接生成——这本来就是人类在检索时的做法。2. 检索后有反思执行检索后,Agent 不急着生成答案,而是先评估:这次拿到的上下文,对回答这个问题有多大帮助?如果分数低于阈值,就认为这次检索失败了。3. 失败可以纠正质量不够,换策略重试。向量检索没找到好内容?试试图遍历,或者直接去网上搜。这个重试循环有上限(本文是 2 次),防止无限循环。这三点合在一起,就从"固定流水线"变成了"有反馈的决策循环"。LangGraph 图结构问题 ↓ [classify] → 分析问题类型,选初始策略 事实型 → vector 关系型 → graph 时效型 → web 常识型 → direct ↓ [retrieve] → 执行选定策略(三个独立节点) ↓ [evaluate] → 打质量分(0.0~1.0),阈值 0.6 ↓ ≥0.6 ──yes──→ [generate] → 最终答案 │ no(尝试次数 2) ↓ [re_route] → 按 vector → graph → web 顺序选下一个未用过的策略 ↓ [retrieve] again... ↓ (最多 2 次后无论如何都进 generate)直接生成路径(direct_generate)绕过所有检索节点,到达 END。关键节点实现State:执行轨迹是调试的眼睛classAgenticRAGState(TypedDict):question:strstrategy:str# "vector" | "graph" | "web" | "direct"tried_strategies:list[str]# 已尝试过的策略列表,防止重复retrieved_docs:list[Document]quality_score:float# evaluate 节点打分 0.0~1.0answer:strpath:list[str]# 执行轨迹,如 ["classify→graph", "graph_retrieve", ...]path是调试利器——运行结束后可以看到每条问题走了哪条路径,哪里触发了 re-route,质量分是多少。这在分析 Agent 行为时比最终指标更有价值。classify 节点:问题分类决定策略起点CLASSIFY_PROMPT=ChatPromptTemplate.from_messages([("system","判断以下问题最适合哪种检索策略,只输出策略名,不加解释:\n\n""vector - 需要检索知识库,事实型(定义、参数、步骤、比较)\n""graph - 需要检索知识库,涉及多实体关系(来自哪里、谁开发了什么)\n""web - 需要最新信息(最新版本、近期论文、今日新闻)\n""direct - 不需要检索(常识、数学、翻译、编程语法)"),("human","问题:{question}"),])defclassify_node(state):raw=classify_chain.invoke({"question":state["qu