Загрузка и разбиение документов в LangChain

В предыдущих статьях мы вводили текст вручную, но в реальных проектах документы могут поступать из PDF, веб-страниц, файлов Markdown и т. д.

В этом разделе рассказывается, как использовать Document Loader для загрузки документов различных типов и как использовать Text Splitter для разбиения документов на небольшие фрагменты, подходящие для поиска.


Document Loader — загрузка документов

LangChain предоставляет десятки загрузчиков документов, охватывающих распространённые форматы файлов:

ЗагрузчикSourceУстановочный пакет
TextLoaderфайлы .txtlangchain (встроенный)
PyPDFLoaderPDF-файлыlangchain-community + pypdf
WebBaseLoaderURL веб-страницыlangchain-community + beautifulsoup4
CSVLoaderCSV-файлыlangchain-community
UnstructuredMarkdownLoaderMarkdown-файлыlangchain-community + unstructured

Пример

# Загрузить текстовый файл (встроенный, дополнительная установка не требуется)
from langchain_community.document_loaders import TextLoader

loader = TextLoader("knowledge.txt", encoding="utf-8")
docs = loader.load()

print(f"Загружено {len(docs)} документов")
print(f"Предварительный просмотр содержимого: {docs)

# Загрузить веб-страницу
# pip install langchain-community beautifulsoup4
from langchain_community.document_loaders import WebBaseLoader

loader = WebBaseLoader("https://www.example.com/python/python-tutorial.html")
docs = loader.load()
print(f"\nСодержимое веб-страницы: {docs)

Разделитель текста — разделение документов

Документы обычно слишком длинные, и их нужно разбивать на небольшие фрагменты для эффективного извлечения. Стратегия разбиения напрямую влияет на производительность RAG:

Пример

from langchain_text_splitters import RecursiveCharacterTextSplitter

# Создать разделитель
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,         # Максимум 500 символов на фрагмент
    chunk_overlap=50,       # Перекрытие 50 символов между фрагментами
    separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""],
    # Сначала разбить по абзацам, затем по предложениям и наконец по символам
)

# Пример документа
long_text = """Example Tutorial (EXAMPLE) — бесплатная платформа для изучения программирования.

Платформа предоставляет богатый набор учебных пособий по языкам программирования, включая, помимо прочего:
- Учебник по Python: от базового синтаксиса до анализа данных
- Учебник по Java: от объектно-ориентированного программирования до фреймворка Spring
- Учебник по фронтенду: HTML, CSS, JavaScript и их фреймворки

Все учебники сопровождаются подробными примерами кода и онлайн-средой выполнения.
Учащиеся могут быстро освоить навыки программирования, обучаясь на практике."""


# Разделить документ
chunks = text_splitter.split_text(long_text)

print(f"Оригинальная длина: {len(long_text)} символов")
print(f"После разделения: {len(chunks)} фрагментов\n")

for i, chunk in enumerate(chunks):
    print(f"--- Фрагмент {i+1} ({len(chunk)} символов) ---")
    print(chunk)
    print()

Результат выполнения:

Original length: 153 字
Chunks after split: 3 块

--- 块 1 (54 字) ---
Example is a free programming learning platform.
平台提供了丰富的编程语言教程,包括但不限于:

--- 块 2 (49 字) ---
- Python 教程:从基础语法到数据分析
- Java 教程:面向对象编程到 Spring 框架

--- 块 3 (50 字) ---
- 前端教程:HTML、CSS、JavaScript 及其框架
所有教程都配有详细的代码示例和在线运行环境。

chunk_overlap очень важен. Если между фрагментами нет перекрытия, полное предложение может быть разбито пополам, из-за чего ключевая информация может быть пропущена при поиске. Перекрытие в 50-100 символов — обычная настройка.


Руководство по настройке параметров разбиения на фрагменты

Сценарийchunk_sizechunk_overlapПричина
FAQ: вопросы и ответы200~50020~50Пары вопрос-ответ короткие, достаточно небольших фрагментов
Техническая документация500~100050~100Технический контент требует больше контекста
Длинные статьи/научные работы1000~2000100~200Нужно сохранить целостность абзацев
Репозиторий кода500~15000~50Функции/классы как естественные границы

Полный поток: Загрузка → Разделение → Векторизация

Пример

from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma
# from langchain_community.document_loaders import TextLoader


# Шаг 1: Загрузка
# loader = TextLoader("example_knowledge.txt", encoding="utf-8")
# docs = loader.load()

# Для демонстрации напрямую используем пример текста
docs = [
    "Example Tutorial (EXAMPLE) — это бесплатный сайт для изучения программирования.",
    "Сайт предоставляет руководства по нескольким языкам программирования, таким как Python, Java и HTML.",
    "Базовое руководство по Python3 содержит 30 глав и подходит для начинающих с нуля.",
    "Базовое руководство по HTML содержит 25 глав, включая формы, мультимедиа и многое другое.",
    "Все базовые руководства на Example бесплатны.",
]

# Шаг 2: Разделение
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=100,
    chunk_overlap=20,
)
chunks = text_splitter.create_documents(docs)

# Шаг 3: Векторизация и сохранение
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vector_store = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./example_db",
)

print(f"Индекс построен: {len(chunks)} фрагментов документов")

# Шаг 4: Извлечение
results = vector_store.similarity_search("Сколько глав в руководстве по Python?", k=2)
for doc in results:
    print(f"Результат поиска: {doc.page_content}")

Результат выполнения:

Index built:5 个文档块
Search result: Python3 基础教程共 30 章,适合零基础入门学习。
Search result: Example is a free programming learning website.
Другие расширения