LangChain:数据增强之加载器-Loader

LangChain框架中的Loader组件是数据增强处理流程中的核心模块,负责将不同格式的数据源转换为统一的Document对象。这些文档对象包含文本内容(page_content)和元数据(metadata),为后续的文本处理、嵌入、问答等操作奠定基础。

加载器(Loader)是数据增强流程的起点,负责将多源数据加载为文档(包含文本内容和元数据),支持本地文件(PDF、CSV、HTML)、数据库、网页、API等内容。

LangChain内部已提供的加载器:

  • 使用AsyncChromiumLoader加载动态网页,结合BeautifulSoupTransformer提取特定HTML标签内容。
  • 通过CSVLoaderWebBaseLoader加载结构化或非结构化数据。

官方:LangChain > document-loaders

Document loaders

Document Loaders are responsible for loading documents from a variety of sources.

核心作用

  1. 多格式支持:支持 PDF、Markdown、HTML、代码文件、Notion、Discord 等格式。
  2. 数据标准化:将PDF、HTML、CSV等异构数据统一转换为结构化文档对象,便于后续处理(如文本分割、向量化等)。
  3. 结构化处理:自动解析文档结构(如章节标题、表格、代码块)。
  4. 元数据保留:自动提取来源、创建时间等元信息,增强检索和溯源能力。
  5. 扩展性:支持自定义加载器,适配私有数据源(如数据库、API等)。
  6. 性能优化:部分加载器实现懒加载或分块读取,适合处理大文件。
  7. 预处理集成:与文本分割器(Text Splitter)、向量化工具无缝衔接。

组件解析

  1. 加载器目录

    LangChain 核心内部和LangChain社区包分别提供了不同的加载器(Loader)。

    • LangChain 核心包加载器目录:langchain_core.document_loaders,已过时。
    • Langchain 社区包加载器目录:langchain_community.document_loaders。
  2. 核心接口BaseLoader

    加载器提供了 load() 方法,用于从指定的数据源读取数据;还提供了一个 **lazy_load()**方法,用于实现数据的懒加载,即在需要时才将数据加载到内存中,这样可以有效地减少内存占用,并提高数据的处理效率。

    1
    2
    3
    4
    5
    6
    7
    class BaseLoader(ABC):
    @abstractmethod
    def load(self) -> list[Document]:
    """将原始数据转换为Document对象列表"""

    def lazy_load(self) -> Iterator[Document]:
    """实现流式加载的迭代器"""
  3. Document对象结构

    1
    2
    3
    class Document:
    page_content: str # 文本内容
    metadata: dict # 包含来源、创建时间等元数据

分类与示例

文本加载器

TextLoader:用于加载普通的文本文件(如 .txt 文件)。

1
2
3
4
5
6
from langchain_community.document_loaders import TextLoader

# 加载文本文件
loader = TextLoader('example.txt')
documents = loader.load()
print("TextLoader:" + documents.__str__())

输出

1
TextLoader:[Document(metadata={'source': 'example.txt'}, page_content='Hello World!')]

PDF加载器

LangChain > How to load PDFs

安装依赖

1
pip install -qU pypdf

PyPDFLoader

PyPDFLoader:可加载PDF文件,提取其中的文本内容。

1
2
3
4
5
6
from langchain_community.document_loaders import PyPDFLoader

# 加载PDF文件
loader = PyPDFLoader(file_path="example.pdf")
document = loader.load()
print("PyPDFLoader:" + document.__str__())

输出

1
2
PyPDFLoader:[Document(metadata={'producer': 'Typora', 'creator': 'Typora', 'creationdate': '20250426165647', 'moddate': '20250426165647', 'source': 'file/example.pdf', 'total_pages': 1, 'page': 0, 'page_label': '1'}, page_content='PDF File Example')]

异步调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from langchain_community.document_loaders import PyPDFLoader
import asyncio

# 加载PDF文件
loader = PyPDFLoader(file_path="file/example.pdf")

async def load_pages():
pages = []
async for page in loader.alazy_load():
pages.append(page)
print(f"{pages[0].metadata}\n")
print(pages[0].page_content)
return pages

# Run the async function
asyncio.run(load_pages())

结果输出

1
2
3
{'producer': 'Typora', 'creator': 'Typora', 'creationdate': '20250426165647', 'moddate': '20250426165647', 'source': 'file/example.pdf', 'total_pages': 1, 'page': 0, 'page_label': '1'}

PDF File Example

CSV/Excel加载器

CSVLoader:CSV/Excel文件加载器

CSV:逗号分隔值(Comma-Separated Values,CSV)文件使用逗号来分隔值的文本文件。文件的每一行都是一条数据记录,每条记录包含一个或多个用逗号分隔的字段。LangChain 将CSV文件的每一行都视为一个独立的文档。

