

Чанкинг (chunking) - это процесс разбиения документов на фрагменты оптимального размера для загрузки в RAG-систему. Качество чанкинга напрямую определяет качество ответов ИИ: слишком мелкие фрагменты теряют контекст, слишком крупные размывают релевантность, а неправильные границы разрезают мысль пополам. В этой статье мы разберём все основные стратегии чанкинга - от простого разбиения по символам до семантического анализа границ - с практическими рекомендациями по выбору подхода для разных типов документов и реальными примерами из проектов Промолитики.
Почему чанкинг критически важен для RAG
Когда вы загружаете документы в RAG-систему, они не используются целиком. Языковая модель имеет ограниченное контекстное окно - даже самые современные модели обрабатывают от 8 000 до 200 000 токенов за раз. Отправить модели все 5 000 документов вашей компании невозможно. Поэтому из всех документов нужно выбрать самые релевантные фрагменты - и качество этого выбора определяется тем, как документы были разбиты.
Представьте базу знаний компании с 500 статьями. Клиент спрашивает: «Как настроить интеграцию с amoCRM?» RAG-система должна найти именно тот фрагмент, где описана настройка amoCRM, а не всю статью на 20 страниц об интеграциях вообще. Если фрагмент слишком большой - модель получит много нерелевантной информации и может «утонуть» в ней. Если слишком маленький - фрагмент может содержать обрывок инструкции без начала и конца.
Чанкинг - это искусство нарезать документы так, чтобы каждый фрагмент был самодостаточным, содержал законченную мысль и имел достаточно контекста для понимания. Это звучит просто, но на практике является одной из самых сложных задач при построении RAG-систем.
Стратегия 1: разбиение по фиксированному размеру
Самый простой подход - разрезать текст на фрагменты фиксированной длины. Например, каждые 500 токенов (примерно 375 слов) начинается новый фрагмент. Это можно реализовать за 10 строк кода, и для простых случаев подход работает удовлетворительно.
Как это работает
Текст документа разбивается на части по заданному количеству символов или токенов. Обычно используется размер от 256 до 1024 токенов. Каждый фрагмент получает свой порядковый номер и метаданные (название документа, автор, дата).
Преимущества
- Простота реализации - минимум кода, нет необходимости анализировать структуру документа
- Предсказуемость - все фрагменты одинакового размера, что упрощает планирование хранилища и расчёт стоимости
- Универсальность - работает с любым типом текста, не зависит от формата документа
Недостатки
- Разрыв смысла - граница фрагмента может пройти посередине предложения, абзаца или даже слова. Фрагмент, который начинается с «...при этом стоимость доставки включена в цену», лишён контекста: доставка чего? по какому тарифу? кому?
- Потеря структуры - заголовки, списки и таблицы теряют свою иерархию. Подзаголовок может оказаться в конце одного фрагмента, а содержание раздела - в начале следующего
- Неравномерная информативность - один фрагмент может содержать два полных раздела с разными темами, другой - обрывок одного предложения и начало нового
Фиксированное разбиение подходит как начальная точка для прототипирования или для однородных текстов (художественная литература, стенограммы), где нет чёткой структуры. Для бизнес-документов с разделами и заголовками - это слабый подход.
Стратегия 2: разбиение по абзацам
Следующий уровень - использовать естественные границы текста. Абзац - это минимальная единица, которая обычно содержит одну законченную мысль. Разбиение по абзацам сохраняет эту целостность.
Как это работает
Текст разделяется по двойным переносам строк (пустым строкам). Каждый абзац становится отдельным фрагментом. Если абзац слишком короткий (менее 50 символов), он объединяется со следующим. Если слишком длинный (более 1500 символов), он разбивается по предложениям.
Преимущества
- Сохранение смысловой целостности - каждый фрагмент содержит законченную мысль, как её задумал автор
- Естественные границы - нет разрывов посередине предложений
- Простая реализация - не намного сложнее фиксированного размера
Недостатки
- Неравномерный размер - абзацы в реальных документах сильно различаются по длине. Один абзац - 30 слов, другой - 300. Это создаёт проблемы для эмбеддинг-модели: короткие фрагменты дают менее точные эмбеддинги
- Потеря контекста раздела - абзац без заголовка раздела может быть непонятен. «В этом случае нужно нажать кнопку «Сохранить» и подождать 5 секунд» - в каком случае? какая кнопка? без заголовка «Настройка уведомлений» фрагмент теряет смысл
- Зависимость от форматирования - в документах, где авторы не ставят пустые строки между абзацами (или наоборот, ставят их после каждого предложения), метод работает некорректно
Разбиение по абзацам хорошо работает для блогов, статей, FAQ и других текстов с логичной абзацной структурой. Для технической документации с глубокой иерархией заголовков нужен более продвинутый подход.
Стратегия 3: разбиение по заголовкам (heading-based)
Самый эффективный подход для структурированных документов - использовать заголовки как естественные точки разбиения. Каждый раздел (H2) или подраздел (H3) становится отдельным фрагментом вместе с текстом под ним.
Как это работает
Парсер анализирует структуру документа: находит заголовки разных уровней (H1, H2, H3) и использует их как точки разбиения. Текст между двумя заголовками одного уровня становится одним фрагментом. Заголовок включается в начало фрагмента, обеспечивая контекст. Иерархия заголовков сохраняется: если H3-подраздел находится внутри H2-раздела, заголовок H2 добавляется как метаданные к фрагменту H3.
Пример
Документ «Руководство по интеграции» с разделом «Настройка amoCRM» (H2) и подразделами «Авторизация» (H3) и «Маппинг полей» (H3) даст три фрагмента. Каждый фрагмент начинается с заголовка и содержит только текст своего раздела. При этом фрагмент «Авторизация» будет иметь метаданные: «Родительский раздел: Настройка amoCRM, Документ: Руководство по интеграции».
Преимущества
- Максимальная семантическая целостность - автор документа уже выделил логические блоки заголовками. Разбиение по заголовкам уважает эту структуру
- Встроенный контекст - заголовок в начале фрагмента сразу объясняет, о чём идёт речь. Модели не нужно «угадывать» тему
- Навигация - можно указать пользователю точный раздел документа, откуда взят ответ, вплоть до номера страницы и заголовка
Недостатки
- Зависимость от качества разметки - если в документе нет заголовков или они используются непоследовательно (заголовки вручную сделаны жирным шрифтом вместо стилей H2/H3), метод не работает
- Экстремальный разброс размеров - один раздел может содержать 50 слов, другой - 3000. Короткие разделы дают бедные эмбеддинги, длинные перегружают контекст модели
- Не все документы структурированы - письма, чаты, транскрипты совещаний не имеют заголовков
Это наш основной подход в Промолитике для базы знаний, документации и технических руководств. Для документов без заголовков мы используем fallback на абзацное разбиение.
Стратегия 4: семантическое разбиение
Самый продвинутый подход - определять границы фрагментов автоматически, на основе анализа смысла текста. Семантическое разбиение не зависит от форматирования документа и работает с любым типом текста.
Как это работает
Алгоритм анализирует последовательные предложения и оценивает «смысловую дистанцию» между ними. Для этого используются эмбеддинги: каждое предложение превращается в вектор, и вычисляется косинусное сходство между соседними предложениями. Когда сходство резко падает - значит, тема сменилась, и здесь должна проходить граница фрагмента.
Представьте текст, в котором 10 предложений посвящены настройке email-уведомлений, а затем автор переходит к описанию push-уведомлений. Косинусное сходство между последним предложением про email и первым про push будет значительно ниже, чем между соседними предложениями внутри каждой темы. Эта «яма» в графике сходства - сигнал для разделения.
Преимущества
- Работает с любым текстом - не зависит от наличия заголовков, абзацев или какого-либо форматирования. Подходит для транскриптов, писем, чатов
- Адаптивные границы - размер фрагмента определяется содержанием, а не формальными правилами. Если тема раскрывается в 3 предложениях - фрагмент будет коротким, если в 15 - длинным
- Высокая точность поиска - фрагменты содержат строго одну тему, что улучшает качество эмбеддингов и, соответственно, поиска
Недостатки
- Вычислительная стоимость - для каждого предложения нужно создать эмбеддинг. Для документа из 1000 предложений это 1000 вызовов модели эмбеддингов на этапе чанкинга (до финальной индексации)
- Чувствительность к порогу - нужно подобрать порог cosine similarity, ниже которого происходит разделение. Слишком низкий - фрагменты будут огромными. Слишком высокий - каждое предложение станет отдельным фрагментом
- Непредсказуемость - размер и количество фрагментов невозможно предсказать заранее. Это усложняет планирование
Семантическое разбиение оправдано для неструктурированных текстов, где другие методы работают плохо: транскрипты звонков, email-переписка, логи чатов. Для документов с хорошей структурой (markdown, HTML) heading-based подход проще и не уступает по качеству.
Размер фрагмента: поиск баланса
Один из ключевых параметров чанкинга - размер фрагмента. Слишком маленький - и контекст теряется. Слишком большой - и релевантность размывается. Рассмотрим, какие компромиссы возникают при выборе размера.
Маленькие фрагменты (100-256 токенов)
- Плюс: высокая точность поиска - фрагмент содержит конкретный факт, и эмбеддинг точно отражает этот факт
- Плюс: больше фрагментов помещается в контекстное окно модели - можно дать ей информацию из разных частей документации
- Минус: потеря контекста. Фрагмент «Стоимость доставки: 500 руб.» без указания, для какого региона и веса - бесполезен
- Минус: шум. При поиске по маленьким фрагментам в топ-10 могут попасть обрывки из разных разделов, не связанные между собой
Большие фрагменты (1024-2048 токенов)
- Плюс: богатый контекст - фрагмент содержит заголовок раздела, вводный текст, детали и примеры. Модель получает полную картину
- Плюс: более стабильные эмбеддинги - длинный текст даёт более информативный вектор
- Минус: размытие релевантности. Фрагмент на 2000 токенов о «Настройке CRM» может содержать и amoCRM, и Bitrix24, и Profitbase. Запрос про amoCRM найдёт этот фрагмент, но модель получит много лишней информации
- Минус: меньше фрагментов помещается в контекст. Если контекстное окно - 8000 токенов, вы сможете подать только 3-4 больших фрагмента вместо 15-20 маленьких
Оптимальный размер
По нашему опыту в Промолитике, оптимальный размер фрагмента для большинства бизнес-задач - от 256 до 512 токенов (примерно 200-400 слов). Это достаточно для сохранения контекста и достаточно компактно для точного поиска.
Но универсального ответа нет. Для товарных каталогов фрагмент = одна карточка товара (может быть 50 токенов). Для юридических документов, где смысл предложения зависит от контекста всего раздела, лучше работают фрагменты по 800-1000 токенов. Для FAQ каждая пара «вопрос-ответ» - это естественный фрагмент, независимо от длины.
Главное правило: размер фрагмента должен определяться типом контента, а не техническими ограничениями. Начните с рекомендованного диапазона и проверьте на реальных запросах - это единственный надёжный способ подобрать оптимум.
Перекрытие между фрагментами (overlap)
Перекрытие - приём, при котором конец одного фрагмента повторяется в начале следующего. Если фрагмент = 500 токенов с перекрытием 100 токенов, то последние 100 токенов фрагмента N становятся первыми 100 токенами фрагмента N+1.
Зачем нужно перекрытие
Перекрытие решает проблему «разорванного контекста». Если мысль начинается в конце фрагмента N и продолжается в начале фрагмента N+1, перекрытие гарантирует, что хотя бы в одном из них мысль будет представлена полностью (или почти полностью).
Практический пример. В документе написано: «Для корпоративных клиентов действует специальный тариф. Стоимость подписки - 50 000 руб./мес при оплате за год.» Если граница фрагмента проходит между этими предложениями, без перекрытия первый фрагмент скажет про «специальный тариф» без цены, а второй - про цену без пояснения, что она для корпоративных клиентов. С перекрытием в 100 токенов оба предложения попадут хотя бы в один фрагмент.
Какой размер перекрытия выбрать
Типичные значения: от 10% до 25% от размера фрагмента. При фрагменте 512 токенов перекрытие составит 50-128 токенов. Мы чаще используем 15-20% - это хороший баланс между покрытием контекста и объёмом хранилища.
Больший overlap означает больше фрагментов (при том же объёме текста) и, соответственно, больший расход на хранение эмбеддингов и вычисления при поиске. Для базы из 10 000 фрагментов это несущественно. Для базы из 10 000 000 - уже заметно.
Важно: при использовании heading-based разбиения перекрытие обычно не нужно, потому что заголовок уже обеспечивает контекст, и каждый раздел - самодостаточная единица. Перекрытие наиболее полезно при фиксированном и абзацном разбиении.
Метаданные: что сохранять вместе с фрагментом
Фрагмент без метаданных - как страница книги без номера и названия главы. Технически текст есть, но использовать его эффективно невозможно. Метаданные обогащают фрагмент контекстом и позволяют фильтровать, ранжировать и цитировать результаты поиска.
Обязательные метаданные
- Название документа - «Руководство по интеграции с amoCRM». Позволяет указать источник в ответе ИИ
- Заголовок раздела - «Настройка вебхуков». Уточняет контекст фрагмента
- Позиция в документе - номер страницы, порядковый номер фрагмента. Позволяет восстановить полный контекст при необходимости
- Дата документа - когда документ был создан или обновлён. Критически важно для разрешения противоречий: если два фрагмента противоречат друг другу, актуальнее тот, что новее
Рекомендуемые метаданные
- Автор - кто написал документ. Полезно для внутренних систем: «Этот регламент составлен юридическим отделом»
- Тип документа - инструкция, FAQ, регламент, коммерческое предложение. Позволяет приоритизировать источники: для вопросов о ценах - прайс-лист важнее FAQ
- Категория или тема - к какой области относится документ. Для фильтрации при поиске: если клиент спрашивает о доставке, нет смысла искать среди документов об HR-политиках
- Иерархия заголовков - полный путь от H1 до текущего H3. Например: «Руководство > Интеграции > amoCRM > Вебхуки». Это «хлебные крошки», которые дают модели полный контекст даже для маленького фрагмента
- URL или путь к файлу - чтобы ИИ мог предоставить ссылку на источник в ответе
- Язык - если база мультиязычная, метка языка позволяет фильтровать фрагменты
В Промолитике мы храним метаданные в виде JSON-объекта, привязанного к каждому вектору в Turbopuffer или pgvector. При поиске метаданные используются для фильтрации (показать только документы за последний год) и для обогащения ответа (указать источник и дату).
Чанкинг для разных типов документов
Универсального подхода к чанкингу не существует. Разные типы документов требуют разных стратегий. Вот наши рекомендации, основанные на десятках проектов.
Markdown и HTML
Идеальные форматы для чанкинга, потому что структура размечена явно. Используйте heading-based разбиение: каждый заголовок ## (H2) начинает новый фрагмент. Заголовки ### (H3) могут либо начинать отдельные фрагменты (если разделы длинные), либо оставаться частью родительского H2-фрагмента (если разделы короткие). Заголовок верхнего уровня # (H1) добавляется как метаданные ко всем фрагментам.
Fallback: если раздел под H2 слишком длинный (более 1500 токенов) и не содержит подзаголовков, разбейте его по абзацам, сохранив H2 в начале каждого фрагмента.
PDF-документы
PDF-документы - самый сложный случай. Если PDF текстовый и имеет закладки (bookmarks), используйте их как аналог заголовков. Если закладок нет, определяйте заголовки по форматированию: больший шрифт, жирный текст, особый стиль. Для сканированных PDF после OCR применяйте абзацное разбиение с перекрытием.
Отдельная проблема - разбиение по страницам. Некоторые системы по умолчанию создают один фрагмент на страницу. Это плохой подход: мысль автора не заканчивается на границе страницы. Мы рекомендуем игнорировать постраничное деление и работать с текстом как с непрерывным потоком.
Email-переписка
Для email-архивов единица чанкинга - одно письмо (после очистки от подписей и цитирования). Если письмо длинное, его можно дополнительно разбить по абзацам. Метаданные обязательно включают: тему письма, отправителя, дату, ID цепочки (для связывания писем одного треда).
Важный нюанс: цепочку писем (thread) можно обрабатывать двумя способами. Первый - каждое письмо отдельно, с ID цепочки в метаданных. Второй - вся цепочка как один документ. Мы используем первый подход для больших архивов (когда цепочки могут содержать 50+ писем) и второй - для коротких переписок (3-5 писем).
Тикеты поддержки
Каждый тикет - отдельный фрагмент. Если тикет содержит много сообщений (10+), мы используем реструктуризацию: языковая модель создаёт из всей переписки один структурированный фрагмент с полями «Проблема», «Решение», «Результат». Этот подход значительно повышает качество поиска по сравнению с загрузкой сырых логов.
Товарные каталоги
Каталог товаров или объектов недвижимости - самый простой случай. Каждая карточка товара = один фрагмент. Все характеристики преобразуются в текстовое описание. Метаданные включают числовые параметры (цена, площадь, вес) для точной фильтрации, которую семантический поиск не может обеспечить.
FAQ
Каждая пара «вопрос-ответ» - один фрагмент. Вопрос включается в текст фрагмента, потому что он содержит ценную семантическую информацию о теме. Если ответ очень длинный (более 500 токенов), его можно разбить, но вопрос должен повторяться в начале каждого фрагмента.
Подход Промолитики: heading-based с fallback на абзацы
В проектах Промолитики мы используем комбинированный подход, который мы называем «heading-first». Он работает в три этапа.
Этап 1: анализ структуры. Парсер определяет тип документа и наличие заголовков. Для markdown и HTML это тривиально. Для PDF используется эвристика на основе размера шрифта и форматирования. Для текстовых файлов - регулярные выражения для обнаружения паттернов заголовков.
Этап 2: первичное разбиение. Если документ имеет заголовки - разбиение по H2/H3. Если нет - по абзацам. В обоих случаях фрагмент обогащается метаданными: название документа, иерархия заголовков, дата, автор.
Этап 3: нормализация размеров. Фрагменты проверяются на размер. Слишком короткие (менее 100 токенов) объединяются со следующими. Слишком длинные (более 1000 токенов) дополнительно разбиваются по абзацам с сохранением заголовка в начале. Перекрытие добавляется только для абзацного разбиения (50-100 токенов).
Этот подход мы применяем в боте для застройщика (база знаний из статей о жилых комплексах), в системе поиска по email-архиву (после реструктуризации писем) и во внутренних проектах (документация, регламенты). Он даёт стабильно хорошие результаты для разных типов контента и не требует сложной настройки.
Типичные ошибки при чанкинге
За время работы с десятками проектов мы собрали список самых частых ошибок, которые снижают качество RAG-системы на этапе чанкинга.
- Одинаковый размер для всех документов - FAQ, техническая документация и переписка требуют разного подхода. Не используйте один chunk_size=512 для всей базы
- Игнорирование метаданных - фрагмент без заголовка раздела и названия документа теряет до 50% своей информативности. Всегда сохраняйте контекст
- Отсутствие перекрытия при фиксированном разбиении - без overlap вы гарантированно теряете информацию на границах фрагментов. Добавьте хотя бы 10%
- Загрузка мусора - колонтитулы, повторяющиеся дисклеймеры, пустые страницы, содержание - всё это создаёт шум и снижает точность поиска. Очищайте данные до чанкинга
- Отсутствие тестирования - чанкинг нужно тестировать на реальных запросах. Подготовьте 20-30 типичных вопросов, прогоните через систему и оцените: находятся ли правильные фрагменты? Достаточно ли в них контекста? Нет ли шума?
- Разрезание таблиц - таблица, разрезанная пополам, бесполезна. Обнаруживайте таблицы на этапе парсинга и сохраняйте их как целые фрагменты, даже если они превышают стандартный размер
- Потеря форматирования - нумерованные списки, важные выделения, вложенные структуры содержат информацию о приоритетности. Сохраняйте хотя бы базовую разметку
Практические рекомендации: с чего начать
Если вы только начинаете работу с RAG, вот пошаговый план выбора стратегии чанкинга:
- Шаг 1: изучите свои документы. Откройте 10-20 случайных файлов и оцените: есть ли заголовки? Есть ли абзацное деление? Какой средний размер раздела? Какой формат?
- Шаг 2: выберите основную стратегию. Если документы структурированы (markdown, HTML с заголовками) - используйте heading-based. Если нет (письма, чаты) - абзацное разбиение с перекрытием. Если однородный текст без структуры - фиксированный размер с перекрытием
- Шаг 3: определите размер фрагмента. Начните с 400 токенов для FAQ и каталогов, 512 - для документации, 800 - для юридических документов. Перекрытие: 15% от размера
- Шаг 4: не забудьте метаданные. Как минимум: название документа, заголовок раздела, дата. Как максимум: автор, тип, категория, URL, иерархия заголовков
- Шаг 5: тестируйте. Подготовьте 20 типичных запросов, прогоните через систему поиска и оцените качество найденных фрагментов. Итеративно корректируйте размер и стратегию
Итог
Чанкинг - невидимый, но критически важный этап построения RAG-системы. Правильное разбиение документов определяет качество поиска и, как следствие, качество ответов ИИ. Не существует единой «лучшей» стратегии - выбор зависит от типа документов, задачи и объёма данных. Heading-based разбиение лучше всего работает для структурированных документов, абзацное - для текстов без заголовков, семантическое - для неструктурированных потоков. Перекрытие между фрагментами и богатые метаданные повышают качество любой стратегии.
В Промолитике мы используем комбинированный подход «heading-first» с fallback на абзацы, перекрытием 50-100 токенов и обязательными метаданными для каждого фрагмента. Этот подход работает в продакшене для базы знаний застройщика, email-архивов, тикетов поддержки и внутренней документации. Если вам нужна помощь с настройкой чанкинга или всей RAG-системы - свяжитесь с нами для бесплатной консультации.



