LangChainJuniorTechnical

Что такое document loader в LangChain и как работают text splitters (RecursiveCharacterTextSplitter)?

Document Loader загружает данные в список Document(page_content, metadata). RecursiveCharacterTextSplitter делит текст рекурсивно по ["\n\n", "\n", " "], с настраиваемым chunk_size и chunk_overlap; для точного соответствия лимитам LLM используют tiktoken-счётчик.

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

Document Loader загружает данные из источника и возвращает список объектов Document(page_content: str, metadata: dict). Все лоадеры реализуют метод load() (или lazy_load() для больших файлов).

from langchain_community.document_loaders import (
    TextLoader,
    PyPDFLoader,
    WebBaseLoader,
    CSVLoader,
)

# Загрузка текстового файла
loader = TextLoader("readme.txt", encoding="utf-8")
docs = loader.load()
print(docs[0].page_content[:100])
print(docs[0].metadata)  # {'source': 'readme.txt'}

# Загрузка PDF (каждая страница = отдельный Document)
pdf_loader = PyPDFLoader("report.pdf")
pdf_docs = pdf_loader.load()  # len == кол-во страниц

# Ленивая загрузка большого CSV
csv_loader = CSVLoader("data.csv", encoding="utf-8")
for doc in csv_loader.lazy_load():
    print(doc.page_content[:80])

RecursiveCharacterTextSplitter — рекурсивное разбиение

RecursiveCharacterTextSplitter — рекомендуемый по умолчанию сплиттер. Пробует разбить по ["\n\n", "\n", " ", ""] — от крупных структур (абзацы) к символам.

from langchain_text_splitters import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,       # максимальный размер чанка в символах
    chunk_overlap=200,     # перекрытие между чанками (сохраняет контекст)
    separators=["\n\n", "\n", ". ", " ", ""],  # порядок разделителей
    length_function=len,   # можно заменить на tiktoken-счётчик токенов
)

text = """Первый абзац текста.\n\nВторой абзац.
Продолжение второго абзаца. Ещё предложение."""

chunks = splitter.split_text(text)
print(len(chunks), chunks[0])

# Разбиение загруженных Document-объектов
from langchain_community.document_loaders import TextLoader
loader = TextLoader("big_doc.txt")
docs = loader.load()
split_docs = splitter.split_documents(docs)
# metadata['source'] и metadata['start_index'] сохраняются

Счётчик токенов вместо символов

import tiktoken
from langchain_text_splitters import RecursiveCharacterTextSplitter

enc = tiktoken.encoding_for_model("gpt-4o")

def tiktoken_len(text: str) -> int:
    return len(enc.encode(text))

splitter = RecursiveCharacterTextSplitter(
    chunk_size=512,        # токены, а не символы
    chunk_overlap=50,
    length_function=tiktoken_len,
)

Специализированные сплиттеры

  • CharacterTextSplitter — разбивает строго по одному разделителю (например, "\n\n").
  • MarkdownHeaderTextSplitter — сохраняет структуру заголовков в metadata.
  • HTMLHeaderTextSplitter — разбивает по тегам <h1><h4>.
  • SemanticChunker (langchain-experimental) — разбивает по семантическому сходству эмбеддингов.

Подводные камни

  • chunk_overlap=0 теряет контекст на границах — факты, начатые в конце одного чанка, не попадут в следующий; рекомендуется 10–20% от chunk_size.
  • Счётчик по символам (len) и по токенам (tiktoken) дают разные размеры — для GPT-моделей с контекстным лимитом в токенах нужен tiktoken.
  • PyPDFLoader плохо обрабатывает колоночный PDF и таблицы — для сложных PDF используйте UnstructuredPDFLoader или PDFMinerLoader.
  • WebBaseLoader парсит HTML через BeautifulSoup — теги, скрипты и стили попадают в page_content, если не настроить bs_kwargs.
  • lazy_load() не поддерживается всеми лоадерами — проверяйте, иначе получите NotImplementedError в runtime.
  • metadata['source'] из лоадера теряется, если вызывать split_text() вместо split_documents() — используйте второй метод для сохранения источника.
  • Слишком маленький chunk_size (< 200 символов) приводит к потере контекста в ответах RAG и росту числа чанков, что замедляет retrieval.

Common mistakes

  • Объяснять document loaders splitters только синтаксисом без shape, dtype, состояния или режима выполнения.
  • Игнорировать leakage, воспроизводимость, пустые входы и скрытые копии данных.
  • Не проверять production-симптомы: latency, память, ретраи, дрейф качества и несовпадение версий.

What the interviewer is testing

  • Может ли связать document loaders splitters с реальным контрактом входов и выходов.
  • Упоминает ли тесты, метрики, reproducibility и диагностику ошибок.
  • Видит ли различие между demo-кодом в ноутбуке и production-пайплайном.

Sources

Related topics