上一篇给了 RAG 五段全景。这一篇讲第一段——Document Loaders:把原始内容读进来。

听起来简单(不就读个文件吗),但它是整条 RAG 链的起点,读进来的质量直接决定后面一切。PDF 的表格没读对、网页的导航栏没去掉,后面切分、向量化、检索再精细,也是垃圾进垃圾出。

Document:统一的载体

不管原始内容是 PDF、网页还是数据库,Loaders 读进来的统一格式都是 Document 对象

Document 对象结构

一个 Document 包含两部分:

  • page_content:文本内容本身(这块会进 RAG 后续处理)
  • metadata:元信息(来源、页码、标题等,检索时可用于过滤、展示来源)

这个统一格式很关键:不管来源多杂,进了 LangChain 都是 Document。后面的切分、向量化只认 Document,不用为每种来源单独写处理。

Loaders 的大家族

不同来源有不同的 Loader,LangChain 提供一大堆:

Loader 读什么
PyPDFLoader PDF
WebBaseLoader 网页(HTML)
CSVLoader CSV 表格
DirectoryLoader 整个目录批量读
NotionLoader / SlackLoader 各类 SaaS
SQLLoader 数据库

Loaders 大家族

选 Loader 看你的数据来源。值得注意:同一来源可能有多个 Loader(比如 PDF 有按页读的、有按结构读的),效果不同,复杂文档要试试哪个读得干净。

最容易被忽略的坑:格式处理

Loaders 这一段,最容易被忽略的坑是格式处理

  • PDF 的表格:简单 Loader 把表格读成一团乱文本,结构全毁。需要能识别表格结构的 Loader
  • 网页的噪声:网页有导航栏、广告、脚本,不处理直接读,这些噪声会污染检索。要先清洗
  • Markdown 的结构:标题、代码块是有结构的,无视结构切分会割裂语义

格式处理的坑

很多人 RAG 效果差,第一反应是「换个 embedding 模型」「调检索参数」,但其实根子在 Loader 这步没读干净。加载格式决定了后面切分质量,这是最该花心思却最常被忽视的一环。

一个工程习惯:先看读进来长啥样

一个好习惯:Loader 读完后,先打印 Document 的 page_content 看看,确认读得干净,再往下走。

docs = loader.load()
print(docs[0].page_content[:500])  # 看前 500 字
print(docs[0].metadata)             # 看元信息

这一步能发现大部分「格式没读对」的问题。等到向量化和检索阶段才发现 Loader 有问题,已经建好库了,返工成本大。早期多花 5 分钟检查,省后面几小时排查。

Loaders 也是 Runnable

和 Phase 1 讲的一致,Loader 本质也是个 Runnable——输入来源,输出 Document 列表。所以它能进 LCEL 链,能被追踪。

不过实际中,加载通常是建库阶段离线做一次(上一篇讲的),不每次查询都加载。所以 Loader 更多是建库脚本里用,而不是在查询的 RAG 链里。

收束:Loader 是 RAG 的起点,最该花心思

这一篇讲了 Document Loaders:

  • 统一输出 Document 对象(page_content + metadata)
  • 有针对各种来源的 Loader 家族
  • 最易被忽视的坑:格式处理(PDF 表格、网页噪声、Markdown 结构)
  • 好习惯:读完先看 page_content 确认干净
  • 通常在离线建库阶段用

下一篇讲第二段——Text Splitters:把读进来的长文档切成块。而且会讲一个反常识的判断:切分策略比 embedding 模型更重要。


关于十三Tech

我是十三,All in AI Agent 方向的架构师,专注 AI 工程实践。我相信 AI 是程序员的最佳搭档。

如果你想跟完这套「图解 LangChain」,欢迎关注公众号 「十三Tech」。全系列 42 篇,会按认识基础、LangGraph 状态机、Agent 与 middleware、RAG 检索、Tools/MCP/记忆、生产化收束这条线更新。

十三Tech公众号二维码