RAG + Agent 架构模式:检索、推理与执行如何分工
从一次失败的知识问答说起
我在做一个内部运维助手时踩过一个典型的坑:产品希望用户问「上个月订单系统的 P99 延迟是多少,如果超过 500ms 就帮我拉一个工单」。我把这句话直接丢给 RAG pipeline,结果它只回答了延迟数值——因为 RAG 的职责到「找到知识、生成回答」就结束了,后面的「拉工单」根本不在它的能力范围内。
这个场景暴露了一个根本问题:RAG 和 Agent 解决的是不同层面的事情。RAG 负责让模型看到正确的知识,Agent 负责让模型规划步骤、调用工具、推进任务。两者可以组合,但不能混为一谈。
后来我又遇到一个更隐蔽的问题:一个客户支持系统,用户问「我的退款为什么还没到账」,RAG 检索到了退款政策文档,生成了一段漂亮的解释。但用户需要的不是政策说明,而是有人帮他查一下退款卡在哪一步。这个问题本质上需要 Agent——先查订单状态,再查支付流水,如果发现异常就触发工单流程。把这类任务当成纯知识问答处理,答案再流畅也解决不了问题。
2025 年 arXiv 上一篇 Agentic RAG 综述(Singh et al.)把这类系统的演化分成三个阶段:朴素 RAG、高级 RAG、Agentic RAG。核心区别在于,检索是否还是一个固定的「一次取一次答」流程,还是变成了一个可以由 Agent 动态控制的多步推理环节。本文将从理论到工程,把 RAG 和 Agent 的分工边界讲清楚。
理论基础:检索与执行的分层
RAG 的本质
RAG 的核心思路并不复杂——在模型生成回答之前,先从外部知识库检索相关片段,拼到 prompt 里作为上下文。Lewis et al.(2020)在原始论文中把它定义为「retrieval-augmented generation」,重点解决模型知识过时和幻觉问题。
一条标准的 RAG pipeline 包含四个环节:
- 索引:文档切块 → 向量化 → 存入向量库
- 检索:用户 query 向量化 → 相似度搜索 → 取 top-k
- 增强:检索片段拼入 prompt
- 生成:LLM 基于上下文生成回答
这套流程对知识问答类任务足够用。但它的局限也很明显:检索只做一次,query 不做改写,结果不做验证,更谈不上执行动作。
一个常见的误解是把 RAG 当成万能药。实际上,RAG 的质量上限取决于检索质量——如果向量库里的 chunk 切分不合理、embedding 模型对领域术语不敏感、或者文档本身有权限隔离没处理好,再强的 LLM 也救不回来。我在实际项目中见过不少团队把精力花在换更强的模型上,而该解决的是 chunk 策略和权限过滤。
Agent 的本质
Agent 的核心是「感知-规划-行动」循环。模型不再只是回答问题,而是拿到一个目标之后,自己拆解步骤、选择工具、执行操作、观察结果、决定下一步。
学界常用的框架是 ReAct(Yao et al., 2022):Thought → Action → Observation 交替进行,直到 Agent 认为信息充足后输出最终答案。
Agent 需要三个基础能力:
- 规划:把复杂目标拆成可执行的子任务
- 工具使用:调用搜索、计算、API、数据库等外部能力
- 记忆:短期记忆存当前对话上下文,长期记忆存历史经验
规划能力是最难做好的部分。简单的 Agent 可以用 chain-of-thought 让模型一步步推理,但遇到复杂的多步任务,往往需要更结构化的规划方法——比如先生成完整的执行计划,再逐步执行,执行过程中根据中间结果调整计划。这就是 Planning 和 Re-planning 的区别。
两层合在一起
当 RAG 和 Agent 组合时,它们的关系是这样的:
- RAG 是 Agent 可以调用的一种工具(检索工具)
- Agent 是 RAG pipeline 的控制层(决定什么时候检索、检索什么、检索几次、结果够不够好)
2026 年的主流架构共识是:RAG 层负责权限过滤、召回、重排和引用溯源;Agent 层负责目标拆解、工具选择、状态推进和失败处理。不要让 Agent 绕过 RAG 的权限控制直接读所有知识库,也不要把需要多步执行的任务硬塞进单次检索。
三种常见架构模式
模式一:先检索后回答(Classic RAG)
最基础的形态。用户提问 → 检索一次 → LLM 生成回答。适合 FAQ、文档问答、知识库查询。
# Classic RAG:一次检索,一次生成
def classic_rag(query: str) -> str:
chunks = retriever.search(query, top_k=5)
context = "\n".join(c.text for c in chunks)
return llm.generate(
system="根据以下上下文回答用户问题,如果上下文无法回答请说明。",
user=f"上下文:\n{context}\n\n问题:{query}"
)这个模式的问题是:如果用户的问题涉及多个文档,或者需要计算、对比、汇总,单次检索很难覆盖所有信息。
我在一个产品手册问答系统里验证过这一点。用户问「A 产品和 B 产品在权限管理上有什么区别」,Classic RAG 经常只检索到 A 产品的文档,因为向量相似度搜索倾向于返回语义最接近的少数几个 chunk,而不是覆盖两个对比对象的所有相关内容。
模式二:先检索后推理(Agentic RAG)
Agent 先拿到检索结果,判断信息够不够。不够就改写 query 再检索,或者调用其他工具补充。循环直到信息充足才生成最终答案。
# Agentic RAG:多轮检索 + 自主判断
def agentic_rag(query: str, max_hops: int = 3) -> str:
state = {"question": query, "evidence": [], "hops": 0}
while state["hops"] < max_hops:
# Agent 决策:继续检索还是直接回答
decision = agent.decide(state)
if decision.action == "answer":
return agent.answer(state)
if decision.action == "retrieve":
chunks = retriever.search(decision.query, top_k=5)
state["evidence"].extend(chunks)
state["hops"] += 1
elif decision.action == "call_tool":
result = tools.execute(decision.tool, decision.params)
state["evidence"].append(result)
state["hops"] += 1
# 超过最大轮次,用已有信息尽力回答
return agent.answer(state)IBM 在 2025 年的技术报告中把这种模式叫做「self-corrective RAG」——Agent 能自我评估检索质量,发现结果不相关就重新检索,发现信息有矛盾就交叉验证。
Weaviate 的技术博客把这种架构叫做「Agentic RAG」,强调 Agent 对检索流程的控制权。核心区别是:Classic RAG 的检索是确定性流程(固定 query、固定 top-k、固定一轮),Agentic RAG 的检索是动态流程(Agent 决定何时停、何时继续、何时换策略)。
模式三:多 Agent 协作检索(Multi-Agent RAG)
复杂任务拆给多个专业 Agent,每个 Agent 负责一个子领域或子任务,最后由一个编排 Agent 汇总结果。
# Multi-Agent RAG:分工检索 + 汇总
def multi_agent_rag(query: str) -> str:
# 编排 Agent 拆解任务
sub_tasks = orchestrator.decompose(query)
results = {}
for task in sub_tasks:
# 根据子任务类型分配给专业 Agent
if task.domain == "internal_docs":
results[task.id] = internal_agent.execute(task)
elif task.domain == "public_web":
results[task.id] = web_agent.execute(task)
elif task.domain == "database":
results[task.id] = sql_agent.execute(task)
# 编排 Agent 汇总所有子结果
return orchestrator.synthesize(query, results)Singh et al. 的综述把多 Agent 架构分成两类:一类是主从式(一个 orchestrator 调度多个 specialist),另一类是对等式(Agent 之间互相传递消息协商)。企业场景里主从式更常见,因为可控性更好。
多 Agent 架构的核心挑战是协调成本。Agent 数量增加后,orchestrator 的 prompt 越来越长,子任务之间的依赖关系越来越复杂,出错的概率也随之上升。Dedicatted 的企业实践文章建议保持 Agent 团队精简,每个 Agent 的能力描述要足够清晰,否则 orchestrator 会分配错误。
架构流程图
下面是一个典型的 Agentic RAG 系统的完整流程:
这个图展示了三种路径的分流逻辑:简单问题走 Classic RAG,复杂知识问题走 Agentic 多轮检索,需要执行动作的问题走 Agent + Tool 路径,且执行过程中可以按需触发 RAG。
关键决策对比
RAG vs Fine-tuning vs Agent
| 维度 | RAG | Fine-tuning | Agent |
|---|---|---|---|
| 核心能力 | 让模型看到外部知识 | 让模型内化特定能力 | 让模型规划和执行多步任务 |
| 数据更新 | 改索引即可,无需重训 | 需要重新训练或 LoRA 微调 | 运行时动态获取 |
| 延迟 | 检索增加 100-300ms | 无额外延迟 | 多轮调用,延迟最高 |
| 成本 | 向量库 + 检索 API | GPU 训练成本 | 多次 LLM 调用 token 消耗 |
| 幻觉风险 | 可通过引用溯源降低 | 知识可能过拟合 | 可通过验证步骤降低 |
| 适合场景 | 知识问答、文档搜索 | 固定风格/格式、高频重复任务 | 多步推理、工具调用、流程自动化 |
| 不适合 | 需要执行动作的任务 | 知识频繁变化的场景 | 简单 FAQ(杀鸡用牛刀) |
四种 RAG 架构模式对比
| 模式 | 检索次数 | 是否需要 Agent | 延迟 | 适合问题类型 | 典型场景 |
|---|---|---|---|---|---|
| Classic RAG | 1 次 | 否 | 低 | 单文档事实问答 | FAQ、产品手册查询 |
| Query Rewriting RAG | 1 次(改写后) | 可选 | 中 | 模糊/复杂 query | 用户表述不清的知识搜索 |
| Multi-hop RAG | 2-N 次(顺序) | 可选 | 中高 | 组合性问题 | 「A 的 B 的 C 是什么」 |
| Agentic RAG | 动态(Agent 控制) | 是 | 高 | 开放复杂问题 | 研究报告、故障排查 |
检索策略对比
| 策略 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| Dense Retrieval | 向量相似度搜索 | 语义匹配能力强 | 对精确关键词不敏感 | 概念性、描述性问题 |
| BM25 关键词检索 | 词频统计 | 精确匹配、速度快 | 不理解语义 | 产品编号、人名、专有名词 |
| Hybrid (BM25 + Dense) | 两路结果融合 (RRF) | 兼顾语义和精确匹配 | 需要调融合权重 | 2026 年的生产默认选项 |
| Hybrid + Reranker | 检索后用交叉编码器重排 | 精度最高 | 增加约 50ms 延迟 | 对准确率要求高的场景 |
| Graph RAG | 实体关系图遍历 | 擅长跨文档全局问题 | 构建图成本高 | 主题综述、知识图谱查询 |
工具执行与知识检索的协作方式
| 协作方式 | 描述 | 优点 | 风险 |
|---|---|---|---|
| 检索 → 生成 | 先查知识再生成,不涉及工具 | 简单可控 | 无法执行动作 |
| 检索 → 规划 → 执行 | RAG 提供背景,Agent 规划后调用工具 | 知识驱动决策 | 规划可能出错 |
| 执行 → 检索 → 继续执行 | 工具执行中发现需要知识,临时检索 | 按需获取,减少冗余检索 | 中断执行流 |
| 生成 → 验证 → 检索 | 先生成答案,再检索验证引用 | 减少幻觉 | 验证失败需要回退 |
工程实现要点
查询预处理
Agent 在检索之前先理解 query,这一步对召回率影响很大。
用户输入往往是模糊的、口语化的,直接拿去做向量检索效果很差。查询预处理的目标是把用户的原始输入转化成更适合检索的形式。常见的策略有三种:HyDE(让模型先生成一个假设性答案,用这个答案去检索)、Step-back(把具体问题抽象化,检索更宽泛的知识)、Decomposition(把组合问题拆成多个子查询分别检索)。
# 查询预处理:意图识别 + query 改写
def preprocess_query(query: str) -> dict:
analysis = llm.generate(
system="分析用户查询的意图、领域、复杂度。",
user=query
)
result = {
"original": query,
"intent": analysis.intent, # "search" | "execute" | "mixed"
"domain": analysis.domain, # "internal" | "public" | "mixed"
"complexity": analysis.complexity # "simple" | "multi_hop" | "agentic"
}
# 如果 query 模糊,做 step-back 改写
if analysis.complexity == "ambiguous":
result["rewritten"] = step_back_rewrite(query)
# 如果是组合问题,拆分子查询
if analysis.complexity == "multi_hop":
result["sub_queries"] = decompose_query(query)
return result混合检索 + 重排序
2026 年的生产系统基本都用 hybrid retrieval 作为默认方案。
纯向量检索的问题是对精确匹配不敏感——用户搜一个产品编号、一个错误码、一个专有名词,embedding 模型很可能把它映射到语义相近但不相关的文档上。BM25 正好相反,它靠词频统计,对精确匹配很在行,但完全不理解语义。两路检索结果用 Reciprocal Rank Fusion 融合,再送 reranker 精排,是目前精度最高的方案。
Anthropic 在 2025 年的技术报告中提到,给每个 chunk 前面加一句父文档的摘要,可以把检索准确率提升 35-50%。这个技巧成本很低,值得所有 RAG 系统采用。
# 混合检索:BM25 + Dense + RRF 融合 + Reranker
def hybrid_search(query: str, top_k: int = 20) -> list[Chunk]:
# 两路并行检索
dense_results = vector_db.search(query, top_k=top_k)
bm25_results = bm25_index.search(query, top_k=top_k)
# Reciprocal Rank Fusion 融合
fused = reciprocal_rank_fusion(
[dense_results, bm25_results],
k=60
)
# 取 top-10 送 reranker 精排
candidates = sorted(fused.items(), key=lambda x: -x[1])[:10]
reranked = reranker.rerank(query, candidates)
return reranked[:5]
def reciprocal_rank_fusion(
rankings: list[list[str]],
k: int = 60
) -> dict[str, float]:
"""融合 N 个排序列表为统一分数。"""
scores: dict[str, float] = {}
for ranking in rankings:
for rank, doc_id in enumerate(ranking, start=1):
scores[doc_id] = scores.get(doc_id, 0.0) + 1.0 / (k + rank)
return scoresAgent 检索循环的终止条件
Agentic RAG 最怕的是死循环。必须设定明确的退出机制。
退出条件通常有三个:置信度达标(Agent 认为信息足够回答问题)、达到最大轮次(防止无限循环)、或者触发降级(检测到重复检索相同内容)。生产环境中,我见过因为没设 max_hops 导致 Agent 在某个模糊 query 上循环几十次、烧掉大量 token 的案例。
# 带终止条件的 Agent 检索循环
class AgenticRetriever:
def __init__(self, max_hops=3, min_confidence=0.8):
self.max_hops = max_hops
self.min_confidence = min_confidence
def search(self, query: str) -> SearchResult:
state = SearchState(query=query)
for hop in range(self.max_hops):
# 检索
chunks = hybrid_search(state.current_query)
state.add_evidence(chunks)
# Agent 评估:信息够不够?
assessment = self.agent.assess(state)
if assessment.confidence >= self.min_confidence:
return SearchResult(
answer=assessment.answer,
evidence=state.all_evidence,
hops=hop + 1,
confidence=assessment.confidence
)
if assessment.action == "rewrite_query":
state.current_query = assessment.new_query
elif assessment.action == "call_tool":
tool_result = execute_tool(assessment.tool_call)
state.add_evidence([tool_result])
# 超过最大轮次,用已有信息尽力回答
return SearchResult(
answer=self.agent.force_answer(state),
evidence=state.all_evidence,
hops=self.max_hops,
confidence=state.best_confidence,
truncated=True # 标记为未完全解决
)引用溯源
生产系统必须做到每个回答都能追溯到来源。
引用溯源不只是在回答末尾加一个「参考资料」列表。正确的做法是:在 prompt 里给每个 chunk 编号,要求模型在每个事实陈述后面标注引用编号,然后在后处理阶段验证这些编号是否真实存在于检索结果中。如果模型引用了不存在的编号,说明出现了引用幻觉,需要触发重新生成或标记警告。
这一步在生产环境中非常关键。没有引用溯源的 RAG 系统,用户无法判断回答是否可靠,出了问题也无法回溯是哪一步检索出了偏差。
# 生成时强制引用,验证时检查引用合法性
def generate_with_citation(query: str, evidence: list[Chunk]) -> Answer:
# 给每个 chunk 编号,要求模型在回答中标注引用
numbered = "\n".join(
f"[{i+1}] {c.text} (来源: {c.source}, 页码: {c.page})"
for i, c in enumerate(evidence)
)
response = llm.generate(
system=(
"根据上下文回答。每个事实陈述后标注引用编号,"
"格式:[1][2]。如果上下文无法支持你的回答,明确说明。"
),
user=f"上下文:\n{numbered}\n\n问题:{query}"
)
# 验证引用:模型引用的编号必须真实存在于证据中
cited_ids = extract_citations(response.text)
valid_ids = set(range(1, len(evidence) + 1))
invalid = [cid for cid in cited_ids if cid not in valid_ids]
if invalid:
# 引用有幻觉,触发重新生成或标记警告
response.warning = f"无效引用编号: {invalid}"
return response生产环境检查清单
部署 RAG + Agent 系统之前,逐项检查:
- 权限隔离:RAG 层实现了文档级或租户级权限过滤,Agent 无法绕过
- 检索质量基线:用标注数据集跑过 recall@k 和 MRR,有明确数值
- 混合检索:同时使用向量检索和关键词检索,用 RRF 或加权融合
- Reranker:top-k 结果经过交叉编码器重排
- 最大轮次限制:Agentic loop 有 max_hops 上限,不会无限循环
- 置信度阈值:Agent 评估置信度低于阈值时,明确告知用户「不确定」而非硬答
- 引用溯源:每个回答标注信息来源,可追溯到原始文档和位置
- 超时和降级:单次请求有总超时,超时后降级到简化回答
- 日志完整:记录每轮检索的 query、返回结果、Agent 决策、工具调用参数
- 评测管线:定期跑 groundedness、answer relevance、context precision 指标
- 成本监控:跟踪每次请求的 token 消耗和检索调用次数,设告警阈值
- 人工兜底:Agent 置信度低或涉及高风险操作时,转人工审核
什么时候不需要 Agent
不是所有场景都需要引入 Agent。我的经验法则是:
只用 RAG 就够了:用户问的是知识问题,答案能从文档里找到,不需要执行动作、不需要多步推理。
需要引入 Agent:用户的请求包含动作(「帮我创建一个工单」「把这份报告发给张三」),或者需要跨多个数据源组合信息,或者需要多步计算和判断。
连 RAG 都不太需要:问题是通用的、模型本身就能回答的,加检索反而增加延迟和噪声。
RAG + Agent 最适合的场景是企业知识助手、客服流程自动化、内部运维、合规审查和复杂研究任务。不适合早期简单 FAQ,也不适合强事务一致性的核心业务操作——那种场景下,传统规则引擎或工作流系统更可靠。
参考资料
- Agentic Retrieval-Augmented Generation: A Survey on Agentic RAG — Singh et al., arXiv 2501.09136, 2025
- What is Agentic RAG? — IBM Think
- What Is Agentic RAG? From LLM RAG to AI Agents — Weaviate Blog
- Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks — Lewis et al., NeurIPS 2020
- ReAct: Synergizing Reasoning and Acting in Language Models — Yao et al., ICLR 2023
- RAG vs. Fine-tuning — IBM Think
- Agentic RAG: Architecture Patterns That Actually Work for Enterprise AI — Dedicatted, 2025
- RAG Architecture in 2026: Patterns + Eval — Future AGI