Заметки

Чанкинг документов для RAG: как правильно резать текст

M
Markabus
·3 сентября 2026 г.
Монитор на тёмном рабочем столе показывает длинный технический документ, разбитый на выделенные цветом блоки с перекрытиями, рядом — терминал, SSD и мини-ПК в расфокусе

Если вы строите поиск по своим документам на базе RAG, качество ответов упирается не в модель и не в промпт, а в то, как вы порезали исходные тексты. Этот этап называется чанкинг (chunking, от англ. chunk — «кусок»): документы разбивают на фрагменты, каждый фрагмент превращают в вектор и кладут в базу, а на запрос пользователя достают несколько самых похожих. Порезали плохо — модель получит обрывки без смысла и уверенно ответит мимо. Разбираем, как резать правильно.

Почему нельзя просто резать по 1000 символов

Самый простой сплиттер режет текст на куски одинаковой длины. Работает он ровно до первого живого документа. Вот что ломается:

  • Разрыв мысли. Абзац с описанием проблемы попал в один чанк, а решение — в следующий. Поиск найдёт первый, модель ответит «проблема известна» и на этом остановится.
  • Потеря контекста. В чанке написано «эта настройка включается в админке», а из какого раздела и о какой настройке речь — осталось за границей фрагмента. Такой кусок бесполезен и человеку, и модели.
  • Разрезанные таблицы. Шапка таблицы в одном чанке, строки — в другом. Числа без названий колонок превращаются в шум.
  • Размытые векторы. Если в чанк попали три разные темы, его эмбеддинг окажется усреднённым и не совпадёт толком ни с одним запросом.

Отсюда правило, которое стоит держать в голове всё время: хороший чанк — это законченная мысль, понятная без остального документа. Всё остальное — техника достижения этой цели.

Четыре стратегии разбиения

1. Фиксированные окна с перекрытием

Режем по N символов или токенов, соседние чанки делаем частично пересекающимися. Перекрытие (overlap) — это хвост предыдущего фрагмента, продублированный в начале следующего: если мысль разорвалась на границе, она хотя бы целиком попадёт в один из двух чанков.

Стратегия годится для однородных текстов без структуры — расшифровок разговоров, логов, потока сообщений. Для документации и статей это нижняя планка качества, с которой стоит начинать только ради быстрого прототипа.

2. Рекурсивное разбиение по структуре текста

Рабочий вариант по умолчанию. Сплиттер пробует резать по списку разделителей в порядке убывания «крупности»: сначала по двойным переносам строк (границы абзацев), если кусок всё ещё великоват — по одинарным, затем по точкам, и только в самом конце — по символам. В LangChain это RecursiveCharacterTextSplitter, в LlamaIndex — SentenceSplitter.

Смысл в том, что резать по границе абзаца почти всегда безопаснее, чем посреди предложения. При тех же настройках размера рекурсивный сплиттер даёт заметно более осмысленные фрагменты, а стоит столько же — это чистая арифметика по строке, без обращений к модели.

3. Разбиение по структуре документа

Если у документа есть разметка — заголовки Markdown, теги HTML, функции и классы в коде — грех этим не воспользоваться. Режем по заголовкам: каждый раздел становится чанком, а путь заголовков («Установка → Требования → PHP») кладём в метаданные и дописываем в начало текста чанка.

Для этого есть готовые инструменты: MarkdownHeaderTextSplitter и HTMLHeaderTextSplitter в LangChain, а для исходного кода — сплиттеры, знающие синтаксис конкретного языка (перечисление Language в том же пакете langchain-text-splitters). Если ваша база знаний — это документация в Markdown или экспорт из вики, начинайте отсюда: структура уже размечена автором, её нужно просто не потерять.

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

4. Семантический чанкинг

Здесь границы определяет не разметка, а смысл. Текст разбивают на предложения, считают эмбеддинг каждого и смотрят, где косинусное расстояние между соседями резко скачет — там и проходит граница темы.

Звучит красиво, на практике — дорого и капризно: нужно посчитать вектор для каждого предложения ещё на этапе индексации, а порог «резкого скачка» приходится подбирать под конкретный корпус. Выигрыш относительно аккуратного рекурсивного разбиения обычно небольшой. Имеет смысл на текстах без всякой структуры, где темы плавно перетекают друг в друга — например, на стенограммах встреч.

Размер чанка и перекрытие: с чего начинать

