☰
Agent时代RAG与文件系统:互补而非替代的混合检索架构
2026/10/20 5:21:36 网站建设 项目流程

1. 从一句质疑说起:RAG 到底遇到了什么麻烦

“RAG 死了吗”这句话,最近半年在技术圈里出现的频率越来越高。我第一次看到这个说法的时候,正在给一个内部知识库做检索增强生成的调优,当时的第一反应是:又来了,每隔一段时间就有人给某个技术判死刑。但冷静下来仔细想想,这句话背后其实藏着一个非常真实的困惑——当 Agent 开始具备自主规划、工具调用、多轮反思的能力之后,传统那套“先检索再生成”的固定流水线,确实显得有些笨拙了。

传统 RAG 的核心逻辑很简单:用户问一个问题,系统去向量数据库里找最相似的若干文本块,拼进提示词,然后让模型基于这些文本块生成回答。这个模式在 2023 年几乎是所有知识问答系统的标配,我也用它交付过不少项目。但问题在于,这套流程是静态的、单次的、不可回溯的。模型拿到什么材料就只能用什么材料,检索错了就一路错到底,中间没有纠错的机会。

Agent 时代的到来改变了这个前提。现在的 Agent 可以自己决定要不要检索、检索什么、检索几次、检索完觉得不够还能换个关键词再查一遍。它甚至可以直接读写文件、执行代码、调用外部接口。这就引出了一个很自然的追问:既然 Agent 这么灵活,那我直接把所有文档丢给它,让它像人一样翻文件不就行了吗?文件系统是不是就能包打一切了?

这个问题我认真想了很久,也在几个实际项目里做了对比测试。结论先放在这里:文件系统不是 RAG 的替代品,而是 RAG 的一种补充形态;Agent 也不是让 RAG 失效的原因,而是让 RAG 的检索策略需要重新设计。下面我把自己的思考过程、实测数据和踩过的坑,完整地展开聊一聊。

2. 传统 RAG 的软肋到底在哪里

2.1 向量检索的“语义相似”不等于“答案相关”

很多人对 RAG 的理解停留在“把文档切块、做 embedding、存向量库、查 top-k”这个层面。这套流程本身没问题,但它有一个被严重低估的缺陷:向量相似度衡量的是语义接近程度,而不是信息对回答的有用程度。

我举个实际遇到的例子。之前做一个设备运维知识库,用户问“泵体温度过高怎么处理”。向量检索返回的 top-5 里,有三条是“泵体温度监测方案”“温度传感器选型指南”“泵体温度异常报警阈值设定”,这些文本和问题的语义相似度极高,但它们都不是用户要的答案。真正有用的那条“泵体温度过高时先检查冷却水流量,再确认轴承润滑状态”反而排在第七位,因为它的措辞和问题的字面重叠度不高。

这就是传统 RAG 最典型的失败模式:检索器找的是“像问题的文本”,而不是“能回答问题的文本”。在 Agent 框架下,这个问题有了新的解法——Agent 可以先拿到一批候选,然后自己判断“这些材料够不够回答问题”,不够就换关键词再查,或者直接去读原始文件。但这并不意味着向量检索没用了,而是说它应该作为 Agent 的一个工具,而不是唯一的入口。

2.2 固定分块策略对结构化内容的破坏

另一个被广泛诟病的问题是分块。传统 RAG 通常把文档按固定字数切分,比如 512 个 token 一块,重叠 50 个 token。这种切法对散文类内容勉强能用,但遇到表格、代码、流程图、层级标题的时候,简直是灾难。

我试过一个极端案例:一份产品规格书,里面有一个关键参数表,表头在上一块,数据行在下一块,注释在再下一块。用户问“这个型号的最大承压是多少”,检索器把三块都召回了,但模型拼出来的上下文里,表头和数据行之间隔着一段无关的文字,导致模型把参数对应错了。这种错误在传统 RAG 里几乎无法避免,因为分块是在索引阶段就定死的,查询阶段没有机会重新组织。

