Skip to content

RAG 进阶

Agentic RAG

固定 RAG 流水线解决不了多源、多跳、需要判断下一步的问题时,把检索变成 Agent 可调用的工具。

适合阶段:复杂问答与多源检索核心机制:Plan / Tool / Observe / Stop面试重点:可控性与评估

Agentic RAG 让模型决定何时查、查哪里、查几次。

面试官想考什么

读完这篇你要能正面回答下面这些题。每题后面括号里是面试官真正想看你答出什么。

Agentic RAG 和普通 RAG 最大区别是什么?考固定 pipeline 和动态 tool loop 的差异。
什么场景值得上 Agentic RAG?什么场景不该上?考工程克制,不是所有问答都需要 Agent。
Agentic RAG 的典型循环怎么设计?如何避免无限检索?考 max steps、stop condition、evidence grading。
检索工具应该怎么设计 schema?返回整段文本还是结构化证据?考工具契约和可引用性。
Agent 什么时候应该重写 query、换检索源、或者拒答?考分支控制,而不是无脑 tool calling。
Agentic RAG 怎么评估?为什么比普通 RAG 更难测?考轨迹评估、工具调用准确率和端到端质量。
Agentic RAG 和 GraphRAG、Self-RAG、ReAct 是什么关系?考概念辨析和架构分层。

为什么需要 Agentic RAG

普通 RAG 是固定流水线:

text
query -> retrieve top-K -> rerank -> generate

这个流程适合单次检索能拿到证据的问题。比如"XPay 退款接口 timeout 最大多少秒?",检索接口文档就够了。

但复杂问题经常不是一次检索能解决的:

text
XPay 退款接口 timeout 最大多少?这个限制是谁维护的?最近有没有相关投诉?

这其实是三个问题:

  • 参数范围在 API 文档里。
  • 维护团队可能在服务目录或组织文档里。
  • 投诉信息可能在工单库里。

固定 RAG 只能提前决定"查哪个库、查几次、怎么组合"。Agentic RAG 把这些动作变成工具,让模型或控制器根据中间结果决定下一步:先查 API 文档,发现实体是 XPay 退款接口,再查服务目录,最后查投诉工单;证据足够就回答,不够就继续或拒答。

LangChain 的 retrieval 文档把 Agentic RAG 描述成:LLM-powered agent decides when and how to retrieve during reasoning。LlamaIndex 的 agentic strategies 也强调,可以把已有 RAG query engine 作为工具交给 agent 做更复杂决策。重点不在更换检索算法,重点在把检索从固定组件变成可规划动作。

Agentic RAG 是怎么工作的

它实际是一个有上限的工具循环。

流程图

这个结构和 ReAct 很像。ReAct 论文 Synergizing Reasoning and Acting 讲的是模型交替生成 reasoning trace 和 actions;Toolformer 论文 Language Models Can Teach Themselves to Use Tools 讨论模型何时调用 API、传什么参数、如何使用返回结果。Agentic RAG 可以看成这些工具使用思想在检索任务上的应用。

工程上不要让 agent 自由奔跑。一个生产级 Agentic RAG 至少要有:

  • 可枚举工具列表和参数 schema
  • 每步的最大候选数和最大 token 数
  • evidence grading 和停止条件
  • max steps / max cost / timeout
  • 每步 trace、引用来源和权限过滤

核心原理 / 关键设计

1. 检索工具要小而清楚

不要给 agent 一个过宽的 search_everything(query)。工具边界越清楚,模型越容易选对。

python
TOOLS = {
    "search_api_docs": "查 API 参数、错误码、接口限制",
    "search_policy": "查员工制度、合同、权限政策",
    "search_tickets": "查近期工单、投诉、故障记录",
}

工具返回也要结构化。只返回一段长文本,后面无法做引用、去重、权限审计。

json
{
  "source": "api/xpay/refund.md",
  "section": "timeout",
  "text": "timeout 参数范围为 1-300 秒。",
  "score": 0.82,
  "updated_at": "2026-05-12"
}

