背景介绍
在过去实践 RAG 的过程中,深刻体会到 RAGFlow 提出的 "Quality in, quality out"
, 只有高质量的文件处理才能获得良好的 RAG 效果。
RAG 的第一步是对文件进行解析,由于 Embedding 和 LLM 模型的长度限制,往往需要将解析后的文件进行切片。原始的 RAG 就是直接按照固定长度对文件进行切分,导致最终检索到的内容都是碎片化的,效果往往不佳。因此后续的改进期望能按照文件的结构进行切分,保证分块信息的完整性,这就是所谓的 "structure-aware" chunker
。
但是并非所有的文件都容易获取到结构信息,比如 pdf 文件获取结构化的信息就比较困难,一个可选的方案就是将 pdf 等难以处理的文档转换为相对容易获取结构的格式,基于转换后的文档进行结构化解析和切分。目前一般会选择转换为 html 或 markdown 格式。
本文就以相对基础的 html 文件为例,比较目前热门 RAG 项目中的结构化解析文件的能力,看看目前 RAG 项目处理文件的基本功如何。
技术方案比较
在梳理了现有的 RAG 开源项目之后,发现使用的技术存在不少相似之处,因此先总结使用的技术方案,后面在与开源项目意义对应。
实际测试时使用的是如下所示的一个 html 片段:
基于 unstructured 解析方案
unstructured 是一个目前热门的开源非结构化文件解析方案,专门为 RAG 场景进行设计,支持了文件的解析,切片等多种场景。
目前基于 unstructured 的方案存在两种用法:
- 使用 unstructured 提取出完整的文本内容,之后将完整的内容提供给 RAG 的 Splitter 环节进行切片,这种方案没办法做任何结构化的优化,因为结构化信息在解析环节已经全部丢弃,后续只能根据符号和文本内容进行分片;
- 使用 unstructured 拆分出 html 元素,提取各个元素的内容并进行必要的拼接,之后再提交给 Splitter 环节进行处理,这种方式可以保留部分文件结构化信息;
下面简单实现 unstructed 的文档解析拆分如下所示:
from langchain_community.document_loaders import UnstructuredHTMLLoader
loader = UnstructuredHTMLLoader(
"./xxx.html",
mode="elements",
strategy="fast",
)
docs = loader.load()
for doc