Chunking strategies: why naive splitting fails
Compare fixed, recursive, structural, and semantic chunking and measure how boundaries, overlap, and document context affect recall.
Lesson content is currently available in Russian.
What you will learn
- →Объяснять, какие типы ошибок retrieval порождает наивный fixed-size сплиттинг.
- →Выбирать стратегию chunking’а под тип документа: markdown, PDF с таблицами, код, чаты.
- →Применять contextual retrieval: обогащать чанк сгенерированным контекстом документа до индексации.
Почему chunking — первое место, где RAG ломается
Retrieval не может найти то, что было уничтожено на этапе индексации. Наивный сплиттер режет документ каждые N символов и порождает три класса дефектов. Первый — разрыв смысловой единицы: определение термина остаётся в чанке 12, а само объяснение уезжает в чанк 13; по запросу находится половина ответа, и модель достраивает остальное — это прямой источник галлюцинаций. Второй — потеря контекста: чанк «выручка выросла на 3%» без названия компании и квартала бесполезен и при поиске, и при генерации. Третий — склейка разнородного: конец одного раздела и начало другого в одном чанке размывают его эмбеддинг, и чанк перестаёт находиться по обоим темам.
Размер чанка — компромисс между точностью поиска и полнотой контекста. Маленькие чанки (128–256 токенов) дают «острые» эмбеддинги и высокий precision, но фрагментируют смысл. Большие (1024+) сохраняют связность, но эмбеддинг усредняется по нескольким темам и recall падает. Практическая стартовая точка для прозы — 400–512 токенов с overlap 10–15% (50–64 токена); дальше размер настраивается не на глаз, а по метрике recall@k на вашем eval-наборе — этому посвящён шестой урок.
Ключевой сдвиг мышления: chunking — это не препроцессинг «нарезали и забыли», а проектное решение уровня схемы базы данных. Его меняют по данным, и каждое изменение требует переиндексации и прогона eval.
Иерархия стратегий: от fixed-size до structure-aware
Стратегии выстраиваются по возрастанию использования структуры документа:
- Fixed-size — резать каждые N токенов с overlap. Базовая линия: дёшево, предсказуемо, ломает границы предложений и разделов.
- Recursive — резать по иерархии разделителей: сначала
\n\n(абзацы), потом\n, потом предложения, и только в крайнем случае — по символам. Стандарт по умолчанию для прозы. - Structure-aware — использовать разметку: markdown-заголовки, HTML-теги, секции PDF. Чанк наследует «хлебные крошки» (
Руководство > Оплата > Возвраты) в метаданные — они участвуют и в поиске, и в фильтрации. - Semantic — считать эмбеддинги предложений и резать там, где косинусная близость соседних предложений падает ниже порога. Дорого на индексации, полезно для длинных неструктурированных текстов.
Отдельные типы контента требуют своих правил. Таблицы нельзя резать по строкам — таблица целиком плюс текстовое резюме («таблица сравнивает тарифы X и Y по цене и лимитам») как отдельный searchable-чанк. Код режется по функциям и классам через AST-парсер (tree-sitter), а не по строкам. Диалоги — по репликам с сохранением пар «вопрос-ответ».
Практическое правило: если у документа есть структура — используйте её; recursive-сплиттер — fallback, а не выбор по умолчанию для всего подряд.
Contextual retrieval: чанк должен знать, откуда он
Anthropic в 2024 году опубликовала технику contextual retrieval: перед индексацией каждый чанк прогоняется через LLM, которая генерирует 50–100 токенов контекста — что это за документ, к какому разделу относится фрагмент и о чём он. Контекст приклеивается к чанку, и уже обогащённый текст эмбеддится и индексируется в BM25:
CONTEXT_PROMPT = (
'<document>{doc}</document>\n'
'Вот фрагмент этого документа: <chunk>{chunk}</chunk>\n'
'Дай короткий контекст (2-3 предложения), привязывающий фрагмент '
'к документу в целом, для улучшения поиска. Только контекст.'
)
def contextualize(doc: str, chunk: str) -> str:
ctx = llm.generate(CONTEXT_PROMPT.format(doc=doc, chunk=chunk))
return ctx + '\n\n' + chunk
По замерам Anthropic contextual embeddings сокращают долю неудачных retrieval (нужный чанк не попал в top-20) на 35%, а в комбинации с contextual BM25 — на 49%; добавление reranking доводит сокращение до 67%. Стоимость разовая: с prompt caching (документ кешируется, меняется только чанк) обогащение стоит порядка 1 доллара на миллион токенов документов.
Дешёвая альтернатива без LLM — конкатенация метаданных: title > section > subsection плюс текст чанка. Это закрывает заметную часть той же проблемы и должно быть включено всегда; полный contextual retrieval подключайте, когда eval показывает, что чанки не находятся из-за потери контекста документа.
Parent-child retrieval: искать мелко, читать крупно
Конфликт «маленький чанк ищется лучше, большой читается лучше» решается разрывом связи между единицей поиска и единицей контекста. В parent-child схеме (в LangChain — ParentDocumentRetriever, в LlamaIndex — SentenceWindowNodeParser) индексируются мелкие child-чанки по 128–256 токенов, но в промпт генератора попадает их parent — раздел на 1000–2000 токенов или окно из соседних предложений. Точность поиска маленького чанка сочетается со связностью большого контекста.
Вариации той же идеи: sentence-window — эмбеддится одно предложение, возвращается оно плюс k соседних; auto-merging — если из одного parent’а найдено несколько детей, они схлопываются в родителя целиком. Расплата — хранение двух уровней и дедупликация: если три child-чанка указывают на один parent, он должен попасть в контекст один раз, а не трижды.
Чек-лист качества chunking’а перед индексацией: (1) случайная выборка из 20 чанков читается человеком без документа — каждый чанк понятен сам по себе; (2) ни одна таблица и ни один блок кода не разрезаны посередине; (3) у каждого чанка есть метаданные — источник, раздел, дата обновления; (4) распределение длин чанков не имеет хвоста из обрезков по 10–20 токенов (их нужно склеивать с соседями или отбрасывать). Этот ручной аудит занимает полчаса и ловит больше проблем, чем неделя подбора гиперпараметров поверх сломанной нарезки.
Practice
Аудит и redesign нарезки
Возьмите 5–10 реальных документов своего домена (документация, договоры, статьи). Нарежьте их тремя способами: fixed-size 512/64, recursive по абзацам, structure-aware с метаданными-«крошками». Для 10 тестовых вопросов вручную проверьте, в какой нарезке нужный фрагмент сохранился целым и находимым.
Deliverable
Таблица «вопрос → стратегия → нужный фрагмент цел/разрезан/без контекста» по трём стратегиям и короткий вывод, какая нарезка выбрана для домена и почему.
Checkpoint
Объясните коллеге, почему «резать каждые 500 символов» ломает RAG, какие три класса дефектов это порождает и как contextual retrieval и parent-child схема их лечат.
- ✓ Названы дефекты наивной нарезки: разрыв смысловой единицы, потеря контекста документа, склейка разнородных тем.
- ✓ Сформулирован компромисс размера чанка: precision мелких против связности крупных — и стартовая точка 400–512 токенов с overlap 10–15%.
- ✓ Описано, как contextual retrieval обогащает чанк контекстом до индексации, а parent-child разделяет единицу поиска и единицу контекста.
Check yourself
Sources