上一篇给了 RAG 五段全景。这一篇讲第一段——Document Loaders:把原始内容读进来。
听起来简单(不就读个文件吗),但它是整条 RAG 链的起点,读进来的质量直接决定后面一切。PDF 的表格没读对、网页的导航栏没去掉,后面切分、向量化、检索再精细,也是垃圾进垃圾出。
Document:统一的载体
不管原始内容是 PDF、网页还是数据库,Loaders 读进来的统一格式都是 Document 对象:
一个 Document 包含两部分:
- page_content:文本内容本身(这块会进 RAG 后续处理)
- metadata:元信息(来源、页码、标题等,检索时可用于过滤、展示来源)
这个统一格式很关键:不管来源多杂,进了 LangChain 都是 Document。后面的切分、向量化只认 Document,不用为每种来源单独写处理。
Loaders 的大家族
不同来源有不同的 Loader,LangChain 提供一大堆:
| Loader | 读什么 |
|---|---|
| PyPDFLoader | |
| WebBaseLoader | 网页(HTML) |
| CSVLoader | CSV 表格 |
| DirectoryLoader | 整个目录批量读 |
| NotionLoader / SlackLoader | 各类 SaaS |
| SQLLoader | 数据库 |
选 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/记忆、生产化收束这条线更新。

