乐于分享
好东西不私藏

06 | RAG主流文档加载器速查(PDF、Text、Markdown、目录)

06 | RAG主流文档加载器速查(PDF、Text、Markdown、目录)
前面对CSV 和 JSON 已经单独讲过了:
04 | RAG中的CSV文档加载(CSVLoader)
05 | RAG中的JSON文档加载(JSONLoader)
主要是让人更深的感受一下它的用法和适用场景,至于剩下的主流资料源,它们本质上都在做同一件事:把不同来源的资料加载成 LangChain 的 Document。
所以本篇不展开赘述,只保留最常用、最容易在本地实际跑起来的几类:PDF、TXT、Markdown、文件夹批量加载,梭哈讲一下。

一、先看怎么选

不用背。先看你的资料长什么样,再选 loader。别为了用高级 loader,把简单事情搞复杂。

二、PDF:PyPDFLoader

适合加载法规、合同、制度、说明书这类 PDF。
默认建议先按页加载,因为页码对 RAG 很有用。用户问制度或法律问题时,最好能追到“第几页”。
# 安装:uv add langchain-community pypdffrom pathlib import Pathfrom langchain_community.document_loaders import PyPDFLoaderpdf_path = Path("data/中华人民共和国数据安全法.pdf")# mode="page":一页 PDF 生成一个 Document。# 好处是 metadata 里会保留 page / page_label,方便后续引用页码。loader = PyPDFLoader(str(pdf_path), mode="page")documents = loader.load()print(len(documents))print(documents[0].page_content[:500])print(documents[0].metadata)
输出:
101 中华人民共和国数据安全法 (来源:中国人大网,2021-07-21) 中华人民共和国数据安全法 2021 年6 月10 日第十三届全国人民代表大会常务委员会第二十九次会议通过) 目  录 第一章 总  则 第二章 数据安全与发展...{'producer''Microsoft® Word 2010''creator''Microsoft® Word 2010''creationdate''2021-08-09T09:17:07+08:00''author''xxx''moddate''2021-08-09T09:17:07+08:00''source''data/中华人民共和国数据安全法.pdf''total_pages'10'page'0'page_label''1'}

三、纯文本:TextLoader

适合 .txt、简单日志、纯文本说明。一个文本文件默认读成一个 Document。
所以就算 xiaoshuo.txt很长,len(documents) 也通常是1。这不是异常,说明 loader 已经把整份文本搬进来了。后面要不要按章节、段落、长度切开,是TextSplitter的事情。
# 安装:uv add langchain-communityfrom pathlib import Pathfrom langchain_community.document_loaders import TextLoadertext_path = Path("data/xiaoshuo.txt")# encoding 很重要。中文文本建议显式写 utf-8,少给自己挖坑。loader = TextLoader(str(text_path), encoding="utf-8")documents = loader.load()print(len(documents))print(documents[0].page_content[:500])print(documents[0].metadata)
输出:
1第一章 崭露头角  青少年时代在意大利半岛的西面,有一个形状如鸡蛋的海岛,名为科西嘉岛。该岛山峦起伏、丛林密布。岛上居住着一个顽强好斗的民族,他们犹如雄鹰一般,时刻盘旋在自己的窝巢之上,对来犯敌人进行毫不留情的痛击。科西嘉岛属热那亚商业国,18世纪上半叶,岛上人民开始了反对热那亚占领者的民族独立运动。他们在自己的领袖保利的领导下,赶走了热那亚人,成立了科西嘉独立政府。然而,好景不长,1768515日,热那亚同法国签订了科西嘉归让法国的秘密协定,把实际上已不拥有的对科西嘉的"权力"出售给法国。法国强大的远征军占领了该岛的沿海城镇。岛上居民对这种出卖和蹂躏科西嘉人民自由权利的行径极为愤慨,他们再度团结一致,在保利的指挥下,展开了反抗法国入侵者的战斗。  保利身边有位年轻的副官名叫夏尔。波拿巴,他是岛上阿雅克修城的一个贵族,当时正在攻读法律。夏尔具有狂热的性格,他痛恨法国人的入侵,毅然放下书本,带着妻子莱蒂齐亚。拉莫利诺参加了科西嘉保卫战。炮声隆隆,飞尘蔽日,岛上居民顽强地抗击着登陆的法军。夏尔的第一个孩子约瑟夫便出生在这个战火纷飞的年代。1769年春,岛上居民终因寡不敌众,被迫向征{'source''data/xiaoshuo.txt'}
TXT 最大的问题不是加载,而是后续切分。
如果一个 TXT 很长,TextLoader只是先读进来,后面通常还要接 TextSplitter。Loader 负责搬进门,切不切块是下一步。