Agent 时代的一个明显进步是,很多框架开始支持结构化感知的分块,或者干脆让 Agent 在需要的时候自己去读原始文件、自己解析表格。文件系统在这里扮演的角色,就是那个“原始真相的来源”。向量库是索引,文件系统是底稿,两者不是二选一的关系。

2.3 单次检索无法处理多跳问题

传统 RAG 还有一个硬伤:它假设答案存在于某一个或某几个文本块里,一次检索就能搞定。但现实中的问题往往是多跳的。比如“去年营收增长最快的产品线,它的主要负责人是谁”,你需要先查营收数据找到产品线,再查组织架构找到负责人。传统 RAG 要么把两个问题拼在一起检索(效果很差),要么分两次检索但中间结果无法传递。

Agent 的优势在这里体现得很明显:它可以先执行第一个查询,拿到结果后提取关键实体,再执行第二个查询。这个过程可以循环多次,直到收集到足够的信息。而文件系统在这个过程中,既可以作为 Agent 的“工作记忆”(把中间结果写进临时文件),也可以作为“知识来源”(直接读取原始文档)。

3. Agent 时代,文件系统为什么突然变得重要了

3.1 Agent 需要可读写的持久化记忆

Agent 和传统 RAG 系统最大的区别之一,是它需要记忆。传统 RAG 是无状态的,每次问答都是独立的。但 Agent 在执行一个复杂任务时,会产生大量的中间状态:已经查过什么、得到了什么结论、下一步计划是什么、哪些假设被推翻了。这些信息如果只放在上下文窗口里,很快就会超出长度限制。

文件系统在这里提供了一个非常自然的解决方案:把中间状态写成文件,需要的时候再读回来。这比把所有东西都塞进向量库要灵活得多,因为文件可以是任意格式——Markdown、JSON、CSV、甚至是一段临时脚本。Agent 可以自己决定写什么、写到哪里、什么时候清理。

我在一个数据分析 Agent 的项目里就是这么做的。Agent 接到任务后,先创建一个工作目录,然后把每一步的查询结果写成 JSON 文件,把中间计算写成 Python 脚本,把最终报告写成 Markdown。整个过程完全透明,出错了可以回溯,中断了可以续跑。这种“文件系统作为工作台”的模式,是传统 RAG 流水线做不到的。

3.2 文件系统提供了天然的层级和导航

向量库的一个根本问题是:它没有结构。所有文本块都是平铺的,检索只能靠相似度。但人类的知识组织方式是有层级的:目录、章节、小节、段落。文件系统天然具备这种层级结构,Agent 可以通过列目录、读文件、跳转路径的方式,像人一样“浏览”知识。

这个能力在处理大型代码库或者复杂文档集的时候特别有用。比如一个 Agent 要回答“这个项目的鉴权逻辑在哪里实现的”,它不需要把整个代码库做 embedding,而是可以先看目录结构,找到 auth 相关的目录,再进去看具体文件。这种导航式的检索,比向量检索更精准,也更容易解释。

当然,文件系统导航也有它的局限:它依赖文件名和目录名有良好的语义。如果文件命名混乱,Agent 也会迷路。所以我在实际项目中会建议团队,如果打算让 Agent 直接读文件,先把文件命名和目录结构整理好,这比调 embedding 模型参数带来的收益大得多。

3.3 文件系统让“检索”变成了“探索”

传统 RAG 的检索是一次性的:查一次,拿结果,生成。Agent 加文件系统的组合,把检索变成了一个探索过程:先看看有什么,再决定读什么,读完发现不够,再换个方向找。这个过程更接近人类解决问题的真实方式。

我做过一个对比实验:同样是回答“某设备的故障代码 E42 代表什么”,传统 RAG 的准确率大约是 62%,而 Agent 加文件系统的方案能达到 89%。差距主要来自 Agent 可以在第一次检索不理想时,主动去读故障代码手册的目录,找到对应的章节,再精读那一节。这种“先定位再精读”的策略,比一次性向量检索要稳健得多。

4. 文件系统真的能包打一切吗

4.1 文件系统的三个硬伤

