Почему размер фрагмента — бизнес-настройка

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

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

Правильный вопрос руководителя не «какой chunk size считается лучшим». Полезнее спросить: какую минимальную единицу должен находить поиск и какой объём контекста нужен человеку или модели, чтобы принять безопасное решение. Эти две единицы часто различаются.

Поисковая единица и единица ответа

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

Отсюда практический шаблон «маленький поиск — широкий контекст»:

  • индекс хранит небольшие дочерние фрагменты;
  • каждый фрагмент знает идентификатор родителя, заголовки и положение в документе;
  • поиск ранжирует дочерние фрагменты;
  • перед генерацией система поднимает родительский раздел или окно соседних элементов;
  • дубликаты родителей объединяются, а итоговый контекст укладывается в лимит.

LlamaIndex демонстрирует похожий приём с предложениями: в индекс попадает отдельное предложение, а перед передачей модели оно заменяется окном соседних предложений. Это не готовый рецепт для любого бизнеса, но хорошо показывает разделение двух задач. Узкий фрагмент помогает найти точное место, а окно возвращает смысл.

Начинайте со структуры документа

Если исходный формат позволяет распознать заголовки, абзацы, списки и таблицы, сначала сохраните эти элементы, а ограничение размера применяйте после. Документация Unstructured описывает именно такой подход: разбиение выполняется над элементами, полученными при partition, и обычный фрагмент объединяет целые элементы. Текст режется внутри элемента, только когда тот сам превышает жёсткий максимум.

Стратегия `by_title` полезна для регламентов, инструкций и коммерческих условий: новый заголовок открывает новый фрагмент, даже если в предыдущем ещё осталось место. Это обычно лучше, чем склеить конец «Гарантии» с началом «Возврата» ради одинаковой длины.

Разумно хранить два ограничения:

  • мягкий размер, после которого фрагмент предпочтительно закрыть;
  • жёсткий максимум, который нельзя превышать из-за контекста embedding-модели или ограничений обработки.

Перекрытие не должно автоматически применяться ко всем нормальным границам. Unstructured отдельно предупреждает, что overlap между уже цельными семантическими элементами может загрязнять фрагменты. Его полезнее оставить для вынужденного разреза слишком длинного элемента и проверить на своих вопросах.

Для разных документов нужны разные политики

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

Регламенты и инструкции

Граница проходит по заголовкам и подпунктам. В метаданные входят путь заголовков, номер версии, дата действия и владелец. При ответе возвращается найденный подпункт вместе с родительским разделом и ближайшими исключениями.

Договоры и нормативные тексты

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

Каталоги и прайс-листы

Лучше индексировать структурированную запись товара или услуги, а не строковое представление всей таблицы. Цена, валюта, период действия, филиал и доступность остаются отдельными полями и фильтрами. Описание можно искать векторно, коммерческие ограничения — проверять детерминированно.

Таблицы

Шапка, единицы измерения, примечания и строки должны оставаться связанными. Маленький фрагмент таблицы обязан наследовать заголовок и контекст таблицы. Если ответ требует агрегирования, расчёт выполняет код или база данных, а не языковая модель по случайному набору строк.

Когда полезно late chunking

Обычная схема сначала режет документ, затем независимо кодирует каждый фрагмент embedding-моделью. Из-за этого фраза «этот тариф» может потерять название тарифа из предыдущего абзаца. Работа Late Chunking предлагает другой порядок: длинный текст сначала проходит через long-context embedding-модель, и только затем представления токенов объединяются в векторы отдельных фрагментов. Так фрагмент сохраняет информацию о положении в документе.

Авторы показали улучшение на ряде retrieval-задач, особенно для небольших фрагментов. Но они также описали случаи, где на больших фрагментах обычная схема была сопоставима или лучше, а нерелевантный окружающий контекст не помогал. Следовательно, late chunking — кандидат для сравнения, а не новая обязательная настройка.

Для внедрения нужно проверить:

  • поддерживает ли embedding-модель достаточно длинный вход и нужный способ pooling;
  • не обрезается ли документ до важного раздела;
  • как меняются время и память индексации;
  • воспроизводятся ли границы фрагментов после изменения парсера;
  • улучшается ли поиск именно на русскоязычных документах компании.

Архитектура конвейера

Надёжная индексация начинается раньше chunker и заканчивается позже векторной базы:

1. Приём документа фиксирует источник, владельца, права, версию и контрольную сумму.
2. Парсер извлекает элементы, порядок чтения и таблицы; сомнительные страницы попадают в карантин.
3. Классификатор выбирает политику нарезки по типу документа.
4. Каждый фрагмент получает стабильный идентификатор, ссылку на родителя, путь заголовков, диапазон страниц и версию.
5. Индексатор записывает векторы и полнотекстовый индекс идемпотентно.
6. Поиск применяет фильтры доступа до ранжирования, затем объединяет векторные и лексические сигналы.
7. Context builder поднимает родителей или соседнее окно, удаляет повторы и соблюдает бюджет контекста.
8. Ответ содержит ссылки на конкретные фрагменты; низкая уверенность и конфликт версий ведут к отказу или человеку.

Как сравнить стратегии на своих вопросах

Возьмите 100–200 реальных запросов из поддержки, продаж, производства или внутренней базы знаний. Для каждого профильный сотрудник отмечает обязательный документ, релевантный раздел и минимальный набор фактов для ответа. В проверочную выборку обязательно добавляют неудобные случаи:

  • ответ находится на границе двух подразделов;
  • правило и исключение разнесены;
  • таблица продолжается на следующей странице;
  • одинаковые термины встречаются в разных продуктах;
  • действует только последняя версия;
  • правильный ответ — «в источниках недостаточно данных».

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

На первом этапе важнее retrieval-метрики:

  • попал ли обязательный фрагмент в top-k;
  • найдено ли исключение вместе с правилом;
  • сколько нерелевантного текста заняло контекст;
  • сколько разных документов пришлось передать модели;
  • соблюдены ли версия и права доступа.

Затем измеряют подтверждённость ответа, долю корректных отказов и число исправлений сотрудника. Ragas перечисляет для RAG контекстную точность и полноту, релевантность ответа, faithfulness и чувствительность к шуму. Автоматические оценки удобны для регрессии, но бизнес-критичные примеры должен подтверждать владелец процесса.

Экономика фрагментов

Маленькие фрагменты увеличивают число векторов, объём индекса, время переиндексации и количество кандидатов для reranker. Большие фрагменты уменьшают эти затраты, но чаще несут лишний текст в запрос к генеративной модели и могут ухудшать точность поиска.

Модельный пример: корпус содержит 20 млн символов очищенного текста. При фиксированном размере 1 000 символов и перекрытии 10% получится примерно 22 тыс. фрагментов. При размере 400 символов с тем же перекрытием — около 56 тыс. Индексирование, резервирование и reranking заметно вырастут.

Считать стоит не стоимость вектора, а стоимость принятого ответа:

  • вычисления для парсинга и embeddings;
  • хранение и резервные копии индекса;
  • reranking и генерация;
  • задержка до ответа;
  • ручная проверка и исправление;
  • цена ошибки из-за потерянного условия.

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

Пилот за две недели

В первую неделю выберите один тип документов и соберите вопросы с размеченными источниками. Зафиксируйте парсер, embedding-модель и поисковые настройки, чтобы менять только стратегию нарезки. Постройте три индекса и сравните retrieval до генерации ответа.

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

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