LangChain PDF 处理:从加载到向量库完整流程
一句话概括:PDF 加载 → 文本切割 → 向量化 → 存入向量库,这也是 RAG(检索增强生成)最基础、最核心的前三步,掌握了这三步,就能轻松搭建简单的 PDF 问答系统。
一、第一步:PDF 加载(两种方式,按需选择)
处理 PDF 的第一步,就是把 PDF 里的文本提取出来,LangChain 给我们提供了专门的 PyPDFLoader 工具,操作非常简单,还支持两种加载模式,适配不同大小的 PDF 文件。
(注意这个好像还得额外下载一个处理pdf的包)
1. 核心依赖导入
1 | from langchain_community.document_loaders import PyPDFLoader |
2. 实例化加载器(必传参数说明)
PyPDFLoader 有多个参数,但只有一个是必须传的——PDF 文件路径,其他参数(如密码、提取图片)默认关闭即可,新手不用额外配置。
1 | # 实例化加载器,传入 PDF 文件路径(必填) |
3. 两种加载方式(重点区分)
根据 PDF 文件大小选择对应的加载方式,避免内存溢出(OOM),这是新手最容易忽略的点!
方式1:普通加载(load())—— 适合小文件
直接一次性将整个 PDF 加载到内存,返回一个 Document 对象列表,每一个 Document 对应 PDF 的一页。
1 | # 普通加载,返回 List[Document] |
方式2:懒加载(lazy_load())—— 适合大文件
采用生成器模式,按需读取每一页,不会一次性占用大量内存,避免大文件加载时出现 OOM 错误,推荐处理大 PDF 时优先使用。
1 | # 懒加载,返回生成器,按需读取 |
关键补充:Document 对象是什么?
不管哪种加载方式,最终得到的都是 Document 对象(或其列表),它是 LangChain 统一的文本载体,结构非常简单,包含两个核心部分:
1 | Document( |
这个 Document 列表非常重要,后续的文本切割、向量化,都需要用到它!
二、第二步:文本切割(
加载后的 PDF 文本通常很长(比如一页几百上千字),如果直接进行向量化,会导致两个问题:一是向量检索不精准,二是后续传入大模型时超出上下文窗口。因此,文本切割是必不可少的一步。
新手首选切割工具:RecursiveCharacterTextSplitter,它是 LangChain 最通用、效果最好的文本分割器,能智能按段落、换行、空格切割,不会生硬切断一句话,保证语义连贯。
1. 依赖导入
1 | from langchain_text_splitters import RecursiveCharacterTextSplitter |
2. 实例化分割器(核心参数详解)
分割器有三个核心参数,新手只需关注前两个,第三个参数默认即可,不用额外配置:
1 | # 实例化文本分割器 |
3. 执行切割(得到小块 Document 列表)
调用分割器的 split_documents 方法,传入第一步加载得到的 Document 列表,切割后返回的依然是 List[Document],只是每个 Document 的内容变成了 500 字符左右的小块。
1 | # 切割文本,得到小块 Document 列表 |
新手避坑:为什么必须切割?
- 避免大模型上下文超限:大模型的上下文窗口有限,长文本无法直接传入。
- 提升检索精度:小块文本向量化后,能更精准地匹配用户的查询(比如用户问某个细节,能快速定位到对应的小块)。
- 提高处理速度:小块文本向量化、检索的速度更快,节省时间。
三、第三步:向量化 + 存入向量库(核心步骤)
文本切割完成后,下一步就是将这些小块文本转成计算机能理解的“向量”(一堆数字),然后存入向量库,方便后续进行相似性检索。这一步需要两个核心工具:嵌入模型(负责转向量) 和 向量数据库(负责存向量)。
主播用的组合是:NVIDIAEmbeddings(云端嵌入模型)+ Chroma(本地向量库)
1. 依赖导入
1 | from langchain_community.vectorstores import Chroma |
2. 初始化嵌入模型(NVIDIAEmbeddings)
嵌入模型的作用是将文本(page_content)转成高维向量,这里用 NVIDIA 的云端嵌入模型,需要先获取 API Key(免费申请),然后传入模型参数。
1 | # 初始化 NVIDIA 嵌入模型 |
补充:如果没有 NVIDIA API Key,也可以用本地开源嵌入模型(如 OllamaEmbeddings),后续会单独补充。
3. 向量化 + 存入 Chroma 向量库(最关键一步)
使用 Chroma 的 from_documents 方法,一键完成“向量化 + 存储”,
正确代码
1 | vector_store = Chroma.from_documents( |
避坑:参数名错误
很多人会把参数名写成 embeddings(加 s),这样会直接报错!正确的参数名是 embedding(单数),一定要记牢!
关键补充:vector_store 里到底存了什么?
是一个向量库对象,不是普通的列表或字典,里面每一个小块文本都对应三样东西: 1.元数据(metadata):来源 PDF 路径、页码等信息,方便后续追溯。 2.文本内容(page_content):切割后的小块文本。 3.向量(embedding):文本转成的高维数字数组,计算机就是通过对比这些向量,找到相似的文本。
四、完整可运行代码(整合版)
把上面三步整合起来,就是一份完整的 PDF 处理代码,新手可以直接复制,替换自己的 PDF 路径和 API Key 就能运行:
1 | # 1. 加载 PDF |
五、总结 + 补充要点
梳理到这里,整个 PDF 处理流程就非常清晰了,新手只需记住:
- 加载:用 PyPDFLoader,小文件 load(),大文件 lazy_load(),得到 List[Document]。
- 切割:用 RecursiveCharacterTextSplitter,核心参数 chunk_size 和 chunk_overlap,得到小块 List[Document]。
- 向量化:用 NVIDIAEmbeddings(或本地模型),存入 Chroma,记住参数名是 embedding(单数)。
补充两个问题
1. 为什么要加 persist_directory?
如果不加这个参数,向量库只会存在内存里,程序一重启,之前的向量化结果就全丢了,下次还要重新加载、切割、向量化,非常浪费时间。加了之后,向量库会保存到本地目录,下次直接加载即可。
2. 没有 NVIDIA API Key 怎么办?
可以用本地开源嵌入模型,比如 OllamaEmbeddings,无需 API Key,直接本地运行,替换嵌入模型部分即可:
1 | from langchain_community.embeddings import OllamaEmbeddings |
1 |