这看起来像小事,但面试很容易问。Agentic RAG 的可靠性很大程度来自工具契约,而不是 prompt 写得多漂亮。

2. Planner 不应该直接生成最终答案

Agent 每一步会做两类事:选工具、读观察结果。最终答案最好由单独的 answer step 生成,并且只允许使用已收集证据。

text
bad:
Planner 一边想一边答,工具结果和模型猜测混在一起。

better:
Planner 只产出 action;
Tool 返回 evidence;
Evaluator 判断够不够;
Answerer 基于 evidence 输出答案和引用。

这样做能降低幻觉,也方便评估每个环节。LangGraph 的 Agentic RAG 教程里也把 retrieval、grade documents、rewrite、generate 拆成不同节点,本质就是为了让控制流可观察。

3. Stop condition 比多查一次更重要

Agentic RAG 最常见的故障:查了一步又一步,仍不给停止理由。

python
for step in range(max_steps):
    action = planner(state)
    observation = run_tool(action)
    state.add(observation)
    if evidence_is_enough(state):
        break
else:
    return refuse("检索次数达到上限,证据仍不足")

停止条件不能只靠"模型觉得够了"。至少要组合几类信号:是否命中必须字段、是否有来源引用、是否覆盖子问题、是否达到 max steps、是否超出成本预算。

4. Agentic RAG 更需要权限和版本控制

固定 RAG 通常只查一个库,权限过滤容易集中处理。Agentic RAG 会跨多个工具:政策库、工单库、CRM、代码库、网页搜索。只要一个工具忘了 tenant/user filter,就可能泄露数据。

text
每个工具调用必须带:
tenant_id
user_id / role
allowed_sources
document_version_policy

工具层要强制权限,不要只靠 planner 自觉。Agent 选择"查工单"时,工单检索工具必须自己做 ACL;不能让上层 prompt 说一句"不要越权"就算完。

5. Agent 轨迹本身就是评估对象

普通 RAG 可以只看输入输出和引用。Agentic RAG 还要看中间步骤:

text
用户问题 -> 选了哪些工具 -> 每个工具参数是什么 -> 返回哪些证据
-> 是否重写 query -> 是否覆盖子问题 -> 为什么停止

没有 trace,你只能看到最终错了,不知道是 planner 选错工具、query 写错、工具没返回、还是 evaluator 误判证据足够。

怎么用:标准库写一个可控 Agentic RAG loop

下面这段代码不用外部模型,演示 Agentic RAG 的控制流:工具路由、多步检索、证据检查、停止和引用。真实项目里,把 plan_next_action() 换成 LLM tool calling,把 search_* 换成真实 retriever。

python
from dataclasses import dataclass, field

API_DOCS = {
    "api-1": "XPay 退款接口 timeout 参数范围为 1-300 秒,超过 300 秒会被网关拒绝。",
    "api-2": "XPay 查询订单接口默认 timeout 为 30 秒。",
}
SERVICE_DOCS = {
    "svc-1": "XPay 退款接口由支付网关团队维护,负责人轮值在服务目录中更新。",
}
TICKETS = {
    "ticket-1": "近 7 天支付网关团队收到 12 起退款接口 timeout 超限投诉。",
}


@dataclass
class Evidence:
    source: str
    text: str


@dataclass
class State:
    question: str
    actions: list[str] = field(default_factory=list)
    evidence: list[Evidence] = field(default_factory=list)


def keyword_search(query: str, corpus: dict[str, str]) -> list[Evidence]:
    terms = [t for t in query.lower().replace("?", " ").split() if len(t) > 1]
    rows = []
    for source, text in corpus.items():
        score = sum(1 for term in terms if term in text.lower())
        if score:
            rows.append((score, Evidence(source, text)))
    return [e for _, e in sorted(rows, key=lambda x: x[0], reverse=True)]


