Чанкинг и подготовка данных
Прежде чем документы попадут в векторный индекс RAG-системы, их режут на куски — чанки. От того, где пройдут границы, качество поиска зависит сильнее, чем от выбора модели эмбеддингов, — и именно здесь чаще всего ломаются реальные пайплайны.
Интуиция
Почему нельзя просто заэмбеддить документ целиком? Эмбеддинг — это одна точка в пространстве смыслов. Пятидесятистраничный регламент говорит о сотне вещей сразу, и его вектор получится «обо всём и ни о чём»: смысл размывается, и на конкретный вопрос такой документ находится плохо. Вдобавок у моделей эмбеддингов есть жёсткий лимит входа (часто 512 токенов) — лишнее просто обрежется.
Противоположная крайность — резать по одному предложению. Тогда каждый вектор точен, но бесполезен: чанк «Он подаётся минимум за две недели» не скажет ни поиску, ни LLM, что речь о заявлении на отпуск. Местоимения и отсылки теряют смысл без окружения — теряется контекст.
Стратегии нарезки
- Фиксированный размер с перекрытием (overlap) — тупо режем каждые N токенов, соседние чанки перекрываются на M токенов. Просто, предсказуемо, но границы попадают куда попало.
- По структуре — по заголовкам, абзацам, разметке markdown. Границы совпадают со смысловыми, но чанки получаются разного размера.
- Рекурсивный сплиттер (recursive character splitter) — пытается резать по самым крупным разделителям (двойной перенос строки → предложение → слово), спускаясь ниже, только если кусок не влезает в лимит. Практичный дефолт.
- Семантический чанкинг (semantic chunking) — считаем эмбеддинги соседних предложений и ставим границу там, где близость резко падает. Точнее, но дороже: нужен прогон эмбеддингов ещё на этапе индексации.
Зачем нужен overlap: если важная мысль оказалась ровно на границе, перекрытие гарантирует, что хотя бы в один чанк она попадёт целиком. Цена — дубли в индексе: хранилище растёт, а в выдаче могут оказаться два почти одинаковых кандидата.
Поэкспериментируй: на вопросе «Заболел в отпуске» при фиксированном размере 4 без overlap ответ режется пополам — правило про продление в одном чанке, а требование больничного листа в другом. Добавь overlap 1 — и ответ целиком попадает в найденный чанк. Режим «По структуре» решает ту же проблему без дублей: границы совпадают со смысловыми секциями.
Обогащение чанков
Голый кусок текста часто недостаточен, поэтому чанки обогащают:
- Заголовки внутрь текста. Чанк «Выплата производится в последний рабочий день» находится по запросу про компенсацию гораздо лучше, если в него дописать «Регламент отпусков → Компенсация при увольнении».
- Метаданные (metadata): дата документа, источник, автор, версия — и обязательно права доступа (ACL, access control list). По метаданным фильтруют кандидатов ещё до поиска.
- Contextual retrieval: LLM читает весь документ и дописывает к каждому чанку одно-два предложения контекста («Этот фрагмент из раздела о компенсациях регламента отпусков компании X»). Дороже на этапе индексации, но заметно поднимает точность поиска.
Особые случаи и подводные камни
Таблицы нельзя резать посреди строк: строка без шапки превращается в бессмысленный набор чисел. Обычно таблицу либо кладут в чанк целиком, либо дублируют шапку в каждый кусок, либо конвертируют строки в текстовые описания. Код режут по функциям и классам, а не по числу символов — рекурсивные сплиттеры для кода используют синтаксические разделители языка.
- «Как выбрать размер чанка?» — это трейд-офф: крупнее — больше контекста, но размытый вектор; мельче — точный вектор, но потерянный смысл. Подбирается экспериментально по метрикам ретривера (см. оценку RAG).
- «Зачем overlap и чем он плох?» — спасает мысли на границах, но плодит дубли в индексе и выдаче.
- «Пользователи жалуются, что ответы обрываются на полуслове. Где искать?» — проверить границы чанков: скорее всего, ответ разрезан; лечится overlap или структурной нарезкой.
- «Что положить в метаданные?» — дату, источник, версию и права доступа; без ACL система небезопасна.