1
2
3
4
5
from langchain_community.document_loaders import CSVLoader

loader = CSVLoader("data.csv")
documents = loader.load() # 每行作为独立文档,保留列名作为元数据
print(documents[0])

每个Document对象代表CSV文件的一行,CSV文件的每一行都被转换为键值对象,并输出到 Document 对象的 page_content 中。

输出结果如下:

1
2
3
page_content='姓名: 张三
年龄: 22
手机号: 13612345678' metadata={'source': './file/data.csv', 'row': 0}

Web网页加载器

安装依赖

1
2
pip install -qU langchain-community beautifulsoup4
pip install -qU langchain-unstructured

WebBaseLoader:用于从网页上抓取文本内容。

1
2
3
4
5
6
# 加载网页内容
from langchain_community.document_loaders import WebBaseLoader

loader = WebBaseLoader(web_path="https://www.deepseek.com/", encoding="utf-8")
data = loader.load()
print("WebBaseLoader:" + data.__str__())

电子邮件加载器

UnstructuredEmailLoader:支持加载电子邮件文件(如 .eml 文件)。

1
2
3
4
5
6
from langchain.document_loaders import UnstructuredEmailLoader

# 加载电子邮件文件
loader = UnstructuredEmailLoader('example.eml')
data = loader.load()

目录加载器

DirectoryLoader:目录加载器

1
2
3
4
5
6
7
from langchain.document_loaders import DirectoryLoader
from langchain.document_loaders import TextLoader

# 加载指定目录下的所有文本文件
loader = DirectoryLoader('./data', glob="**/*.txt", loader_cls=TextLoader)
documents = loader.load()

代码仓库加载器

GitLoader:基于Git仓库加载

1
2
3
4
5
6
7
8
9
10
from langchain.document_loaders import GitLoader

# 克隆或加载本地仓库
loader = GitLoader(
clone_url="https://github.com/username/repo.git",
repo_path="./local_repo", # 本地存储路径
branch="main", # 指定分支
file_filter=lambda file_path: file_path.endswith(".py") # 仅加载.py文件
)
documents = loader.load() # 每个代码文件转为Document对象

加载特定目录

1
2
3
4
loader = GitLoader(
repo_path="./local_repo",
file_filter=lambda file_path: file_path.startswith("src/core/") # 仅加载src/core目录
)

元数据增强:加载时会自动生成元数据

1
2
3
4
5
{
"source": "repo/src/utils.py", # 文件路径
"commit_hash": "a1b2c3d", # 最后一次提交hash
"file_type": "python" # 文件类型
}

自定义处理(如忽略测试文件)

1
2
3
4
5
6
7
def file_filter(file_path: str) -> bool:
return (
file_path.endswith(".py")
and "test/" not in file_path # 排除测试目录
)

loader = GitLoader(repo_path="./local_repo", file_filter=file_filter)

从本地已有仓库加载(无需克隆)

1
2
3
4
loader = GitLoader(
repo_path="/existing/repo/path",
branch="dev"
)

关键特性说明:
增量加载:支持通过lazy_load()迭代处理大仓库
二进制文件:默认跳过二进制文件(可通过file_filter调整)
依赖项:需预先安装gitpython包:

1
pip install gitpython

数据库加载器

1
2
3
4
5
6
7
8
9
10
11
12
13
from langchain.document_loaders import SQLDatabaseLoader
from sqlalchemy import create_engine

# 创建数据库连接
engine = create_engine("mysql+pymysql://user:password@localhost:3306/dbname")

# 加载articles表数据
loader = SQLDatabaseLoader(
engine,
"SELECT id, title, content FROM articles WHERE status = 'published';",
metadata_columns=["id", "title"] # 将id和title存入元数据
)
documents = loader.load() # 每行数据转为Document对象

带分页大表加载

1
2
3
4
5
6
7
8
9
10
loader = SQLDatabaseLoader(
engine,
"SELECT * FROM large_table",
page_size=500, # 每次加载500条
metadata_columns=["create_time"]
)

# 使用懒加载迭代处理
for doc in loader.lazy_load():
process_document(doc)

加载关联表数据

1
2
3
4
5
6
query = """
SELECT p.id, p.title, p.content, u.username as author
FROM posts p
JOIN users u ON p.user_id = u.id
"""
loader = SQLDatabaseLoader(engine, query)

依赖安装

1
pip install sqlalchemy pymysql

特别说明
复杂查询建议在SQL中完成JOIN和过滤,比加载后处理更高效
敏感字段(如密码)应避免在metadata_columns中指定
支持所有SQLAlchemy兼容的数据库(PostgreSQL/Oracle等)

Notion 数据库加载器

示例:获取网页特定标签内容