说了这么多文件系统的好处,现在必须泼一盆冷水:文件系统不是万能的,它有三个绕不过去的硬伤。

第一个硬伤是规模。文件系统适合处理几十到几百个文件的项目,但当文件数量达到几万甚至几十万的时候,Agent 靠列目录和读文件的方式会变得极其低效。它不可能把每个文件都读一遍,必须依赖某种索引来缩小范围。这时候向量检索或者关键词检索仍然是必要的。

第二个硬伤是模糊匹配。文件系统是基于精确路径的,Agent 必须知道文件名或者目录名才能找到文件。但用户的问题往往是模糊的:“帮我找一下之前那个关于性能优化的讨论”。如果 Agent 不知道具体文件名,它在文件系统里就无从下手。向量检索在处理这种模糊语义查询时,仍然有明显优势。

第三个硬伤是非文本内容。文件系统里的 PDF、图片、音频、视频,Agent 不能直接“读”,需要先经过解析或者转录。这个预处理步骤在传统 RAG 里是索引阶段完成的,在 Agent 加文件系统的方案里,要么实时做(慢),要么提前做(又回到了索引的老路)。

4.2 混合架构才是现实解

所以我的结论很明确:文件系统和向量检索不是替代关系,而是互补关系。一个成熟的 Agent 知识系统,应该是这样的架构:

  • 文件系统作为底层存储:保存原始文档、中间结果、工作脚本、最终输出。
  • 向量索引作为快速入口:对文档做 embedding,支持模糊语义查询,快速缩小候选范围。
  • 关键词索引作为精确补充:支持精确匹配、布尔查询、字段过滤。
  • Agent 作为调度器:根据问题类型,决定走哪条路径,必要时组合使用。

这个架构的核心思想是:不要让 Agent 在“只有向量”和“只有文件”之间二选一,而是给它多种工具,让它自己判断。我在实际项目中就是这么做的,Agent 的提示词里会明确告诉它:如果你知道大概的文件名或者目录,直接去读文件;如果你只有一个模糊的概念,先用向量检索找候选;如果向量检索结果不理想,再回到文件系统里探索。

4.3 一个具体的决策流程

为了让大家更清楚什么时候用什么,我整理了一个简单的决策表:

场景特征推荐策略理由
问题包含明确文件名或路径直接读文件最快最准,无需索引
问题模糊,只有语义描述向量检索文件系统无法处理模糊匹配
需要多跳推理Agent 循环 + 文件系统中间结果写文件,逐步推进
文档量大且更新频繁向量索引 + 增量更新文件系统遍历成本太高
需要精确匹配代码或参数关键词检索 + 文件精读向量检索对精确匹配不敏感
处理表格、图表等结构化内容文件系统 + 解析工具向量化会丢失结构信息

这张表不是绝对的,但可以作为一个起点。实际使用中,Agent 应该有能力根据反馈动态调整策略,而不是死守某一种方法。

5. 实操:搭一个 Agent 加文件系统的知识助手

5.1 整体架构设计

下面我以一个实际做过的内部技术文档助手为例,讲讲怎么把 Agent 和文件系统结合起来。这个项目的需求是:团队有大约 300 份技术文档,包括设计文档、API 说明、故障排查手册、会议纪要,格式有 Markdown、PDF、Word。用户希望通过自然语言提问,快速找到答案。

我的架构是这样的:

  • 存储层:所有文档统一转成 Markdown,按项目/模块/类型组织目录结构。
  • 索引层:用轻量级向量库做 embedding,同时保留一个基于 SQLite 的关键词索引。
  • Agent 层:一个基于 ReAct 模式的 Agent,配备四个工具:list_directory、read_file、vector_search、keyword_search。
  • 记忆层:Agent 的工作目录,用来写中间结果和最终报告。

这个架构的关键在于,Agent 不是被动地接受检索结果,而是主动地选择工具、组合工具。它的提示词里会明确说明每个工具的适用场景,以及什么时候应该换一个工具试试。

5.2 文档预处理的关键步骤

