Чанкинг документов
| Применение | 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). С ростом контекстных окон часть задач решается вообще без разбиения: небольшой корпус целиком помещают в промпт с кэшированием.
См. также
- RAG (генерация с дополнением поиском)
- Векторный поиск
- Эмбеддинг
- Markdown как формат для LLM
- llms.txt