LangChain 基础系列之文档加载与分割详解:从非结构化数据到知识图谱的关键一步
引言:当大模型遇到非结构化数据
在构建智能问答系统、企业知识库或自动化文档处理流程时,我们往往需要将 PDF、Word、Markdown 等非结构化文档转化为大模型可处理的格式。LangChain 作为连接大模型与外部数据的桥梁,其文档加载与分割模块正是解决这一问题的核心组件。本文将从技术实现和工程实践两个维度,深度解析 LangChain 处理文档的全流程。
一、文档加载:支持全格式数据接入
1. 基础文档加载器矩阵
LangChain 通过langchain.document_loaders
模块提供了丰富的加载器实现:
文档类型 | 加载器类 | 核心参数 | 适用场景 |
---|---|---|---|
纯文本 | TextLoader | file_path , encoding | 日志文件、配置文件处理 |
PyPDFLoader | file_path , password | 学术论文、财报解析 | |
Markdown | MarkdownLoader | file_path , mode | 技术文档、博客内容提取 |
Word | Docx2txtLoader | file_path | 办公文档结构化处理 |
网页 | BeautifulSoupLoader | url , parser | 网络信息抓取 |
代码示例:多格式加载器组合使用
from langchain.document_loaders import PyPDFLoader, MarkdownLoader, TextLoader
# 混合加载不同格式文档
pdf_docs = PyPDFLoader("report.pdf").load()
md_docs = MarkdownLoader("guide.md").load()
txt_docs = TextLoader("data.txt", encoding="utf-8").load()
all_docs = pdf_docs + md_docs + txt_docs
2. 进阶加载器扩展
二进制文件处理:通过BinaryFileLoader
实现自定义解析逻辑
压缩文件处理:使用ZIPLoader
直接加载压缩包内文档
远程文件加载:支持 HTTP/HTTPS 协议的WebBaseLoader
二、文档分割:精细化处理的核心逻辑
1. 基础分割策略对比
(1)按字符分割
from langchain.text_splitter import CharacterTextSplitter
splitter = CharacterTextSplitter(
chunk_size=1000,
chunk_overlap=100,
length_function=len
)
chunks = splitter.split_documents(all_docs)
适用场景:纯文本且格式简单的场景,如日志文件
(2)按句子分割
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
separators=["\n\n", "\n", " ", ""]
)
chunks = splitter.split_documents(all_docs)
智能策略:优先在段落、句子边界分割,保持语义完整性
(3)按结构分割(针对 Markdown/PDF)
from langchain.text_splitter import MarkdownTextSplitter
splitter = MarkdownTextSplitter(
chunk_size=1000,
heading_level=2 # 基于二级标题分割
)
chunks = splitter.split_documents(md_docs)
2. 分割参数调优要点
参数名称 | 作用描述 | 推荐值范围 |
---|---|---|
chunk_size | 单块最大字符数 | 500-2000(根据模型上下文调整) |
chunk_overlap | 相邻块重叠字符数 | 50-200(保证语义连续性) |
separators | 分割优先级列表(从高到低) | [段落分隔符,句子分隔符,空格] |
三、实战案例:构建技术文档知识库
1. 需求场景
某开源项目需要将官方文档(包含 PDF 指南和 Markdown API 文档)接入问答系统,要求:
保留文档原始结构(标题、代码块)
支持按技术模块(如 API 章节)分割
处理公式和特殊符号
2. 解决方案
(1)加载阶段
# 自定义PDF加载器(保留公式)
class FormulaPDFLoader(PyPDFLoader):
def load(self) -> List[Document]:
docs = super().load()
for doc in docs:
doc.metadata["source"] = self.file_path
# 修复LaTeX公式解析问题
doc.page_content = doc.page_content.replace(r"\\(", "\$\$").replace(r"\\)", "\$\$")
return docs
# 加载Markdown并保留标题层级
md_loader = MarkdownLoader("api_docs.md", mode="html")
(2)分割阶段
# 组合分割策略
splitter = RecursiveCharacterTextSplitter(
chunk_size=800,
separators=[
"\n## ", # Markdown二级标题
"\n### ", # 三级标题
"\n#### ",
"\n\n", "\n", " "
]
)
# 执行分割并添加元数据
chunks = splitter.split_documents([pdf_docs, md_docs])
for i, chunk in enumerate(chunks):
chunk.metadata["chunk_id"] = f"section-{i}"
chunk.metadata["source_type"] = "technical_doc"
四、工程实践中的注意事项
1. 大文档处理优化
流式加载:使用Streamlit
实现分段加载进度显示
内存管理:通过Document
对象的page_content
和metadata
控制内存占用
增量处理:记录已处理文档哈希,避免重复加载
2. 常见问题解决方案
问题现象 | 原因分析 | 解决方法 |
---|---|---|
PDF 中文乱码 | 字体缺失 | 使用PyMuPDFLoader 替代PyPDFLoader |
Markdown 表格丢失 | 解析器不支持 | 启用MarkdownTableLoader 扩展 |
分割后语义断裂 | 分隔符优先级错误 | 调整separators 顺序 |
元数据丢失 | 加载器未设置 | 自定义加载器时添加metadata |
五、最佳实践:从分割到向量存储的完整链路
结语:解锁非结构化数据的智能处理能力
文档加载与分割作为 LangChain 数据处理 pipeline 的起点,其处理效果直接影响后续检索、问答的准确性。通过合理选择加载器、优化分割策略,并结合具体业务场景进行定制化开发,我们能够高效地将海量非结构化数据转化为可被大模型理解的知识单元。