文档 Loader
🎯 学习目标
- 为 PDF、Markdown、Web、Git 等来源选择合适的 Loader
- 理解 Document 的 page_content 与 metadata 契约
- 在加载阶段做清洗、去噪与权限标签
- 避免 Loader 阶段丢失引用所需的页码与路径信息
引言
RAG 质量上限往往在「进索引之前」就定了。Loader 负责把世界里的 messy 文件变成统一的 Document 流。本节强调:加载不是简单 readFile,而是提取、清洗、打 metadata 的第一步治理。
章节正文
第 1 步:Document 对象契约
from dataclasses import dataclass
@dataclass
class Document:
page_content: str
metadata: dict # source, page, title, updated_at, acl, ...LangChain 等框架的 Document 同构。后续 Splitter、Vector Store 都依赖这份契约。source 必须是稳定 ID(如 repo 相对路径 + commit),而非临时绝对路径。
第 2 步:常见 Loader 选型
| 来源 | 工具/方式 | 注意点 |
|---|---|---|
| 本地 Markdown/TXT | DirectoryLoader | 编码 UTF-8、忽略 node_modules |
| PyPDF / pdfplumber / Unstructured | 扫描件要 OCR;表格易乱 | |
| Web | HTTP + Readability / Trafilatura | 去导航、广告、cookie 横幅 |
| GitHub | GitLoader / API | rate limit、私有库 token |
| 数据库 | SQL → row 文本化 | PII 脱敏后再索引 |
PDF 与 Web 是「脏数据」重灾区,Loader 后常接清洗函数。
第 3 步:DirectoryLoader 示例
from pathlib import Path
def load_markdown_dir(root: str) -> list[Document]:
docs = []
for path in Path(root).rglob("*.md"):
if any(p in path.parts for p in (".git", "node_modules")):
continue
text = path.read_text(encoding="utf-8")
docs.append(Document(
page_content=text,
metadata={
"source": str(path.relative_to(root)),
"title": path.stem,
"updated_at": path.stat().st_mtime,
},
))
return docs加载后立即统计:文档数、总字符、空文件列表,避免 silent failure。
第 4 步:Web 与 PDF 清洗
def clean_web_text(html: str) -> str:
# 伪代码:抽取 main 正文,去 script/style
text = extract_main_content(html)
text = collapse_whitespace(text)
return text[:100_000] # 单页上限,防异常大页PDF 表格若乱,考虑 Unstructured 的 layout 模式或人工转 Markdown 再索引。宁可慢而干净,不要快而脏。
第 5 步:metadata 与权限标签
企业场景在 metadata 加 acl: ["hr", "manager"],检索时按用户角色 filter:
metadata={"source": "hr/salary-band.md", "acl": ["hr"]}Loader 阶段还可写入 lang、product、version,供 4.6 路由到不同索引。
动手练习
- 实现 load_markdown_dir,对 sample 目录输出文档数与平均长度。
- 找一份含表格的 PDF,对比两种 Loader 提取质量,写 200 字结论。
- 为 Web 页面写 clean 规则列表(至少 5 条要去掉的内容类型)。
- 设计 metadata schema(至少 6 个字段),说明每个字段在检索或展示阶段的用途。
- 模拟 acl 过滤:同一 index,hr 用户能命中 hr/ 文档,guest 不能。
常见问题
Q:要不要在 Loader 里就切 chunk?
通常 Loader 只负责「一篇 logical 文档一个 Document」或「一页 PDF 一个 Document」,切分交给 Splitter(4.4),职责更清晰。超大单文件可在 Loader 按章节预切。
Q:图片里的文字怎么处理?
OCR(Tesseract、云 OCR)转文本再索引;图表若语义关键,可人工 caption 或 multimodal 模型描述后入库,并 metadata 标记 type=figure。
Q:索引代码仓库合适吗?
可以,但代码检索常需 Hybrid(关键词 + 向量)与 path metadata。注意许可证与 secrets 扫描,勿索引 .env。
本节小结
Loader 产出统一 Document + 丰富 metadata,是 RAG 治理的第一道门。选型、清洗、权限标签在此完成,后面才谈切分与向量。