本地 Agentic RAG:何时值得 peine
Agentic RAG 将检索的控制权交给模型:由它决定检索什么,阅读检索到的内容,并在缺少信息时再次发起查询。这个循环是有代价的,尤其是在本地机器上,每一轮都要付出生成时间。本指南将说明它与经典 RAG 相比有哪些变化、哪些情况下值得承担这笔额外开销,并给出一个使用 Ollama 提供模型服务并结合 LangGraph 的完整示例。
#Agentic RAG 概览
传统 RAG 遵循固定路径:问题触发一次检索,检索到的段落进入提示词,然后由模型作答。Agentic RAG 则用循环取代了这条路径。模型拥有检索工具,并自行决定是否调用、使用什么查询以及调用多少次,直到它判断自己可以作答或应当放弃为止。
微软的 AI Agents for Beginners 课程将其描述为这样一种运行方式:模型规划后续步骤,同时从外部来源获取信息,并采用“maker-checker”式循环:生成、检查、修正。该课程同时指出了这种自主性的边界:它只在你提供的任务和工具范围内发挥作用。
实际结论可以用一句话概括。如果你的 RAG 失败是因为单次检索无法汇集完整答案,循环可能会有帮助。如果失败是因为数据摄取或分块质量差,循环只会以更慢的速度重复同样的问题。
#Agentic RAG 与单次检索 RAG:两者的区别
借助我们的经验和引导式路径,搭建你的本地 RAG,用你自己的文档工作。
- 在线空间,终身可用
- PDF + 文件
- 30 天内退款
基础组件保持不变:embedding、向量数据库、生成模型。如果您还不熟悉这些组件,请先阅读本地 RAG 入门介绍。变化在于由谁决定执行流程。在经典 RAG 中,决定者是您的代码;在智能体式 RAG 中,决定者是模型,但要受代码为其设定的限制约束。
- 查询
- 经典 RAG:使用用户的问题,有时会改写一次。智能体式:模型自行编写查询,并可将一个问题分解为多个查询。
- 检索次数
- 经典 RAG:一次,事先已知。智能体式:因问题而异,受您设定的上限约束。
- 来源
- 传统 RAG:通常只有一个索引。智能体式:可使用多种工具(向量索引、关键词检索、SQL 数据库),由模型在其中进行选择。
- 结果把控
- 经典 RAG:没有,模型根据收到的内容撰写回答。智能体式 RAG:模型可以判断段落不足并重新检索,但这并不是保证:这一判断本身也可能出错。
- 对模型的要求
- 经典 RAG:任何能根据摘录内容撰写回答的模型。智能体式 RAG:能正确处理工具调用的模型。
- 可预测性
- 经典 RAG:响应时间相当稳定。智能体式 RAG:耗时不固定,执行路径需要通过运行轨迹来检查。
这个循环由三种机制组成。规划:将问题分解为子问题。工具使用:将每个子问题转化为一次调用。重新发起:读取结果,并决定是改写查询还是得出结论。关于智能体的整体架构(记忆、安全护栏、监控),请参阅专门的指南:这里我们只关注检索循环。
还有一种常被忽略的中间方案:固定步骤流水线。查询改写、混合检索和 reranker 始终按相同顺序执行,无需模型做出决策。这不属于智能体式方案,而且通常是应当首先尝试的做法。
#何时值得使用 Agentic RAG
正确的判断标准在于您的问题形式,而不是期望达到的复杂程度。请查看现有 RAG 的实际失败案例,然后对其进行分类。
- 多跳问题
- 第一次检索的结果决定第二次检索:先找到某份合同的供应商,再找到适用于该供应商的条款。
- 跨文档比较
- “比较合同 A 和合同 B 的通知期”需要两次独立的检索。仅一次查询可能会返回同一份合同中的五个段落。
- 多个不同性质的数据源
- 一个数字存放在 SQL 数据库中,而相关说明存放在 PDF 里。模型根据问题选择工具,正如 Microsoft 课程中针对复杂数据库交互所描述的那样。
- 对等待的容忍度
- 文献检索、资料准备、后台处理:只要结果会经过复核,多花几十秒不会对任何人造成困扰。
- 速度方面的优先修正
- 当不完整的回答代价高昂时,增加一个验证步骤是合理的,但前提是对具有约束力的决策保留人工复核。
反之,在以下情况下请继续使用简单 RAG:
- FAQ 和单一来源问题
- 答案就在一个段落中:一次检索就够了,循环只会增加等待时间。
- 小型硬件上的对话助手
- 用户期望快速得到回答,而模型的运行已接近其极限。
- 未能命中正确段落的检索
- 请先修正切分、embedding 和混合检索。重新运行一次未调好的检索,只会得到另一批糟糕的结果。
- 对结构化数据进行精确计算
- 写好并测试过的 SQL 查询,比智能体临时拼凑的查询更可靠。
- 整个语料库中实体之间的多重关联
- 如果需求是大规模遍历关系,基于图的方法解决的是另一类问题:请参阅 GraphRAG 指南。
#延迟与模型方面的代价
在云端,每一轮循环都会体现在账单上;在本地,则体现在耗时和内存占用上。有三项开销值得关注。
#延迟成倍增加
进行 N 次检索时,模型需要生成 N + 1 次:每次检索前生成一次,最后再为回答生成一次。单次 RAG 只生成一次。由于提示词每轮都会变长,每次生成都要重新读取更多文本,但运行时的上下文缓存可复用的部分除外。总耗时取决于模型、量化方式和机器;请在自己的环境中实测,不要依赖笼统的数字。
#上下文很快被占满
示例计算:按每个 token 3 到 4 个字符计算,4 个 1 200 字符的段落约相当于 1 400 个 token。因此,五次检索会增加约 7 000 个 token,还不包括问题、指令和模型的思考内容。当 num_ctx 为 8192 时,余量几乎耗尽。此时 Ollama 会截断上下文,最早的结果乃至指令都可能被移出窗口,而应用程序不会明确提示这一点。
增大 num_ctx 会消耗更多内存,并拖慢后续轮次。通常更好的做法是少返回一些段落,或者先摘要其内容再重新注入。
#模型必须能撑得住循环
模型必须生成格式正确的工具调用,然后判断已读取的内容是否足够。请使用 ollama show 检查是否支持:Capabilities 部分应列出 tools。这项检查只能说明该格式受支持,并不能说明模型会做出正确决策。
- RTX 3060 12 GB 或 RTX 4070 12 GB
- Q4_K_M 量化的 7 到 9B 模型(本站参考值:7B ≈ 5 GB)可为上下文和 embedding 留出空间。这正是下文示例的起点,使用的是 qwen3.5:9b。
- RTX 4080 16 GB
- Q4_K_M 量化的 14B 模型(≈ 9 GB)可以运行,并为扩大上下文留出更充裕的余量。
- RTX 4090 24 GB 或 M4 Pro 24 至 48 GB
- 可以考虑更大的模型,例如 qwen3.8:27b(约 18 GB)。在 24 GB 的配置上,请留意扩大上下文后还剩余多少内存。
#选择编排器
编排器负责执行循环:转发工具调用、将结果返回给模型并应用各项限制。共有三种途径,全都兼容本地模型。
- 手写循环
- 围绕 Ollama 的聊天 API 及其 tools 参数,大约二十行代码即可实现。适合用来理解其机制或处理非常简单的场景。限制和运行轨迹需要你自己编写。
- LangGraph
- 循环是一张由节点和边构成的显式图,具备状态、递归上限和步骤流式输出。如果你想控制每一次状态转移,这是不错的选择。我们的示例采用的正是它。
- LlamaIndex
- 如果您的数据摄取和索引已经基于它构建,它就值得考虑:其智能体会将您的查询引擎复用为工具。
不要根据流行程度来选择。如果你的流水线已经在某个框架上运行,就继续用它。无论如何,都要锁定版本:这些库迭代很快,其预构建函数也会变化。因此,我们的示例显式编写了图,这也让循环更易读懂。
#先决条件
- Ollama
- 已安装,并在 http://localhost:11434 上监听。
- Python
- 一个较新的虚拟环境。请在安装时确认各软件包要求的版本。
- 文档
- 在 mes_documents 文件夹中放几个 Markdown 或文本文件。如果是 PDF,请沿用 ChromaDB 教程中的摄取流程。
- 内存
- 9B 模型及其上下文约需 6 GB 可用内存;如果增大 num_ctx,则需要更多。
#使用 LangGraph 和 Ollama 的 Agentic RAG 示例
该示例构建了一个智能体,它只有一个检索工具,并基于本地 ChromaDB 索引运行。示例有意保持最简,以便清楚地展示循环过程。
#第 1 步:安装模型和软件包
#第二步:为文档建立索引
按字符切分只是为了让示例保持简短。在真实语料上,请使用尊重文档结构的切分方式,以及已在您的法语文本上验证过的 embedding 模型。
#第 3 步:编写工具和循环
工具描述很重要:模型正是通过阅读它来决定是否调用工具。系统指令要求先检索再作答、拆分子问题,并在缺少信息时如实承认。
#第 4 步:查看跟踪记录
stream_mode="values" 的好处在于能显示每条消息。在看最终回答之前,请先阅读运行轨迹,并参考下面这张检查表:
- 01模型是否调用了工具?如果它直接作答,就说明没有进行检索:请强化指令或更换模型。
- 02查询语句是否有意义?对于比较类问题,理想情况下每份合同对应一条查询。如果只有一条查询且照搬整个问题,则说明没有完成问题分解。
- 03这些段落能回答问题吗?如果片段与问题无关,问题出在索引上,而不是智能体。
- 04回答是否基于检索到的片段?请在对应段落中核对每一处方括号引用。
#第 5 步:为循环设定上限
每次检索会消耗图中的两个步骤(先是智能体,然后是工具)。因此,上限为 12 时可以进行五次检索,然后生成最终回答。超出上限后,LangGraph 会抛出 GraphRecursionError 错误(langgraph.errors 模块):请在应用中捕获该错误并返回明确的提示信息,不要让用户直接面对错误堆栈。
#陷阱与故障排除
- 模型从不调用工具
- 检查 ollama show 中的 tools,改写工具描述,并尝试其他模型。不要靠写越来越长的提示词来弥补。
- 它重复执行相同的检索
- 模型在原地打转。请降低限制,并让工具在查询已执行过时返回明确的消息。
- 回答遗漏了最初的检索结果
- 这很可能是上下文被截断的迹象。请减小 n_results、切分得更细,或在内存允许的情况下增大 num_ctx。
- 回答变得非常缓慢
- 查看 ollama ps:可能有一部分模型运行在 CPU 上,或者多个模型在内存中轮流加载。同时也要统计运行轨迹中的轮次数量。
- 它什么都没找到,却仍在编造内容
- 循环并不能阻止模型捏造内容。请通过程序校验引用:每个被引用的来源都必须出现在对话的工具结果中。
- 过于强大的工具
- 读取文档的智能体也会接收文档内容,而这些内容可能带有恶意。请只给它提供只读工具,任何会修改内容的操作都要经过人工确认。
#根据您自己的问题做出决定
其他地方公布的数据基于不同的语料库、模型和参数设置。只有用你自己的数据做对比才能得出结论,而且这并不需要太多硬件。
- 01建立一组问题集选取您已知答案和来源段落的真实问题,并混合简单问题与多跳问题。请记录每个问题的类型。
- 02确定基准将它们输入您现有的 RAG,不使用智能体。记录是否检索到了正确的段落、回答是否正确,以及总耗时。
- 03只改动一项在同一台机器上,使用相同的索引和模型,让智能体运行同一组测试。
- 04按问题类型阅读请分别查看简单问题和复杂问题的结果,并记录每个问题的检索次数。整体平均值可能会掩盖这样的情况:一类问题有所改善,另一类问题却白白耗费时间。
- 05保留确有必要的部分如果只有部分问题能从中受益,做一层路由可能就够了:默认使用直接 RAG,被判定为复杂的问题再走循环。
如需自动完成这项对比中的质量评估部分,可参阅 Ragas 专题指南,其中介绍了适用的指标。另外,请记录软件包版本、模型、量化方式和 num_ctx:否则下个月你的结果将无法比较。
#深入了解
Agentic RAG 建立在已经正常运行的 RAG 之上。这些指南涵盖需要首先稳定的基础、相邻方案以及智能体架构。
有反馈、发现了错误,或想补充说明?请告诉我们,让这份指南对每个人都更有帮助。