系列目标:30 天从 LangChain 入门到企业级部署
今日任务:掌握UnstructuredLoader、PyPDFLoader等核心加载器 → 实现多格式文档统一解析 → 为 RAG 准备高质量文本!
📚 一、为什么需要 Document Loaders?
在构建 RAG(检索增强生成)系统时,第一步永远是:把非结构化数据变成纯文本。
但现实中的知识分散在:
- 📄 PDF 技术手册
- 📝 Word 产品文档
- 🌐 公司官网/Confluence
- 💾 数据库 FAQ 表
- 📧 邮件/会议纪要
手动复制粘贴?不可能!
LangChain 的 Document Loaders 就是“万能读取器” —— 它封装了各种解析逻辑,统一输出为 List[Document] 对象:
from langchain_core.documents import Document
docs = loader.load()
# [Document(page_content="...", metadata={"source": "xxx.pdf", "page": 1}), ...]
✅ 今天,我们就来实测 5 大高频场景的加载器!
🧰 二、必备依赖安装
不同格式需要不同后端库,按需安装:
# 通用(推荐)
pip install unstructured[pdf,docx] # 支持 PDF/Word/PPT 等
# 或单独安装
pip install pypdf # 轻量 PDF
pip install python-docx # Word (.docx)
pip install beautifulsoup4 lxml # 网页 HTML
pip install sqlalchemy # 数据库
💡
unstructured是 LangChain 官方推荐的全能解析库,支持 20+ 格式!
🛠️ 三、实战 1:读取 PDF(技术手册/论文)
方案 A:轻量级(PyPDFLoader)
# day16_document_loaders.py
from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader("docs/ai_whitepaper.pdf")
docs = loader.load()
print(f"共加载 {len(docs)} 页")
print("第1页内容预览:", docs[0].page_content[:100])
✅ 优点:快、轻量
❌ 缺点:不支持扫描版 PDF(图片)
方案 B:全能型(UnstructuredPDFLoader)
from langchain_community.document_loaders import UnstructuredPDFLoader
loader = UnstructuredPDFLoader(
"docs/ai_whitepaper.pdf",
mode="elements", # 保留标题/段落结构
strategy="fast" # fast / hi_res(高精度但慢)
)
docs = loader.load()
💡 支持表格、图片 OCR(需额外安装
unstructured[local-inference])
🛠️ 四、实战 2:读取 Word 文档(.docx)
from langchain_community.document_loaders import Docx2txtLoader
loader = Docx2txtLoader("docs/product_spec.docx")
docs = loader.load()
print("Word 文档内容:", docs[0].page_content[:100])
⚠️ 注意:仅支持
.docx,不支持旧版.doc(需转格式)
🛠️ 五、实战 3:抓取网页内容(去广告+正文提取)
from langchain_community.document_loaders import WebBaseLoader
# 自动去除导航栏、广告,提取正文
loader = WebBaseLoader(
web_paths=["https://example.com/blog/ai-trends"],
bs_kwargs=dict(parse_only=...) # 可选:指定 HTML 标签
)
docs = loader.load()
print("网页标题:", docs[0].metadata.get("title"))
print("正文预览:", docs[0].page_content[:100])
✅ 内部使用
BeautifulSoup+trafilatura,智能提取正文!
🛠️ 六、实战 4:读取数据库记录(FAQ 表)
假设你有 MySQL/PostgreSQL 中的 faq 表:
表格
| id | question | answer |
|---|---|---|
| 1 | 如何退货? | 请登录... |
from langchain_community.document_loaders import SQLDatabaseLoader
from langchain_community.utilities import SQLDatabase
# 连接数据库(示例为 SQLite)
db = SQLDatabase.from_uri("sqlite:///company.db")
# 加载 faq 表,拼接 question + answer
loader = SQLDatabaseLoader(
query="SELECT question || ' ' || answer AS content FROM faq",
db=db
)
docs = loader.load()
print("FAQ 条目数:", len(docs))
💡 适用于将结构化数据注入 RAG 知识库!
🛠️ 七、实战 5:批量加载整个目录(混合格式)
from langchain_community.document_loaders import DirectoryLoader
# 自动根据扩展名选择加载器
loader = DirectoryLoader(
"knowledge_base/",
glob="**/*.pdf", # 只加载 PDF
show_progress=True, # 显示进度条
use_multithreading=True # 多线程加速
)
docs = loader.load()
print(f"共加载 {len(docs)} 个文档片段")
🔍 支持 glob 模式:
*.docx,**/*.html等
🧹 八、后处理:清洗与分块(为向量化准备)
加载后的文本通常需要清洗:
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 1. 去除多余空白
cleaned_docs = [
Document(page_content=doc.page_content.replace("\n\n", "\n").strip(), metadata=doc.metadata)
for doc in docs
]
# 2. 分块(RAG 必需)
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
separators=["\n\n", "\n", "。", "!", "?", ";", " ", ""]
)
chunks = text_splitter.split_documents(cleaned_docs)
print(f"分块后:{len(chunks)} 个片段")
✅ 合理分块是 RAG 效果的关键!
⚠️ 九、注意事项 & 最佳实践
表格
| 问题 | 建议 |
|---|---|
| PDF 解析乱码 | 指定 encoding="utf-8";或用 Unstructured 的 hi_res 模式 |
| 网页加载超时 | 设置 requests_per_second 限速;加 retry |
| Word 表格丢失 | 用 unstructured 替代 docx2txt |
| 数据库敏感信息 | 在 SQL 查询中脱敏,勿直接 SELECT * |
| 内存爆炸 | 对大目录使用 yield_per 分批加载 |
💡 生产建议:
- 建立文档预处理流水线(加载 → 清洗 → 分块 → 向量化)
- 记录每个 chunk 的
source和page,便于溯源
📦 十、配套代码结构
langchain-30-days/
└── day16/
├── document_loaders_demo.py # PDF/Word/网页/数据库加载示例
└── knowledge_base/ # 测试文档目录
├── manual.pdf
└── spec.docx
📝 十一、今日小结
- ✅ 理解了 Document Loaders 在 RAG 中的基础作用
- ✅ 掌握了 PDF、Word、网页、数据库四大场景的加载方法
- ✅ 学会了用
DirectoryLoader批量处理混合格式 - ✅ 实践了文本清洗与智能分块
- ✅ 知道了各加载器的优缺点与适用边界
🎯 明日预告:Day 17 —— 向量存储入门!用 Chroma 构建本地向量数据库,实现语义检索!