文档预处理这一步,很多人会直接丢给现成的 RAG 框架,但我在踩了几次坑之后,现在会手动做几件事:

第一步是统一格式。把所有 PDF、Word 转成 Markdown。PDF 转换用pymupdf或者pdfplumber,Word 用python-docx。转换的时候要注意保留标题层级,因为后面 Agent 要靠标题来导航。

第二步是重命名和重组目录。原始文件名往往是“文档1.pdf”“最终版_v3.docx”这种,Agent 根本看不懂。我会根据内容重新命名,比如auth/oauth2-flow.md、troubleshooting/pump-overheat.md。目录结构尽量扁平,不超过三层,因为太深了 Agent 也容易迷路。

第三步是生成摘要文件。在每个目录下放一个_index.md,里面列出该目录下所有文件的名称和一句话描述。Agent 可以先读这个索引文件,快速了解有什么内容,再决定读哪个具体文件。这个技巧非常实用,相当于给文件系统加了一层“目录页”。

第四步才是做 embedding。把 Markdown 按标题层级切块,每个块保留所属的标题路径作为元数据。这样检索结果里会带上“来自 auth/oauth2-flow.md 的‘令牌刷新’章节”这样的信息,方便 Agent 判断相关性。

5.3 Agent 的工具定义与提示词设计

Agent 的工具定义很直接,用 Python 函数加装饰器就行。关键是提示词的设计,我改了好几版才找到比较稳定的写法。核心要点是:

  • 明确告诉 Agent 每个工具返回什么格式的数据。
  • 给出每个工具的适用场景和典型调用顺序。
  • 强调“如果第一次检索结果不理想,不要重复同样的查询,换一个工具或换一个关键词”。
  • 要求 Agent 在每一步之后简要说明“我学到了什么”和“下一步计划”。

我实际用的提示词片段大概是这样的:

你可以使用以下工具来查找信息。当你需要了解某个目录下有什么文件时,使用 list_directory。当你已经知道要读哪个文件时,使用 read_file。当你只有一个模糊的问题,不知道具体在哪个文件时,先用 vector_search 找候选,再用 read_file 精读。如果 vector_search 的结果不相关,尝试 keyword_search 做精确匹配。每次检索后,评估结果是否足以回答问题。如果不够,换一个策略再试。

这个提示词看起来简单,但它把“检索是一个迭代过程”这个观念植入了 Agent 的决策逻辑里。实测下来,Agent 平均会进行 2.3 次工具调用才给出最终答案,而传统 RAG 只有一次。

5.4 一个完整的问答流程实录

我记录了一个真实的问答过程,展示 Agent 是怎么工作的。用户问:“OAuth2 的令牌刷新失败一般是什么原因?”

第一轮:Agent 先调用vector_search("OAuth2 令牌刷新失败原因"),返回了三个候选块,分别来自auth/oauth2-flow.md、troubleshooting/token-issues.md、api/authentication.md。Agent 判断这三个都可能相关,但需要更多细节。

第二轮:Agent 调用read_file("troubleshooting/token-issues.md"),读到了完整的故障排查章节,里面列出了五种常见原因:刷新令牌过期、客户端密钥错误、时钟偏移、网络超时、权限范围变更。Agent 觉得这个文件很有用,但还想确认一下具体的错误码。

第三轮:Agent 调用keyword_search("令牌刷新 错误码"),找到了api/authentication.md里的错误码表,里面有invalid_grant、invalid_client等具体代码。

第四轮:Agent 综合三个来源的信息,生成了最终回答,并且附上了每个结论的出处文件路径。

整个过程 Agent 调用了四次工具,耗时大约 8 秒。如果用传统 RAG,一次检索可能只能命中其中一个文件,回答的完整性会差很多。

6. 常见问题与排查技巧实录

6.1 Agent 迷路在文件系统里怎么办

这是最常见的问题。Agent 在目录里来回跳转,读了一堆不相关的文件,最后超时或者给出一个模糊的答案。我遇到过一次,Agent 为了找一个配置项,把整个config目录下的 20 多个文件全读了一遍,耗时 40 多秒。

