你可能并不需要 RAG
这篇文章的目的并非全盘否认 RAG(Retrieval-Augmented Generation,检索增强生成),而是尝试提供一种新的视角,帮助你重新思考“知识检索”这件事。
为什么我们需要 RAG?
回顾最初引入 RAG 的原因,主要有两点:
- 知识截止问题:LLM(Large Language Model,大型语言模型)的训练数据具有时间边界,无法覆盖最新信息。
- 企业数据隔离:企业内部的私有数据并未参与模型训练,模型天然“不可见”。
既然模型不知道,我们是否可以把所有数据直接通过提示词(Prompt)提供给它?
这种“把所有信息都塞进去”的思路,在实践中往往会遇到几个关键问题:
- Token 消耗巨大:不仅成本高,还会显著拖慢响应速度。
- 上下文窗口限制:即使部分模型支持百万级上下文,仍然存在物理上限。
- 注意力分散(Lost in the middle):在长文本中,模型容易忽略中间信息,导致回答质量下降。
RAG 正是在这样的背景下诞生的:在调用模型之前,先检索出与问题最相关的内容,再将其作为上下文提供给模型,从而提升回答质量。
传统 RAG 面临的困境
为了更清楚地理解问题,我们先看一下传统 RAG 的基本流程:
问题往往出现在复杂场景中。传统 RAG 依赖于基于文本片段(Chunk)的语义相似度检索。当答案分散在多个位置时,向量检索通常只能返回若干“相似”的片段,而这些片段之间缺乏完整的逻辑关联。
换句话说,它更擅长“找相关内容”,但不一定能“还原完整答案”。
基于这一问题,本文尝试提出一种不同思路:一种基于 Agent 的层级化检索方案,也可以理解为“弱化 RAG”的方式。
破局思路:基于目录树的检索方式
需要说明的是,这种方法并非通用解法,更适用于金融、法律等对准确性和逻辑完整性要求较高的场景。
核心思想:让模型“像人一样阅读”
当人类查阅一本专业书籍时,通常不会逐页阅读或随机翻找,而是遵循一个自然过程:
先看目录 → 浏览章节 → 定位段落 → 精读内容
这一过程可以在系统中被复现为一种“分层检索机制”。
在工程实践中,可以按如下步骤实现:
-
目录隔离管理
原始文件统一存放在raw目录;经过处理后的结构化数据存放在data目录,实现数据分层管理。 -
放弃简单切块
不再进行传统的 Chunk 切分,而是以文档结构为核心进行处理。 -
生成文档概览
使用模型对文档整体进行总结,生成标题与摘要。 -
构建目录树
提取章节结构(如一级、二级标题),并为每个节点生成简要描述,递归构建完整目录树。 -
结构化存储
将目录结构与摘要整理为 JSON 文件,保存到data目录。 -
构建全局索引
更新统一入口文件(如index.md),用于管理所有文档的结构信息。
数据结构示例
一个典型的目录树结构如下:
{
"document_id": "doc_1024",
"title": "2024年度企业财务合规指南",
"summary": "本文档详细规定了企业在2024年度的财务报销、税务申报及内控合规审计的相关标准与流程。",
"source_file": "raw/finance_guide_2024.pdf",
"toc": [
{
"level": 1,
"title": "第一章:报销规范",
"description": "涵盖差旅、餐饮及日常办公用品的报销标准及各级审批流程。",
"content_path": "data/doc_1024/chapter_1.md",
"sub_sections": [
{
"level": 2,
"title": "1.1 差旅费报销",
"description": "国内及国际出差的交通工具等级限制、酒店限额及发票合规要求。"
}
]
}
]
}
检索与问答流程
在完成上述结构构建后,问答流程将发生变化:
这种方式本质上将知识组织为类似 Wiki 的结构化网络。 在回答问题时,Agent 先进行路径选择,再进行局部阅读,必要时跨文档整合信息,从而生成更完整的答案。
进阶问题:大文件与复杂格式
在实际应用中,还需要处理复杂文档,例如体量较大的 PDF 文件或包含表格、图片的资料。
这类问题可以通过“多模态数据清洗”解决。例如借助类似 MarkItDown 的工具,将 PDF 转换为 Markdown,并保留结构信息。
如果转换后的内容仍然较大,可以基于 Markdown 的标题结构(如 #、##)进行自然分段,再逐段生成描述,最终构建目录树。
结语
与其不断优化向量检索的召回效果,不如尝试从结构化组织的角度重新思考问题。让 Agent 具备类似人类的“阅读路径”,往往能带来更稳定、可解释的结果。
如果你有建议或者想法,欢迎进一步交流。