1
2
3
4
5
6
7
from langchain_community.document_loaders import AsyncChromiumLoader
from langchain_community.document_transformers import BeautifulSoupTransformer

loader = AsyncChromiumLoader(["https://example.com"])
html = loader.load()
# 提取特定标签内容
docs_transformed = BeautifulSoupTransformer().transform_documents(html, tags_to_extract=["p", "span"])

自定义JSON加载器

1
2
3
4
5
6
7
8
from langchain.document_loaders import JSONLoader

loader = JSONLoader(
file_path="data.json",
jq_schema=".items[]", # 使用jq语法指定提取路径
content_key="text" # 指定内容字段
)
documents = loader.load()

自定义加载器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from langchain.schema import Document
from langchain.document_loaders.base import BaseLoader

class CustomDBLoader(BaseLoader):
def __init__(self, connection_str: str):
self.conn = connect_db(connection_str)

def load(self) -> List[Document]:
records = self.conn.query("SELECT * FROM docs")
return [
Document(
page_content=record.content,
metadata={"source": record.id}
) for record in records
]

非结构化文件加载器

官方文档:LangChain > UnstructuredSupported file types

加载非结构化文件,必须先安装依赖,否则可能会报错,例如:UnstructuredMarkdownLoader resulting in zipfile.BadZipFile: File is not a zip file

依赖安装

1
2
3
import nltk
nltk.download('punkt')
nltk.download('averaged_perceptron_tagger')

安装完后,再次运行程序,若问题仍存在,执行下面的代码

1
2
import nltk
nltk.download('all')

Markdown加载器

MarkdownLoader:专门用于加载Markdown格式的文件(如 .md 文件)。

Markdown 是非结构化文件,需先添加非结构化依赖库。

1
2
3
pip install markdown
pip install unstructured
pip install "unstructured[md]"

使用示例

1
2
3
4
5
6
from langchain_community.document_loaders import UnstructuredMarkdownLoader

# 加载Markdown文件
markdown_loader = UnstructuredMarkdownLoader("file/example.md")
markdown_data = markdown_loader.load()
print("MarkdownLoader:" + markdown_data.__str__())

输出

1
MarkdownLoader:[Document(metadata={'source': 'file/example.md'}, page_content='Level1\n\nLevel2\n\nLevel3\n\nTitle\n\npython Hello World!')]

HTML加载器

1
2
3
4
5
6
7
8
# 加载网页内容
from langchain_community.document_loaders import UnstructuredHTMLLoader

loader = UnstructuredHTMLLoader(
"file/example.html", mode="elements", strategy="fast",
)
document = loader.load()
print("UnstructuredHTMLLoader:" + document.__str__())

输出

1
UnstructuredHTMLLoader:[Document(metadata={'source': 'file/example.html', 'category_depth': 0, 'last_modified': '2025-04-26T20:21:53', 'languages': ['eng'], 'file_directory': 'file', 'filename': 'example.html', 'filetype': 'text/html', 'category': 'Title', 'element_id': '735dd56e06edeaa528f67f8ee4f43d76'}, page_content='Hello World')]

最佳实践建议

  1. 统一元数据规范:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    class StandardLoader(CSVLoader):
    def load(self) -> List[Document]:
    base_docs = super().load()
    for doc in base_docs:
    doc.metadata.update({
    "format_version": "1.0",
    "processing_time": datetime.now().isoformat()
    })
    return base_docs
  2. 异常处理策略:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    from langchain.document_loaders import UnstructuredPowerPointLoader

    try:
    loader = UnstructuredPowerPointLoader("presentation.pptx")
    slides = loader.load()
    except UnstructuredParserError as e:
    handle_corrupted_file(e)
    except FileNotFoundError:
    logging.error("File path invalid")

通过合理选择Loader组件并配置优化参数,开发者可以高效处理各类数据源。建议根据具体场景组合使用不同Loader,并结合LangChain的文本分割、向量化组件构建完整的数据处理流水线。对于特殊格式需求,可通过继承BaseLoader实现定制化加载逻辑。

加载器组件是LangChain框架中数据输入的重要环节,它能够适配多种数据源,帮助开发者将不同格式的数据转换为统一的文档对象,方便后续进行文本处理和分析。根据不同的数据源类型,选择合适的加载器可以提高数据加载的效率和准确性。

高级用法
并发加载:部分加载器支持多线程(如AsyncHtmlLoader)
增量加载:通过lazy_load()方法实现流式处理
元数据增强:可在加载后添加自定义元数据字段
通过组合不同Loader,可以构建复杂的数据管道,例如先加载PDF中的表格,再用CSV解析器处理表格内容。

作者

光星

发布于

2025-04-23

更新于

2025-04-27

许可协议

评论