排查思路:先看 Agent 的轨迹日志,确认它是在哪个环节开始偏离的。通常是因为目录结构太深,或者文件名没有语义。我的解决办法是:

  • 限制 Agent 的最大工具调用次数,比如 10 次,超过就强制它基于已有信息回答。
  • 在每个目录下放_index.md,让 Agent 先读索引再决定读哪个文件。
  • 在提示词里明确说“不要一次读超过三个文件,如果三个文件还不能回答,就告诉用户信息不足”。

6.2 向量检索和文件读取结果冲突怎么处理

有时候向量检索返回的文本块和文件精读的结果不一致,Agent 会陷入困惑。这种情况通常是因为向量库里的内容是旧版本,而文件系统里的是新版本。

解决办法:在 Agent 的提示词里加一条规则——当文件内容和向量检索结果冲突时,以文件内容为准,因为文件是最新的原始来源。同时,定期重建向量索引,确保它和文件系统同步。我在项目里加了一个定时任务,每天凌晨重新索引变更过的文件。

6.3 文件太多导致列目录超时

当目录下有几百个文件时,list_directory返回的列表会非常长,既浪费上下文窗口,又让 Agent 难以聚焦。我的做法是:

  • 目录下文件超过 50 个时,自动分页,每次只返回前 50 个。
  • 在_index.md里按类别分组,Agent 可以先看分组再决定看哪一组。
  • 对于特别大的目录,拆分成子目录,保持每个目录下不超过 30 个文件。

6.4 常见问题速查表

问题现象可能原因解决方向
Agent 反复读同一个文件提示词没有要求它记录已读文件在提示词里要求维护已读列表
回答缺少出处没有要求 Agent 标注来源提示词强制要求附上文件路径
检索结果不相关向量模型不适合该领域换模型或增加关键词检索兜底
处理速度慢工具调用次数太多限制最大调用次数,优化索引
文件读取乱码编码不统一预处理时统一转 UTF-8
表格内容丢失向量化破坏了结构表格单独处理,不走向量检索

6.5 几个我踩过的坑

第一个坑是过度依赖向量检索。一开始我给 Agent 只配了向量检索工具,结果遇到精确匹配的需求就歇菜。后来加了关键词检索和文件直读,效果立刻好转。

第二个坑是文件命名太随意。早期文档都是“新建文档.md”“最终版.md”,Agent 完全无法判断内容。后来强制要求文件名包含模块名和主题,比如auth-token-refresh.md,Agent 的导航效率提升了一倍多。

第三个坑是没有限制上下文长度。Agent 读了一个大文件,把整个内容塞进上下文,导致后面的推理被淹没。后来我在read_file工具里加了截断逻辑,超过 2000 字的文件只返回前 2000 字,并提示 Agent 可以用关键词检索定位具体段落。

7. 我的个人体会与后续扩展方向

回到最初的问题:“RAG 死了吗?文件系统能包打一切吗?”我的答案是:RAG 没有死,它只是从“唯一的检索方式”变成了“多种检索方式中的一种”。文件系统也不能包打一切,它擅长的是结构化导航和精确读取,不擅长模糊匹配和大规模检索。

真正重要的是,Agent 给了我们一个机会,把过去那些割裂的技术——向量检索、关键词检索、文件系统、代码执行——整合到一个统一的决策框架里。Agent 不需要在它们之间做非此即彼的选择,而是可以根据任务特点灵活组合。

我在实际项目中的体会是,与其纠结用哪种技术,不如先把知识本身整理好。文件命名清晰、目录结构合理、每个目录有索引文件,这些基础工作带来的收益,远比换一个更贵的 embedding 模型要大。技术是放大器,但前提是输入本身是干净的。

后续我打算在这个方向上继续做两件事:一是把 Agent 的工具调用轨迹可视化,方便排查问题;二是尝试让 Agent 自己维护索引,当它发现某个文件经常被检索到但内容过时,自动提醒更新。这两个方向都还在实验阶段,等有成熟结果了再单独写一篇分享。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询