def search_api_docs(query: str) -> list[Evidence]:
    return keyword_search(query, API_DOCS)


def search_service_catalog(query: str) -> list[Evidence]:
    return keyword_search(query, SERVICE_DOCS)


def search_tickets(query: str) -> list[Evidence]:
    return keyword_search(query, TICKETS)


def plan_next_action(state: State) -> str:
    text = "\n".join(e.text for e in state.evidence)
    q = state.question.lower()

    if "api" not in state.actions and ("timeout" in q or "接口" in q):
        return "api"
    if "service" not in state.actions and ("维护" in state.question or "谁" in state.question or "团队" in state.question):
        return "service"
    if "tickets" not in state.actions and ("投诉" in state.question or "最近" in state.question):
        return "tickets"
    if "timeout 参数范围" in text and ("维护" not in state.question and "投诉" not in state.question):
        return "done"
    return "done"


def run_action(action: str, question: str) -> list[Evidence]:
    if action == "api":
        return search_api_docs(question)
    if action == "service":
        return search_service_catalog(question)
    if action == "tickets":
        return search_tickets(question)
    return []


def enough_evidence(state: State) -> bool:
    text = "\n".join(e.text for e in state.evidence)
    checks = []
    if "timeout" in state.question:
        checks.append("timeout 参数范围" in text)
    if "谁" in state.question or "维护" in state.question:
        checks.append("维护" in text and "团队" in text)
    if "投诉" in state.question or "最近" in state.question:
        checks.append("投诉" in text)
    return bool(checks) and all(checks)


def agentic_rag(question: str, max_steps: int = 4) -> State:
    state = State(question=question)
    for _ in range(max_steps):
        action = plan_next_action(state)
        if action == "done" or enough_evidence(state):
            break
        state.actions.append(action)
        state.evidence.extend(run_action(action, question))
    return state


if __name__ == "__main__":
    state = agentic_rag("XPay 退款接口 timeout 最大多少?谁维护?最近有投诉吗?")
    print("actions:", state.actions)
    for e in state.evidence:
        print(f"[{e.source}] {e.text}")

这个 demo 里,Agent 不会一次性查所有库,而是根据问题和已有证据选择下一步。生产系统要把 actions、工具参数、返回证据、停止原因全部写进 trace。

容易踩的坑

坑 1:把 Agentic RAG 用在简单 FAQ

现象:原来 300ms 的知识库问答,变成几秒,还多了不稳定工具调用。

根因:简单单跳问题不需要规划。Agent loop 增加了 LLM 调用、分支和状态。

修法:做 query classifier。单点事实问题走普通 RAG;多源、多跳、需要补查的问题才走 Agentic RAG。

坑 2:工具描述太像,模型乱选

现象:该查 API 文档时查了工单库,该查政策库时查了网页。

根因:工具边界不清,description 写成"搜索相关信息"这种泛话。模型无法根据语义区分工具。

修法:工具名和描述写具体:search_api_docssearch_hr_policysearch_recent_tickets;给参数 schema 和反例;用离线问题集测 tool selection accuracy。

坑 3:没有 max steps 和成本上限

现象:Agent 一直检索、重写、再检索,线上延迟和成本失控。

根因:没有硬停止条件,或者把停止完全交给模型判断。

修法:设置 max steps、timeout、max tokens、max tool calls;evidence grading 达标才生成;未达标就拒答或请求澄清。

坑 4:工具返回不可引用

现象:答案看起来对,但没法知道来自哪份文档;用户追问来源时系统说不清。

根因:工具只返回纯文本,丢了 source、section、page、version、score。

修法:工具返回结构化 evidence。最终回答必须引用 evidence id;没有来源的文本不能进入答案。

坑 5:跨工具权限不一致

现象:向量库做了租户过滤,工单工具却返回了别的团队数据。

根因:Agentic RAG 把多个数据源组合起来,权限模型分散在各工具里,容易漏。

