当前位置: 首页 > news >正文

Document Loader:LangChain 如何读取 PDF、网页、Word、数据库?

一、Loader 是 RAG 的入口,不是普通文件读取

很多人第一次用 LangChain 做知识库,代码通常是这样的:

loader = PyPDFLoader("产品手册.pdf")
docs = loader.load()

看起来像两行文件读取。其实不是。

Loader 的真正任务,是把各种乱七八糟的资料,统一变成 LangChain 标准的 Document。PDF、网页、Markdown、CSV、数据库、云盘,格式完全不同。后面的 Splitter、Embedding、VectorStore、Retriever 不想关心这些差异。

所以 LangChain 在这里做了一层抽象:不管你从哪里来,最后都要变成 Document。

二、官方定义:Loader 解决的是“统一入口”问题

LangChain 官方文档把 Document Loaders 定义为一个标准接口:它们负责从 Slack、Notion、Google Drive 等不同来源读取数据,并转换成 LangChain 的 Document 格式。这样后续组件可以用统一方式处理资料。

所有文档加载器都实现 BaseLoader 接口。每个加载器参数可以不同,但共享两个核心 API:

API

作用

适合场景

load()

一次性加载所有 Document

小文件、调试、Demo

lazy_load()

按需产出 Document 生成器

大文件、批量任务、生产环境

aload() / alazy_load()

异步加载版本

异步服务、爬取、批量并发

load_and_split()

加载后直接切分

旧写法,不建议作为生产核心入口

一句话:load() 是方便入口,lazy_load() 才是生产思维。

三、BaseLoader 到底做了什么?

BaseLoader 的源码并不复杂,但设计很关键。它没有假设你读的是 PDF、网页还是数据库。它只约定一件事:子类最终要产出 Document。

源码逻辑可以压缩成四句话:

• load():直接把 lazy_load() 的结果收集成 list。

• lazy_load():真正的懒加载入口,应该由子类实现。

• aload() / alazy_load():异步包装,适合异步任务。

• load_and_split():先 load,再 split,但源码里已经提醒不要重写,且应逐步淡出核心用法。

用伪源码看,更清楚:

class BaseLoader:
def load(self):
return list(self.lazy_load())
def lazy_load(self):
# 子类实现:读取数据,yield Document
raise NotImplementedError
async def alazy_load(self):
# 异步地从 lazy_load() 里拿 Document
yield document

这里有一个非常重要的工程点:

BaseLoader 鼓励子类实现 lazy_load(),因为大文件、大目录、大网页集合,不能一次性全塞进内存。

四、Document 是 Loader 的标准产物

Loader 读完资料以后,不是返回字符串,也不是返回 JSON,而是返回 Document。

Document 的核心字段很少,但都很关键:

字段

含义

为什么重要

page_content

正文文本

后续会被切分、向量化、拼进 Prompt

metadata

元数据字典

source、page、title、权限、业务标签、时间都靠它

id

可选唯一标识

方便增量更新、删除、去重、追溯

源码里还特意强调:Document 是 retrieval workflow 的对象,不是 chat message。也就是说,Document 是知识库里的资料单元,不是多轮对话里的 HumanMessage、AIMessage。

Document(
page_content="这里是正文内容",
metadata={"source": "manual.pdf", "page": 12},
id="stable-doc-id"
)

生产环境里,metadata 比你想象中更重要。没有 metadata,RAG 就没法做来源引用;没有 page,用户不知道答案来自哪一页;没有权限字段,私有文档可能被错误召回;没有版本号,增量更新会变成噩梦。

五、Blob 和 Parser,为什么要拆开?

更深一点看源码,LangChain 还有 Blob 和 BaseBlobParser。

Blob 表示原始数据:可能是文件路径,可能是 bytes,可能是内存里的字符串,还可以带 MIME、encoding、metadata。Parser 负责把 Blob 解析成一个或多个 Document。

这个设计背后的思想是:

• 加载和解析分开。拿到文件是一回事,理解 PDF、HTML、DOCX 又是另一回事。

• 同一个 Blob 可以交给不同 Parser。比如 PDF 可以用简单解析器,也可以用带 OCR 的解析器。

• Parser 可以懒解析。大文件不必一次性全部读完。

• 扩展更干净。你要接企业内部文档系统,只需要把原始内容变成 Blob,再写 Parser。

这就是为什么企业级 RAG 不要只写“loader.load()”。你真正要关心的是:原始数据怎么取?解析器怎么选?Document 怎么补元数据?失败怎么重试?

