Agent知识库集成:RAG调用最佳实践指南
摘要
RAG 与 Agent 融合:超越“给 LLM 挂个搜索引擎”的旧思路 多数从业者对 RAG 的初步认知,常
RAG 与 Agent 融合:超越“给 LLM 挂个搜索引擎”的旧思路
多数从业者对 RAG 的初步认知,常常停留在这个简化流程:用户提问 → 自动检索知识库 → 将结果注入 Prompt → 由大模型生成响应。

这个模式在学术上称为 Pipeline RAG。它在很多场景下确实管用,但其致命缺陷在于:它缺乏自主判断力。
Pipeline RAG 面对任何问题都会执行检索操作,无论是“WonderBot 订阅的价格是多少”(此类问题确实需要依赖知识库),还是“Python 列表平均值怎么计算”(这类通用编程知识 LLM 自身就能处理)。你可以把它理解为一位只会单一技能的工人:不管接到什么任务,第一反应永远是冲向仓库。
Agentic RAG 的核心突破恰恰在于:让 Agent 自主决策何时需要检索、检索的具体内容,以及评估返回结果是否满足生成需求。
本文聚焦三大核心机制展开深度剖析:
- 检索决策:当前问题是否真的需要外部知识库支持?
- 多知识库路由:若需检索,应精准定位到哪个专用库?
- 质量门控 + Fallback:检索结果质量达标吗?若不达标,如何兜底处理?
Pipeline RAG vs Agentic RAG:架构层面的本质分野
先直观对比两种架构的设计思想:
Pipeline RAG(每次必检索):
用户问题
↓
向量检索(不问类型,一律执行)
↓
结果注入 Prompt
↓
LLM 生成
Agentic RAG(智能决策):
用户问题
↓
[决策节点] 当前问题是否需要检索?
├─ 不需要 → LLM 直接回答(适用于常识、数学运算、通用编程等)
└─ 需要 → 选择哪个知识库?
├─ product_kb(产品功能/定价)
├─ ops_kb(部署/运维/监控)
└─ faq_kb(账号管理/退款/发票)
↓
检索质量满足阈值吗?
├─ 满足 → LLM 生成
└─ 不满足 → 重写查询 → 重新检索(最多尝试 2 次)→ LLM 生成
两者最核心的区别在于:此架构中 LLM 扮演的是决策中枢,而非末端文本生成器。
Demo 1: Pipeline RAG vs Agentic RAG 核心差异对比
我们设计 5 个测试问题:其中 3 个必须依赖知识库,另外 2 个分别属于通用常识和数学计算,无需检索。
Pipeline RAG 实现
def pipeline_rag(question: str) -> dict:
"""Pipeline RAG:检索→注入→生成,强制执行检索步骤"""
docs = unified_retriever.invoke(question)
context = "n".join(d.page_content for d in docs)
answer = _ask(
f"基于以下参考资料回答问题,若资料与问题无关请严格依据资料内容作答。n参考:{context}",
question,
)
return {"answer": answer, "retrieved": True, "docs": len(docs)}
请注意 Prompt 中“若资料与问题无关请严格依据资料内容作答”这条指令——当知识库内容与问题完全无关时,LLM 的表现会陷入两难:要么生硬地将不相关内容混杂进回答,要么输出“根据参考资料,无法回答该问题”这类无意义响应。
Agentic RAG 实现
def agentic_rag(question: str) -> dict:
"""Agentic RAG:先决策,再选择性检索"""
# Step 1:Agent 自主判断是否需要检索
decision = _ask(
"判断以下问题是否需要通过知识库检索才能回答。n"
"需要检索的典型场景:产品定价/功能规格、运维操作指南、用户服务政策n"
"无需检索的场景:常识类问题、数学计算、通用编程知识n"
"仅输出 yes 或 no",
f"问题:{question}",
).strip().lower()
if "yes" not in decision:
answer = _ask("你是一个知识渊博的助手,请直接回答问题。", question)
return {"answer": answer, "retrieved": False, "docs": 0}
else:
docs = unified_retriever.invoke(question)
context = "n".join(d.page_content for d in docs)
answer = _ask(f"基于以下参考资料回答问题。n参考:{context}", question)
return {"answer": answer, "retrieved": True, "docs": len(docs)}
实测对比结果
5 个问题的实际运行数据如下:
问题类型 | Pipeline 检索 | Agentic 检索 | 问题
─────────────────────────────────────────────────────────────────
产品功能 | (3条) | (3条) | WonderBot Pro 基础版每月 API 调用次数是多少?
运维操作 | (3条) | (3条) | 部署 WonderBot 服务的最低内存要求是多少?
用户服务 | (3条) | (3条) | 购买 30 天后是否支持退款?
通用常识 | (3条) | 跳过 | 如何在 Python 中计算列表的平均值?
数学计算 | (3条) | 跳过 | 1024 除以 32 等于多少?
Pipeline RAG 对全部 5 个问题均执行了检索——即便是“1024 除以 32 等于多少”这种即使获取知识库内容也毫无价值的查询。而 Agentic RAG 则准确识别了通用常识和数学问题,直接跳过了检索流程。
不是所有问题都需要“跑一趟数据仓库”——这个看似调侃的说法,精准揭示了问题的本质。
Demo 2: 多知识库路由
企业真实环境中,知识库通常不止一个:产品文档、运维手册、用户 FAQ 等不同领域的数据,需要被路由到对应的存储源进行查询。
三个独立知识库
PRODUCT_DOCS = [
Document(page_content="WonderBot Pro 订阅价格:基础版 ¥99/月,专业版 ¥299/月,企业版需联系销售报价。"),
Document(page_content="API 调用限额:基础版 10K次/月,专业版 100K次/月,超出部分按 ¥0.01/次计费。"),
Document(page_content="WonderBot Pro 支持 GPT-4、Claude 3、Gemini Pro、GLM-4,可在控制台自行切换。"),
Document(page_content="数据安全:对话数据存储于中国区服务器,通过等保三级认证,支持加密导出。"),
]
OPS_DOCS = [
Document(page_content="部署要求:Docker 20+,内存 ≥ 8GB,CPU ≥ 4核,推荐使用 docker-compose up --build。"),
Document(page_content="故障排查:服务无响应→执行 docker ps 检查;API 超时→检查 LLM 连通性;内存溢出→调高内存 limit。"),
Document(page_content="备份策略:每日凌晨 2 点自动备份,保留 30 天,通过 restore.sh 脚本恢复。"),
Document(page_content="监控告警:CPU > 80% 持续 5 分钟触发告警;内存 > 90% 触发告警;API 错误率 > 5% 触发告警。"),
]
FAQ_DOCS = [
Document(page_content="重置密码:登录页点击'忘记密码'→输入注册邮箱→查收重置邮件→设置新密码。"),
Document(page_content="退款政策:7 天内全额退款,7-30 天按比例退还,30 天后不予退款。"),
Document(page_content="申请开票:在'账单中心'点击'申请发票',3-5 个工作日内开出电子发票并发送至邮箱。"),
Document(page_content="API Key 管理:在'开发者设置'中创建/撤销,每账号最多可创建 5 个。"),
]
LangGraph 路由实现
class RoutingState(TypedDict):
question: str
kb_choice: str # 取值:"product" | "ops" | "faq"
context: str
answer: str
path: list
def route_node(state: RoutingState) -> RoutingState:
"""Step 1:LLM 判断应查询哪个知识库"""
decision = _ask(
"根据问题内容,判断应查询哪个知识库,仅输出知识库名称:n"
"product - 涉及产品功能、价格、技术规格、支持的模型类型n"
"ops - 涉及部署、运维、故障排查、监控告警、备份恢复n"
"faq - 涉及账号密码、退款、开票、API Key 等用户服务",
f"问题:{state['question']}",
).strip().lower()
...
该图结构极为简洁:
route → retrieve → generate
route_node 的输出将直接决定 retrieve_node 调用哪个专用检索器。
实测路由准确率
针对 6 个测试问题(每个知识库 2 个)的实际运行结果:
预期KB | 实际路由 | 匹配 | 问题
─────────────────────────────────────────────────────────────
应查 product | product | ✓ | 专业版每月订阅费是多少?支持哪些大模型?
应查 product | ops | ✗ | 数据存储在哪里,通过了何种安全认证?
应查 ops | ops | ✓ | 服务 API 超时如何排查?
应查 ops | ops | ✓ | CPU 超过 80% 会触发什么告警?
应查 faq | faq | ✓ | 我购买 15 天,还能退多少款?
应查 faq | ops | ✗ | 如何为公司在税务局开具增值税发票?
路由准确率:4/6 = 67%
两个异常案例极具分析价值:
- "数据存储在哪里" → 被路由至 ops(预期为 product):LLM 误将“数据存储”归为运维范畴,这种语义歧义在单句路由判断中极易发生。
- "如何为公司在税务局开具增值税发票" → 被路由至 ops(预期为 faq):发片类问题提及“公司”,LLM 便将其与企业运维关联,导致错误分类。
67% 的准确率揭示了一个关键事实:依赖 LLM 进行路由判断虽可行,但对存在歧义的问题必须辅以增强手段。生产环境中常用的优化策略如下:
# 优化方案:在路由 Prompt 中增加带标注的示例
route_prompt = """
判断应查询哪个知识库:
product:产品定价/功能/模型支持/数据安全认证
ops:服务部署/故障排查/监控/备份恢复
faq:账号密码/退款/开票/API Key/用户账单
带标注示例:
"支持哪些大模型" → product
"开发票" → faq ← 发票相关均属用户服务范畴
"数据存储安全" → product ← 数据安全属于产品特性描述
问题:{question}
"""
完整示例的实际回答
以“API 超时了怎么排查?”为例,系统路由至 ops 知识库,检索后生成:
路由到:ops_kb
回答:API 超时,可按以下步骤排查:
1. 检查 LLM(语言模型)的连通性,确保网络连接正常。
2. 查看 Docker 运行状态,使用 docker ps 命令确认服务是否正常启动。
3. 若由内存溢出导致,可尝试提高 Docker 的内存限制。
知识库命中准确,回答直接引用了 ops 文档中的排查流程。
Demo 3: 质量门控 + 查询重写 Fallback
当检索结果的质量不达标时,与其直接输出低质内容,不如先优化问题表述,再重新尝试检索。
核心流程设计
retrieve → evaluate_quality
├─ 质量评分 ≥ 0.6 → generate
└─ 质量评分 < 0.6 且重试次数 < 2 → rewrite_query → retrieve(重新循环)
LangGraph 实现
QUALITY_THRESHOLD = 0.6
MAX_RETRIES = 2
class QualityGateState(TypedDict):
question: str
rewritten_q: str # 经过重写的查询(初始值等于原始问题)
context: str
quality_score: float
answer: str
attempts: int
path: list
def qg_evaluate_node(state: QualityGateState) -> QualityGateState:
"""让 LLM 评估检索内容与问题的相关度"""
score = _score_quality(state["question"], state["context"])
return {**state, "quality_score": score, ...}
def qg_rewrite_node(state: QualityGateState) -> QualityGateState:
"""将模糊问题改写为更精确的检索语句"""
rewritten = _ask(
"将以下模糊问题改写为更具体的检索查询,保留原意但增加关键限定词,仅输出改写后的问题:",
state["question"],
).strip()
return {**state, "rewritten_q": rewritten, "attempts": state["attempts"] + 1}
def should_rewrite(state: QualityGateState) -> str:
if state["quality_score"] >= QUALITY_THRESHOLD:
return "generate" # 质量达标,直接生成
if state["attempts"] >= MAX_RETRIES:
return "generate" # 已达重试上限,兜底生成
return "rewrite" # 质量不足,执行查询重写
实测结果
使用三个极度模糊的问题进行测试:
原始问题 | 重试次数 | 最终质量 | 执行路径
─────────────────────────────────────────────────────────────────────
价钱怎么样 | 2 | 0.00 | retrieve → evaluate(0.50) → rewrite → retrieve → evaluate(0.00) → rewrite → retrieve → evaluate(0.00) → generate
出问题了怎么办 | 2 | 0.50 | retrieve → evaluate(0.50) → rewrite → retrieve → evaluate(0.50) → rewrite → retrieve → evaluate(0.50) → generate
钱的事 | 2 | 0.50 | retrieve → evaluate(0.50) → rewrite → retrieve → evaluate(0.50) → rewrite → retrieve → evaluate(0.50) → generate
详细追踪“价钱怎么样”的处理过程:
原始问题: "价钱怎么样"
↓ retrieve → 检索到备份/部署/退款相关内容(不相关)
↓ evaluate → 质量分 0.50(LLM 判定为略微相关)
↓ rewrite → "商品价格范围查询"(重写导致概念泛化)
↓ retrieve → 检索结果质量下降
↓ evaluate → 质量分 0.00
↓ rewrite → "商品价格范围查询"(重写无实质改善)
↓ generate → 输出兜底回答
最终回答:根据您提供的参考资料,未包含价格相关信息。
如需了解价格,建议直接联系服务提供商或访问官方网站。
此结果具有重要的教学意义:查询重写并非万能工具。对于“价钱怎么样”这类极度模糊的问题,LLM 重写后生成“商品价格范围查询”,反而丢失了特定产品上下文,质量未获任何改善。
更优的解决方案是在质量评估前增加一个意图澄清节点:
# 优化方案:质量持续偏低时,引导用户提供上下文
if state["attempts"] >= MAX_RETRIES and state["quality_score"] < 0.3:
return "clarify" # 新增节点:反问用户“您想查询哪个产品/服务的价格?”
这正是 Agentic RAG 在真实落地中面临的典型困境——检索质量不佳不一定是策略问题,有时根源在于问题本身信息量不足。
Agentic RAG 设计清单
设计一套 Agentic RAG 系统时,务必重点审视以下核心决策点:
检索决策层
- 清晰界定需要检索的问题类型(业务专属知识 vs 通用常识)
- 在 LLM 判断 Prompt 中提供具体边界示例,降低歧义
- 设置
skip_retrieval类别:纯数学/代码语法/常识问题直接走 LLM
知识库路由层
- 为每个知识库编写清晰描述(类型定位 + 典型问题 + 边界案例)
- 路由准确率低于 80% 时,考虑引入 Few-shot 示例或专用分类模型
- 支持跨知识库检索(当问题涉及多个领域时,合并多库结果)
质量门控层
- 设定合理的质量阈值(0.6 是良好起点,可按业务场景调整)
- 限制最大重试次数(建议 2 次,避免陷入死循环)
- 记录每次重写后的查询语句和质量评分(用于后续数据优化迭代)
- 质量持续偏低时触发澄清机制(主动追问用户),而非硬性生成
生产优化
- 在 LangGraph 的路由 Prompt 中加入领域专属示例
- 考虑采用专用 embedding 模型 + BM25 混合检索策略,提升基础检索质量
- 记录被跳过检索的问题以及触发重写的问题,用于效果评估与持续迭代
本篇小结
几个核心结论:
- Pipeline RAG 的症结不在于检索本身,而在于缺乏思考:对所有问题一刀切执行检索,既浪费计算资源,又可能因不相关内容干扰回答质量。
- Agentic RAG 的本质是 LLM 担任调度中枢:检索、路由、评估均由 LLM 自主决策,而非遵循固定流程。
- 多知识库路由的真实准确率并非完美无缺:67% 的准确率表明,仅靠一段 Prompt 进行路由存在明显局限,生产环境需借助 Few-shot 或专用分类模型提升性能。
- 质量门控 + 重写机制并非银弹:对于极度模糊的问题,重写有时反而导致查询泛化,根本解法是在必要节点向用户澄清意图。
- LangGraph 的图结构为 Agentic RAG 提供了极佳的扩展性:新增知识库只需添加一个节点并调整路由 Prompt,无需改动整体架构。
下一篇将探讨上下文工程——Token 预算管理、动态上下文组装策略,以及如何在 128K 上下文窗口中将每个 Token 的价值发挥到极致。
参考资料
- LangGraph Agentic RAG 官方示例
- LangChain RAG 概念指南
- CRAG 论文(Corrective RAG)
- 本系列完整代码仓库:agent-06-agentic-rag
来源:互联网
本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。