Универсального числа нет, и любой, кто называет одно «правильное», продаёт вам свой пресет. Но есть рабочий диапазон, от которого удобно отталкиваться:

  • Размер: 300–800 токенов. Для русского языка это примерно 700–2000 символов — кириллица расходует токены заметно щедрее латиницы (подробнее об этом — в заметке про токены и лимиты).
  • Перекрытие: 10–20% от размера чанка. Больше — раздуваете базу и получаете дубликаты в выдаче; меньше — теряете мысли на стыках.
  • Ориентируйтесь на длину ответа, а не документа. Если типичный ответ на вопрос пользователя умещается в абзац, чанк размером в страницу будет тащить в контекст лишнее.

Верхнюю границу задаёт эмбеддинг-модель. У text-embedding-3-small и text-embedding-3-large от OpenAI лимит входа — 8192 токена, у актуальной модели Gemini Embedding — столько же. Формально в один вектор можно упаковать десяток страниц, но это плохая идея: чем длиннее текст, тем сильнее размывается его вектор. Лимит — это потолок, а не рекомендация.

Отдельная тонкость: короткие чанки хорошо ищутся, длинные — хорошо отвечают. Поэтому часто применяют разделение ролей: ищем по мелким фрагментам, а в контекст модели подставляем родительский раздел целиком. В LlamaIndex это называется AutoMergingRetriever, в LangChain — ParentDocumentRetriever.

Контекстное обогащение чанков

Самый заметный по эффекту приём последних лет — не менять способ резки, а дописывать каждому чанку короткую справку о том, откуда он взят. Anthropic описала подход под названием Contextual Retrieval: перед индексацией дешёвая модель генерирует к каждому фрагменту 50–100 токенов пояснения («Это фрагмент из отчёта ACME за 2 квартал 2023; речь о выручке относительно предыдущего квартала»), и уже обогащённый текст уходит в эмбеддинг и в индекс.

По их замерам одни контекстные эмбеддинги снижают долю неудачных поисков на 35% (с 5,7% до 3,7%), связка с лексическим поиском BM25 — на 49%, а если добавить переранжирование выдачи, то на 67% (до 1,9%). Разовая стоимость обработки при включённом кэшировании промптов — около 1 доллара за миллион токенов документов. Там же рекомендуют отдавать модели не топ-5, а топ-20 найденных чанков.

Дешёвый вариант той же идеи, без единого вызова модели: дописать в начало каждого чанка название документа и путь заголовков. Стоит ноль, а половину пользы даёт.

Late chunking

Ещё один способ не потерять контекст — поменять порядок действий. Обычно текст сначала режут, потом считают векторы. При late chunking («позднем чанкинге») наоборот: весь документ прогоняют через длинноконтекстную эмбеддинг-модель целиком, получают векторы токенов, уже насыщенные контекстом всего текста, и только потом усредняют их по границам чанков. Местоимение «он» в третьем абзаце оказывается связано с существительным из первого — потому что модель видела оба.

Ограничение очевидно: документ должен помещаться в контекст эмбеддера, а сам эмбеддер — уметь отдавать потокенные векторы, а не один готовый на вход.

Метаданные — половина успеха

Чанк — это не только текст. Вместе с вектором в векторную базу стоит класть: идентификатор и название исходного документа, путь заголовков, URL или путь к файлу, дату обновления, раздел или продукт, язык. Это даёт три вещи сразу — фильтрацию перед поиском (только актуальные версии, только нужный продукт), ссылки на источник в ответе и возможность точечно переиндексировать изменившийся документ, а не всю базу.

Все популярные базы это умеют: в Qdrant, например, метаданные хранятся в payload и по ним же строятся фильтры запроса.

Что делать с неудобным контентом

  • Таблицы. Не режьте поперёк. Небольшую таблицу берите целиком одним чанком; большую — по строкам, дублируя шапку в каждый фрагмент. Ещё лучше — сгенерировать текстовое описание таблицы и индексировать его, а в ответ подставлять саму таблицу.
  • PDF и сканы. Сначала нормальный парсинг с сохранением структуры, потом чанкинг. Если из PDF вываливается каша из колонок и колонтитулов, никакая стратегия резки её не спасёт.
  • Код. Режьте по функциям и классам, а не по строкам. Обязательно сохраняйте путь к файлу в метаданных.
  • Списки и FAQ. Пара «вопрос — ответ» это готовый чанк, ничего изобретать не нужно.

Как понять, что чанкинг работает