修法:每个工具强制接收 auth context,并在工具内部做 ACL;trace 记录每次工具调用的 tenant/user/source filter。

与相似概念的区别

概念决策权在哪里适合什么问题主要风险
Naive RAG固定 pipeline单跳事实问答漏召回、缺自检
Advanced RAG控制流规则 + LLM 改写/评分召回失败、自检、纠错分支复杂
GraphRAG图索引和查询路由全局主题、多跳关系构图成本高
Agentic RAGAgent 动态选择工具和步骤多源、多步、需要规划不稳定、难评估、成本高
ReAct AgentThought/Action/Observation 循环通用工具使用容易循环和幻觉动作

Agentic RAG 可以包含 GraphRAG 工具,也可以包含 Advanced RAG 的 query rewrite 和 evidence grading。它更像控制层:决定用哪些检索算法、按什么顺序用、什么时候停止。

面试题深度解析

Q1: Agentic RAG 和普通 RAG 最大区别是什么?

  • 30 秒版本:普通 RAG 是固定检索生成流水线;Agentic RAG 把检索源包装成工具,由 Agent 根据问题和中间证据决定查哪里、查几次、是否重写或拒答。
  • 追问 1:这带来什么收益?能处理多源、多跳和不确定问题,比如先查 API 文档,再查服务目录,再查工单。
  • 追问 2:代价是什么?延迟、成本、可重复性和评估复杂度都上升,所以要有 max steps、trace 和工具权限控制。

Q2: 什么场景值得上 Agentic RAG?

  • 30 秒版本:问题需要多源数据、动态分解、补查、或工具选择时值得上。单库 FAQ 和简单政策问答不需要。
  • 追问 1:怎么判断?看历史失败 case:如果错误来自"查错库/少查一步/需要跟进问题",Agentic RAG 有价值;如果错误来自 chunking 或 embedding,先修基础 RAG。
  • 追问 2:怎么灰度?先用 query classifier 只让复杂问题进入 Agentic RAG,对比普通 RAG 的答案准确率、延迟和成本。

Q3: Agentic RAG 怎么避免无限检索?

  • 30 秒版本:硬上限 + 证据评分 + 停止原因。max steps、timeout、max tool calls 必须写死,不能只靠模型说"我完成了"。
  • 追问 1:证据评分怎么做?检查子问题是否都有来源、是否命中必要字段、引用是否来自允许数据源。
  • 追问 2:证据不足怎么办?拒答、请求澄清、或走受控补救分支。不要继续无限重写 query。

Q4: Agentic RAG 怎么评估?

  • 30 秒版本:评估最终答案还不够,还要评估轨迹:工具选择是否正确、参数是否正确、证据是否支持答案、是否有多余调用。
  • 追问 1:指标有哪些?tool selection accuracy、evidence recall、answer accuracy、citation precision、average tool calls、p95 latency、cost per query。
  • 追问 2:怎么 debug?保存每步 trace,并把失败归因到 planner、retriever、evaluator、answerer。没有分段归因,Agentic RAG 会变得很难诊断。

延伸阅读

  • 文档:LangChain Retrieval: Agentic RAG — 官方对 semantic search、RAG、Agentic RAG 的对比很清楚。
  • 文档:LangGraph Agentic RAG — 看 retrieval tool、grade documents、rewrite、generate 如何拆成图节点。
  • 文档:LlamaIndex Agentic Strategies — 看如何把 query engine 作为 agent tool。
  • 文档:LlamaIndex Agents — 理解 LlamaIndex 里 RAG pipeline 和 agent/tool 的关系。
  • 论文:ReAct — Agentic RAG 的行动循环可以从 ReAct 理解。
  • 论文:Toolformer — 理解模型何时调用工具、如何使用工具结果。
  • 论文:Self-RAG — 检索、生成、自我批判的训练化路线,适合和 Agentic RAG 对比。
  • 论文:Reflexion — 语言反思如何帮助 agent 从失败反馈中改进下一步。

基于 MIT 协议开源