Чанкинг документов

Материал из llmdocs — справочник разработчика
Чанкинг документов
ПрименениеRAG, семантический поиск, суммаризация длинных текстов
Типичный размер200–1000 токенов
Перекрытие10–20% от размера чанка
Стратегиификсированная длина, рекурсивная, по структуре, семантическая
ИнструментыLangChain text splitters, LlamaIndex node parsers, Unstructured, Docling

Чанкинг (англ. chunking) — разбиение документов на небольшие фрагменты, чанки, которые затем по отдельности индексируются и находятся поиском. Это первый и один из самых влиятельных этапов в системах RAG: модель отвечает на основе найденных чанков, и если нужный факт разрезан пополам или утонул в слишком большом фрагменте, качество ответа падает независимо от того, насколько хороша сама языковая модель.[4]

Зачем разбивать

  • Точность поиска. Эмбеддинг длинного текста усредняет много тем и плохо совпадает с конкретным вопросом; эмбеддинг короткого фрагмента выражает одну мысль.
  • Ограничения моделей. У моделей эмбеддингов есть предел входа (часто 512–8192 токенов), а контекстное окно генератора не безгранично и стоит денег.
  • Цитирование. Маленький фрагмент можно показать пользователю как источник ответа.

Противоположная крайность — слишком мелкие чанки: они теряют контекст («он», «этот метод», «см. выше») и не содержат полного ответа. Выбор размера — компромисс между точностью поиска и полнотой фрагмента.

Стратегии

Стратегия Как режет Плюсы и минусы
Фиксированная длина каждые N символов или токенов просто, но рвёт предложения
Рекурсивная по абзацам, затем предложениям, затем словам — пока кусок не влезет хороший вариант по умолчанию
По структуре по заголовкам Markdown или HTML, функциям в коде, строкам таблицы сохраняет смысловые границы
Семантическая там, где резко меняется смысл соседних предложений по эмбеддингам дороже, выигрыш нестабилен
Агентная / LLM модель сама выделяет смысловые блоки качественно, но медленно и дорого

Рекурсивный разделитель — стандарт в библиотеках LangChain и LlamaIndex.[1][2] Для документации и вики лучше всего работает разбиение по структуре: раздел с заголовком — естественная единица смысла.

from langchain_text_splitters import (MarkdownHeaderTextSplitter,
                                      RecursiveCharacterTextSplitter)

md = open("tls.md").read()
by_headers = MarkdownHeaderTextSplitter(
    headers_to_split_on=[("#", "h1"), ("##", "h2"), ("###", "h3")]
).split_text(md)

splitter = RecursiveCharacterTextSplitter(chunk_size=1200, chunk_overlap=150)
chunks = splitter.split_documents(by_headers)   # заголовки сохраняются в metadata

Перекрытие и метаданные

Перекрытие (overlap) — соседние чанки делят 10–20% текста, чтобы факт на границе попал целиком хотя бы в один из них. Метаданные — источник, заголовки раздела, дата, язык — хранятся вместе с чанком: их используют для фильтрации, цитирования и для добавления в сам текст перед вычислением эмбеддинга.

Контекст для чанка

Главная слабость чанкинга — фрагмент, вырванный из документа, теряет контекст. Приёмы борьбы:

  • Заголовочная цепочка — к тексту чанка приписывается путь «Документ → Раздел → Подраздел».
  • Контекстный поиск (contextual retrieval) — языковая модель пишет к каждому чанку одно-два предложения о его месте в документе; по данным Anthropic, это заметно сокращает число неудачных извлечений, особенно в сочетании с ключевым поиском BM25.[3]
  • Позднее разбиение (late chunking) — эмбеддинги токенов вычисляются по всему документу длинноконтекстной моделью и только потом усредняются по чанкам.[5]
  • Родитель–потомок — ищут по мелким чанкам, а модели отдают крупный родительский фрагмент.

Подготовка исходников

Качество чанкинга упирается в извлечение текста. PDF с колонками, таблицами и колонтитулами превращается в кашу, если читать его наивно; инструменты вроде Docling и Unstructured восстанавливают структуру, таблицы и порядок чтения.[6] Поэтому документация, изначально написанная в Markdown, — лучший вход для RAG (см. Markdown как формат для LLM и Документация для ИИ: как подготовить).

Как подобрать параметры

Универсального размера нет. Разумный старт — 500–1000 токенов с перекрытием 10–15% и разбиением по заголовкам. Дальше параметры подбирают на наборе реальных вопросов с известными ответами, измеряя долю найденных нужных фрагментов (recall@k) — см. Оценка LLM (evals). С ростом контекстных окон часть задач решается вообще без разбиения: небольшой корпус целиком помещают в промпт с кэшированием.

См. также

Источники

  1. LangChain — Text splitters
  2. LlamaIndex — Node Parser Modules
  3. Anthropic — Introducing Contextual Retrieval (2024)
  4. Pinecone — Chunking Strategies for LLM Applications
  5. Günther et al. — Late Chunking: Contextual Chunk Embeddings (2024)
  6. Docling — документация