Подбирать параметры на глаз бессмысленно — нужен хотя бы минимальный замер. Достаточно такого набора:

  1. Соберите 30–50 реальных вопросов пользователей и для каждого руками отметьте, в каком фрагменте документации лежит ответ.
  2. Прогоните поиск и посчитайте recall@k — в какой доле случаев нужный фрагмент попал в топ-5 или топ-20 выдачи. Это главная метрика: то, что не нашлось, модель не исправит.
  3. Меняйте по одному параметру за раз: размер, перекрытие, тип сплиттера, наличие контекстной справки. Сравнивайте на одном и том же наборе вопросов.
  4. Глазами просмотрите два-три десятка получившихся чанков. Если фрагмент непонятен вам без соседей — он непонятен и модели.

Коротко

Начните с рекурсивного разбиения по структуре текста: 300–800 токенов, перекрытие 10–20%. Если документы размечены заголовками — режьте сначала по ним, а слишком длинные разделы добивайте рекурсивно. Допишите в каждый чанк название документа и путь заголовков, сложите метаданные рядом с вектором. Соберите набор из полусотни вопросов и померяйте recall — дальше улучшайте по цифрам, а не по ощущениям. И только когда простое перестанет вытягивать, беритесь за семантический чанкинг, контекстное обогащение моделью и late chunking.

Частые вопросы

Q.Какой размер чанка выбрать для RAG?

Начинайте с 300–800 токенов (для русского текста это примерно 700–2000 символов) и перекрытия в 10–20% от размера чанка. Дальше подбирайте под свои документы: ориентируйтесь не на длину документа, а на длину типичного ответа на вопрос пользователя. Верхняя граница — лимит эмбеддинг-модели (у OpenAI text-embedding-3 и актуальной Gemini Embedding это 8192 токена), но упираться в него не стоит: чем длиннее текст, тем сильнее размывается его вектор.

Q.Зачем нужно перекрытие между чанками?

Перекрытие — это хвост предыдущего фрагмента, продублированный в начале следующего. Оно страхует от разрыва мысли на границе: если предложение или абзац разрезаны пополам, они целиком попадут хотя бы в один из двух соседних чанков. Слишком большое перекрытие раздувает базу и приводит к дубликатам в выдаче, поэтому обычно берут 10–20%.

Q.Стоит ли сразу делать семантический чанкинг?

Обычно нет. Семантическое разбиение требует посчитать эмбеддинг каждого предложения на этапе индексации и подобрать порог под конкретный корпус, а выигрыш относительно аккуратного рекурсивного сплиттера чаще всего небольшой. Начните с рекурсивного разбиения и разбиения по заголовкам, замерьте recall — и переходите к сложному, только если простое перестало вытягивать.

Q.Что такое контекстное обогащение чанков?

Это приём, при котором перед индексацией к каждому фрагменту дописывают короткую справку о том, откуда он взят. В подходе Contextual Retrieval от Anthropic такую справку на 50–100 токенов генерирует дешёвая модель; по их замерам доля неудачных поисков падает на 35%, а вместе с BM25 и переранжированием — на 67%. Бесплатный вариант той же идеи — просто дописать в начало чанка название документа и путь заголовков.

Источники

Предыдущая
Краткий пересказ нейросетью: как выжать суть из документа

Читайте также

Рабочий стол в тёмной комнате: слева толстая стопка распечатанных страниц в расфокусе, в центре крупным планом экран ноутбука с коротким пересказом из четырёх пунктовЗаметки
2 сентября 2026 г.

Краткий пересказ нейросетью: как выжать суть из документа

«Сделай краткий пересказ» даёт воду, из которой не понять, что было в документе. Разбираем, как формулировать запрос, что делать с текстами, которые не влезают в модель целиком, и как проверять результат.

Читать →
Вид сверху на рабочий стол: ряд бумажных карточек с короткими парами «вход — выход», рядом ручка, механическая клавиатура и край экрана с кодомЗаметки
1 сентября 2026 г.

Few-shot и примеры в промпте: как получить нужный ответ

Иногда нужный результат проще показать, чем описать. Разбираем few-shot: сколько примеров давать, как их размечать, почему важны порядок и баланс классов, где приём не нужен и во сколько токенов обходится.

Читать →
Рабочий стол ретушёра в полутёмной студии: крупный монитор с фотореалистичным снимком и панелями цветокоррекции, рядом фотоаппарат со светосильным объективом, калибровочная карта и тестовые отпечаткиЗаметки
31 августа 2026 г.

Промпт для генерации изображения: как добиться фотореализма

Модель выдаёт восковую кожу и пластиковый глянец не потому, что она слабая, а потому что промпт слишком короткий. Разбираем формулу из шести слотов — герой, план, объектив, свет, среда, материалы, — готовый шаблон с примером и обзор моделей: Gemini Nano Banana, GPT-Image-2, Midjourney V8.2 и FLUX.2.

Читать →