六、常见 Loader 怎么选?

LangChain 的集成生态很大。官方文档中,Document Loader 按来源覆盖网页、PDF、云服务、常见文件类型等类别。LangChain 的整体集成生态也覆盖聊天模型、Embedding、工具、文档加载器、向量库等 1000+ 集成。

选择 Loader 不要只看“能不能读出来”,还要看“读出来的结构好不好”。

资料类型

重点问题

建议

PDF

表格、页码、图片、扫描件、双栏排版

普通 PDF 可用 PyPDF 类;复杂版式考虑 Docling、Unstructured、OCR

网页

导航、广告、脚本、动态渲染

静态页用 WebBaseLoader;动态页考虑浏览器/爬虫服务

Markdown

标题层级、代码块、列表结构

尽量保留 Markdown 结构,方便后续按标题切分

目录

文件太多、格式混杂、隐藏文件

用 glob 精准过滤,用 loader_cls 指定解析器

表格

字段语义、行级颗粒度

把字段名和业务主键放进 metadata

数据库

分页、权限、增量

按更新时间/主键批量拉取,不要全表扫

七、PDF Loader:最容易被低估的坑

PDF 是 RAG 里最常见,也最容易出问题的资料。

很多 PDF 看起来很规整,但里面可能是文本框、图片、表格、页眉页脚、两栏布局。普通解析器把它转成纯文本时,很容易丢结构。

PDF 解析要重点看四件事:

• 能不能保留页码。页码是溯源的关键。

• 能不能处理表格。表格被打散后,答案会很容易错。

• 能不能处理扫描件。扫描件需要 OCR,不是普通文本提取。

• 能不能处理版式。两栏排版、页眉页脚、脚注都可能污染内容。

PDF Loader 的核心不是“能读出字”,而是“读出的字还能不能回答问题”。

八、WebBaseLoader:网页不是正文,网页是噪声集合

网页加载也一样。你想要的是正文,但网页里还有导航栏、推荐文章、广告、版权声明、评论区、脚本内容。

WebBaseLoader 通常会配合 BeautifulSoup 解析 HTML。BeautifulSoup 的定位是从 HTML/XML 中提取数据,并提供遍历、搜索、修改解析树的能力。

真正使用时,不要无脑抓整页。最好指定正文区域。比如只抓文章标题、正文容器、文档主体 class。

loader = WebBaseLoader(
web_paths=[page_url],
bs_kwargs={"parse_only": SoupStrainer(class_="article-content")},
)

这里的关键不是代码,而是思路:

• 能过滤就过滤,不要把整页垃圾都送进知识库。

• 动态网页要小心,requests 抓不到 JS 渲染后的内容。

• 批量抓网页要有速率限制、User-Agent、失败重试。

• 网页内容要保留 URL、标题、发布时间、站点来源。

九、DirectoryLoader:它不是解析器,它是调度器

很多人误会 DirectoryLoader,以为它自己会解析所有文件。更准确地说,它负责遍历目录,真正解析通常交给 loader_cls。

也就是说:

DirectoryLoader(
path="./docs",
glob="**/*.md",
loader_cls=TextLoader,
)

这段代码的核心是:DirectoryLoader 找文件,TextLoader 读文件。

所以目录加载要重点控制:

• glob:只加载你要的文件,不要把临时文件、日志、备份都吃进去。

• loader_cls:不同文件类型要选不同 Loader。

• silent_errors:生产中不要简单吞错,要记录失败原因。

• use_multithreading:I/O 密集任务可以加速,但错误处理要更严格。

• load_hidden:隐藏文件是否加载,要看业务安全策略。

十、Loader 之后,立刻进入数据治理

企业级项目里,Loader 后面不能直接进 Embedding。中间至少要经过清洗、去重、补元数据、权限校验。

推荐的数据表设计可以简单分成几层:

表/对象

作用

关键字段

raw_document

保存原始文档记录

source_url、file_path、hash、status

parse_task

记录解析任务

task_id、status、error_message、retry_count

document_chunk

保存切分后的 Chunk

doc_id、chunk_id、content、metadata

document_embedding

保存向量索引关联

chunk_id、vector_id、embedding_model

source_permission

权限控制

source_id、tenant_id、role、user_scope

这样做的好处是:出了问题可以查。哪份文档解析失败,哪一页表格错了,哪个 Chunk 被召回,哪个用户有权限看,都能追溯。

十一、Loader 最容易翻车的地方

这几个坑,生产系统里非常常见:

• 编码问题:中文、日文、特殊符号乱码,后续向量化也会跟着错。

• PDF 表格丢失:财报、研报、合同里的关键数据经常藏在表格里。

• 网页噪声:导航、广告、推荐位进入知识库,召回结果会变脏。

• 元数据不足:没有 source/page/title,答案无法引用来源。

• 权限缺失:私有资料被公共用户检索到,属于严重安全事故。

• 全量重跑:每次都重新解析所有文档,成本高、速度慢、容易不稳定。

十二、源码级总结:Loader 链路压缩成一条线

真正要记住的不是 API 名字,而是职责边界:

• Loader 负责把外部资料读进来。

• Document 负责统一数据结构。

• metadata 负责来源、权限、追溯。

• Blob/Parser 负责把原始数据和解析逻辑拆开。

• lazy_load 负责生产环境的大文件和流式加载。

十三、总结

LangChain 的 Document Loader 看起来是小组件。

但在 RAG 系统里,它是第一道门。

门口放进来的资料越干净,后面的检索越准。

门口放进来的资料越混乱,后面的模型越容易胡说。

RAG 的质量,不是从 Prompt 开始的,而是从 Loader 开始的。

下一章继续讲 Text Splitter:为什么知识库不能整篇文档直接丢给大模型?


内容来源:Document Loader:LangChain 如何读取 PDF、网页、Word、数据库?:功能变化与行业影响解析_热闻岛

http://www.jsqmd.com/news/1008777/

相关文章:

  • 避开性能坑!在uniapp里用uQRCode绘制复杂二维码时,我是这样优化canvas渲染和图片保存的
  • 开会不用埋头记!5款AI神器自动整理全套会议记录
  • 【课程设计/毕业设计】基于 SpringBoot 的校园家教信息平台的设计与实现高校校园家教服务信息平台【附源码、数据库、万字文档】
  • 新手也能懂的DC-DC降压电路PCB布局:从MPQ8633A实战到自检清单
  • AI 时代,忙碌不再等于价值
  • 收藏!2026最新完整版AI大模型系统学习路线图,零基础程序员也能稳步入行
  • 别再只会生成黑白码了!用uQRCode在UniApp里玩转彩色、带Logo和边框的个性化二维码
  • 20250931在RK3399的Buildroot【linux-6.1】下关闭camera_engine_rkisp
  • Devin AI 自主式 AI 软件工程师智能体
  • 别再死记硬背单纯形法了!用C++手写一个两阶段求解器,从原理到代码一次搞定
  • ArcMap布局视图下,给专题图加上专业经纬网的保姆级教程(含样式自定义)
  • 华为OD机试真题 新系统 2026-06-10 JavaGoC 实现【双系统资源类型调配】【200】
  • MATLAB数据处理效率翻倍:巧用reshape函数将表格数据快速转为图像输入格式
  • R3nzSkin:游戏换肤技术的Windows钩子注入实现深度解析
  • Python多重循环实战:从鸡兔同笼到打印字母金字塔,新手必练的5个经典案例
  • GPT4ALL的LocalDocs功能实战:如何用你的本地文档(PDF/TXT)搭建一个私密知识库问答系统
  • CH32V103/V307 IAP跳转避坑指南:机器模式配置、函数属性与长跳转的那些事儿
  • 联想拯救者工具箱终极指南:3步轻松掌控游戏本性能
  • 手把手教你用RISC-V Sail Model生成C模拟器:从形式化规范到可执行代码
  • 智能科学与技术=人工智能专业? [特殊字符] 高考志愿的十字路口,深度解析与通关秘籍!
  • AI 时代,真正的差距不是模型能力,而是控制能力
  • 还在手写会议纪要?这5个AI工具一键搞定全部内容
  • 异常值检测实战:可视化诊断与统计方法双轨并行
  • Spring Boot项目从fastjson1.x升级到fastjson2.x实战:手把手教你重写Redis序列化工具类
  • LS1046A SEC中断聚合配置实战:提升嵌入式安全处理器性能
  • 保姆级教程:H3C S6520交换机端口状态信息全解读(从display interface到dis brief)
  • 别再死记硬背for循环了!用Python解决‘完全数’和‘剩余木料’问题,理解循环嵌套的本质
  • 厉害了,程序员的高考试卷,你能拿几分?
  • 基于PLC的智能温室控制系统设计12(设计源文件+万字报告+讲解)(支持资料、图片参考_降重降ai)
  • 收藏!2026 年版 AI 行业深度解析:不用焦虑,普通人零基础也能入局大模型赛道