菜鸟AI - 让提示词生成更简单! 全站导航 全站导航
AI工具安装 新手教程 进阶教程 辅助资源 AI提示词 热点资讯 技术资讯 产业资讯 内容生成 模型技术 AI信息库

已有账号?

首页 > AI创作与模型 > Agent知识库集成:RAG调用最佳实践指南
模型技术

Agent知识库集成:RAG调用最佳实践指南

2026-05-29
阅读 0
热度 0
作者 菜鸟AI编辑部
摘要

摘要

RAG 与 Agent 融合:超越“给 LLM 挂个搜索引擎”的旧思路 多数从业者对 RAG 的初步认知,常

RAG 与 Agent 融合:超越“给 LLM 挂个搜索引擎”的旧思路

多数从业者对 RAG 的初步认知,常常停留在这个简化流程:用户提问 → 自动检索知识库 → 将结果注入 Prompt → 由大模型生成响应。

Agent系列(七):知识库集成——Agent 调用 RAG 的正确姿势

这个模式在学术上称为 Pipeline RAG。它在很多场景下确实管用,但其致命缺陷在于:它缺乏自主判断力

Pipeline RAG 面对任何问题都会执行检索操作,无论是“WonderBot 订阅的价格是多少”(此类问题确实需要依赖知识库),还是“Python 列表平均值怎么计算”(这类通用编程知识 LLM 自身就能处理)。你可以把它理解为一位只会单一技能的工人:不管接到什么任务,第一反应永远是冲向仓库。

Agentic RAG 的核心突破恰恰在于:让 Agent 自主决策何时需要检索、检索的具体内容,以及评估返回结果是否满足生成需求

本文聚焦三大核心机制展开深度剖析:

  1. 检索决策:当前问题是否真的需要外部知识库支持?
  2. 多知识库路由:若需检索,应精准定位到哪个专用库?
  3. 质量门控 + 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 混合检索策略,提升基础检索质量
  • 记录被跳过检索的问题以及触发重写的问题,用于效果评估与持续迭代

本篇小结

几个核心结论:

  1. Pipeline RAG 的症结不在于检索本身,而在于缺乏思考:对所有问题一刀切执行检索,既浪费计算资源,又可能因不相关内容干扰回答质量。
  2. Agentic RAG 的本质是 LLM 担任调度中枢:检索、路由、评估均由 LLM 自主决策,而非遵循固定流程。
  3. 多知识库路由的真实准确率并非完美无缺:67% 的准确率表明,仅靠一段 Prompt 进行路由存在明显局限,生产环境需借助 Few-shot 或专用分类模型提升性能。
  4. 质量门控 + 重写机制并非银弹:对于极度模糊的问题,重写有时反而导致查询泛化,根本解法是在必要节点向用户澄清意图。
  5. LangGraph 的图结构为 Agentic RAG 提供了极佳的扩展性:新增知识库只需添加一个节点并调整路由 Prompt,无需改动整体架构。

下一篇将探讨上下文工程——Token 预算管理、动态上下文组装策略,以及如何在 128K 上下文窗口中将每个 Token 的价值发挥到极致。


参考资料

  • LangGraph Agentic RAG 官方示例
  • LangChain RAG 概念指南
  • CRAG 论文(Corrective RAG)
  • 本系列完整代码仓库:agent-06-agentic-rag

来源:互联网

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

同类文章推荐

相关文章推荐

更多