四、Markdown:UnstructuredMarkdownLoader

适合技术文档、README、内部知识库、Notion 导出的 Markdown。
Markdown 比 TXT 多了标题、列表、链接这些结构。用普通 TextLoader也能读,但UnstructuredMarkdownLoader更适合保留一些文档结构信息。
注意:这个 loader 依赖markdown包。如果没装,运行时可能会报ModuleNotFoundError: No module named 'markdown'。
# 安装:uv add langchain-community unstructured markdownfrom pathlib import Pathfrom langchain_community.document_loaders import UnstructuredMarkdownLoadermd_path = Path("data/internal_refund_guide.md")md_path.write_text(    "# 退款操作手册\n\n"    "## 未发货订单\n"    "用户可以直接在订单详情页申请退款。\n\n"    "## 已发货订单\n"    "需要先确认物流状态,再进入售后流程。\n",    encoding="utf-8",)# mode="single":整篇 Markdown 作为一个 Document# mode="elements":按标题正文等元素拆成多个 Document,适合更细粒度处理loader = UnstructuredMarkdownLoader(str(md_path), mode="single")documents = loader.load()print(documents[0].page_content[:500])print(documents[0].metadata)
输出:
退款操作手册未发货订单用户可以直接在订单详情页申请退款。已发货订单需要先确认物流状态,再进入售后流程。{'source''data/internal_refund_guide.md'}
Markdown 的选择很简单:
  • 只是先加载进来:`mode="single"`
  • 想按标题、段落等结构拆得更细:`mode="elements"`
别一上来就 elements。先看你的文档是不是值得这么细。

五、文件夹批量加载:DirectoryLoader

真实项目里,一个目录里往往不止一种文件。比如:
policies/  refund.txt  invoice.txt  中华人民共和国数据安全法.pdf
这时候不要指望DirectoryLoader 自动识别所有格式。它的作用是批量找文件,然后把文件交给指定 loader。所以更清楚的做法是:按文件类型分批加载。
# 安装:uv add langchain-community pypdffrom pathlib import Pathfrom langchain_community.document_loaders import DirectoryLoader, TextLoader, PyPDFLoaderfolder = Path("data/policies")folder.mkdir(exist_ok=True)# 第一批:加载 txt 文件。# DirectoryLoader 负责找到所有 txt;TextLoader 负责读取每个 txt。txt_loader = DirectoryLoader(    str(folder),    glob="**/*.txt",    loader_cls=TextLoader,    loader_kwargs={"encoding""utf-8"},)# 第二批:加载 pdf 文件。# DirectoryLoader 负责找到所有 pdf;PyPDFLoader 负责按页读取每个 pdf。pdf_loader = DirectoryLoader(    str(folder),    glob="**/*.pdf",    loader_cls=PyPDFLoader,    loader_kwargs={"mode""page"},)txt_documents = txt_loader.load()pdf_documents = pdf_loader.load()# 最后把不同类型加载出来的 Document 合并。documents = txt_documents + pdf_documentsprint("txt docs:"len(txt_documents))print("pdf docs:"len(pdf_documents))print("all docs:"len(documents))print(documents[0].page_content[:300])print(documents[0].metadata)
输出:
txt docs: 2pdf docs: 10all docs: 12未发货订单支持退款。{'source''data/policies/refund.txt'}