Перейти к содержимому
17 сент. 2024 г.·8 мин чтения

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

Чанкинг на русском для RAG требует другого подхода: абзацы, разделы и смысловые блоки ведут себя по-разному на регламентах и договорах.

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

Где ломается поиск по русским документам

Русские регламенты и договоры часто дают плохой поиск не из-за слабой модели, а из-за самого текста. Запрос цепляется за общие слова вроде "срок", "уведомление" или "согласование" и вытаскивает фрагмент, где термины совпали, а смысл нет.

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

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

Особенно плохо работают конструкции вроде: сотрудник обязан сделать A, кроме случаев B, при согласовании с C, по форме D, в сроки E. После этого часто идет список 1.1, 1.2, 1.3, где каждое уточнение меняет смысл основного правила. Если чанк разрезал такой блок посередине, условие остается в одном фрагменте, а действие уходит в другой.

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

Пример

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

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

Каким должен быть чанк

Чанк - это не просто кусок текста на 500 или 800 символов. Хороший чанк держит одну законченную мысль, которую можно найти, понять и процитировать без догадок. Если после чтения фрагмента возникает вопрос "а к чему это относится?", граница выбрана плохо.

На русских регламентах и договорах это видно сразу. Такие документы любят длинные формулировки, ссылки на подпункты и фразы с исключениями. Если резать текст по длине, модель часто получает половину правила в одном куске, а вторую половину - в другом. Поиск находит "срок ответа 5 рабочих дней", но пропускает продолжение "кроме обращений по инцидентам ИБ". Ответ звучит уверенно, но ошибается в сути.

Чанк должен сохранять опору на источник. Минимальный набор - заголовок раздела, номер пункта и сам текст нормы. Без этого цитата становится почти бесполезной: фраза есть, а проверить ее трудно. Для договора разница между "п. 4.3 Ответственность сторон" и просто абзацем текста огромна. Для внутреннего регламента по обработке персональных данных номер пункта тоже нужен, иначе юрист или комплаенс-специалист не поймет, откуда взялось требование.

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

Чаще всего ломаются пары "правило + исключение" и "условие + последствие". Их нельзя разносить. В договоре это выглядит так: "Исполнитель платит неустойку..." и сразу следом "если просрочка возникла по вине заказчика, неустойка не начисляется". В регламенте то же самое: "доступ согласует руководитель" и тут же "для аварийных работ действует упрощенный порядок". Если такие связки попали в разные куски, поиск начинает путать обычный случай и особый.

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

Что дает разбиение по абзацам

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

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

Подход особенно хорошо работает там, где редактура уже дисциплинировала структуру:

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

Хороший пример - регламент согласования заявок. Один абзац может звучать так: "Срок согласования заявки составляет 3 рабочих дня с даты регистрации в системе". Если пользователь спрашивает о сроке, поиск достает именно этот фрагмент. Не нужен весь раздел про порядок работы отдела, где рядом лежат роли, исключения и ссылки на форму заявки.

Но у абзацев есть три частые проблемы. Первая - списки. Пункт списка сам по себе часто теряет смысл, если вводная фраза осталась в другом чанке. Фразу "К заявке прикладываются:" и подпункты лучше хранить вместе.

Вторая - сноски и примечания. Если сноска меняет смысл, например уточняет срок или исключение, ее стоит приклеить к абзацу. Если это просто ссылка на приказ или форму, ее лучше вынести в метаданные, чтобы не шумела в выдаче.

Третья - подпункты вроде 4.2 и 4.3. Они часто зависят от родительского пункта 4. Если отрезать их отдельно, модель увидит частность без общего правила. На практике помогает простое правило: хранить подпункт вместе с коротким заголовком или первой фразой родительского пункта.

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

Когда полезно резать по разделам

Разбиение по разделам хорошо работает там, где автор документа уже сам отделил одну тему от другой. В регламенте это часто видно по структуре: "Общие положения", "Порядок согласования", "Ответственность", "Контроль". В договоре логика похожая: "Предмет", "Права и обязанности сторон", "Оплата", "Срок действия".

Это один из самых простых стартов. Не нужно угадывать смысловые границы с нуля: их уже задал юрист, методолог или автор политики. Если заголовки чистые и повторяются от документа к документу, поиск обычно становится стабильнее.

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

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

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

С регламентами то же самое. Раздел "Порядок обработки обращений" может включать роли, сроки, каналы связи, исключения для VIP-клиентов и контроль качества. Для вопроса про срок ответа это уже слишком много.

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

Как собирать смысловые блоки

Проверьте RAG на живых вопросах
Гоняйте один набор запросов по разным моделям без смены SDK и кода.

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

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

Что склеивать в один блок

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

  • задают условие: "если", "при условии", "в случае"
  • вводят исключение: "кроме", "за исключением", "если иное не предусмотрено"
  • уточняют срок, сумму или ответственного
  • ссылаются на приложение, пункт или другую редакцию нормы

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

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

Договоры и регламенты ломаются в похожих местах. Проблемы создают длинные предложения с несколькими "если", ссылки вида "в порядке, предусмотренном п. 4.2", двойные отрицания, перечисления после двоеточия и обороты вроде "если иное не установлено". Еще один неприятный случай - когда правило стоит в одном пункте, а санкция или исключение уехали в подпункт ниже. Если это не склеить, поиск отвечает уверенно, но мимо смысла.

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

Один вопрос к регламенту и договору

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

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

Разбиение по разделам сработает надежнее. Если оба пункта лежат внутри раздела "Порядок согласования исключений", поиск почти наверняка поднимет весь кусок. Но вместе с ответом приедут общие правила, роли, ссылки на формы и еще полстраницы текста. Для генерации это уже шум.

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

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

На таком вопросе три схемы обычно ведут себя так:

  • Абзацы дают точное попадание в формулировку, но часто режут связку "кто + срок" или "санкция + условие".
  • Разделы реже теряют смысл, но почти всегда приносят лишний текст.
  • Смысловые блоки чаще возвращают полный ответ без перегруза, если вы склеиваете соседние пункты по роли, действию и условию.

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

Как выбрать схему шаг за шагом

Запустите open-weight модели в РФ
Проверьте варианты с низкой задержкой на российских GPU и не меняйте код.

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

Если пустить все документы под одну сетку, поиск начнет промахиваться. Регламент чаще выигрывает от мелких кусков, а договор - от более крупных, потому что смысл там живет не в одном абзаце, а в связке пункта, подпункта и оговорки рядом.

  1. Разделите корпус по типу структуры. Отдельно держите регламенты с четкими пунктами, отдельно договоры, отдельно приложения, формы и шаблоны. Смотрите не на тематику, а на то, как документ отвечает на вопрос.
  2. Назначьте базовую единицу для каждой группы. Для регламента это часто абзац или пункт, если норма помещается целиком. Для договора обычно лучше брать пункт вместе с подпунктами, иначе срок, ответственность и исключения разъедутся по разным чанкам.
  3. Добавляйте overlap только там, где мысль рвется на границе. Если пункт 4.2 задает правило оплаты, а 4.3 сразу описывает исключение, небольшой overlap оправдан. Если абзацы независимы, overlap только раздует индекс и добавит шум.
  4. Прогоните схему на 20-30 живых вопросах. Нужны вопросы из реальной работы: "кто согласует исключение", "когда наступает штраф", "какой срок ответа по обращению". Смотрите не только на попадание, но и на лишний текст рядом.
  5. Зафиксируйте правила на время теста. Если вы меняете размер чанка, overlap и очистку текста после каждого запроса, сравнение теряет смысл. Один прогон - одна схема.

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

Хорошая схема не обязана быть универсальной. Намного полезнее иметь 2-3 понятные схемы под разные типы русских документов, чем одну общую, которая одинаково плохо режет и регламент, и договор.

Ошибки, которые портят выдачу

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

Когда режут слишком механически

Частая ошибка - отрывать заголовок от первого пункта. В регламенте заголовок "Порядок согласования платежей" может жить в одном чанке, а пункт 4.1 "Финансовый контролер проверяет заявку в течение 1 рабочего дня" - уже в другом. Тогда запрос про согласование платежей находит сухую норму без темы, а запрос по теме находит заголовок без действия. Оба фрагмента выглядят слабо.

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

Еще одна частая поломка - смешивать приложение с основным текстом. Например, в договоре поставки приложение с формой акта, таблицей SKU и тарифами попадает в тот же набор чанков, что и раздел про порядок приемки. В результате запрос про срок подписания акта уводит поиск в шаблон приложения, хотя ответ есть в основном тексте договора.

Когда теряется смысл термина

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

На практике помогает простое правило: если термин из раздела 1 сильно влияет на трактовку пунктов 7, 8 и 10, его нельзя оставлять в полном отрыве. Либо подтягивайте определение в соседние чанки, либо добавляйте явную связь через метаданные.

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

Если после индексации в топ-10 лежат почти одинаковые чанки, проблема уже видна. Если ответ на запрос теряет тему раздела, путает приложение с договором или игнорирует определение термина, причина почти всегда в схеме разбиения, а не в модели.

Быстрая проверка перед запуском

Сравните 500+ моделей
Быстро найдите, какая модель лучше держит цитату из регламента или договора.

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

Хороший тест занимает меньше часа. Возьмите 10-15 фрагментов из регламента и 10-15 из договора. Добавьте в выборку обычные пункты, длинные списки, таблицы и места с исключениями вроде "кроме случаев" или "если иное не указано".

  • Из каждого чанка должно быть ясно, кто делает что и когда. Если субъект остался в одном куске, срок во втором, а условие в третьем, такой чанк уже сломан.
  • Чанк должен хранить метаданные: номер раздела, номер пункта, версию документа, а лучше еще тип документа и дату действия. Без этого вы найдете смысл, но не докажете источник.
  • По короткой цитате из ответа человек должен быстро открыть исходник и попасть в нужное место. Если аналитик тратит на это несколько минут, проблема почти всегда в плохой привязке чанка к документу.
  • Тесты должны отдельно проверять списки, таблицы и исключения. В договорах штрафы, сроки оплаты и основания для расторжения часто живут именно там, а не в обычных абзацах.
  • Одна и та же схема должна нормально работать и на регламенте, и на договоре. Если на регламенте все точно, а договор распадается на бессвязные куски, не пытайтесь лечить это только поиском. Сначала поправьте разбиение.

Мини-тест на цитируемость

Попросите систему ответить на 5 простых вопросов и вернуть цитату. Затем проверьте две вещи: ответ не теряет условие, а цитата ведет в конкретный пункт, а не в близкий по теме раздел.

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

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

Что делать после первого теста

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

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

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

Смотрите не только на попадание в нужный документ. Для регламентов и договоров важнее другое: попал ли поиск в точную цитату, которую можно показать человеку без риска исказить норму. Если запрос звучит как "когда можно расторгнуть договор в одностороннем порядке", система может привести в правильный раздел, но пропустить оговорку с исключениями в соседнем абзаце. Формально документ найден, по сути ответ уже опасный.

Удобно проверять результаты по простой сетке:

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

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

Если вы тестируете такие схемы в российском контуре, это удобно делать через RU LLM. Сервис дает один OpenAI-совместимый endpoint для разных моделей, а логи, биллинг и хранение остаются внутри РФ. За счет этого проще прогонять одинаковые тесты для нескольких вариантов чанкинга, не меняя SDK, код и промпты.

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

Часто задаваемые вопросы

Почему поиск по русским документам часто дает неверный фрагмент?

Чаще всего виноват не эмбеддинг, а сам текст. Русские регламенты и договоры прячут условие или исключение в конце длинной фразы, а поиск цепляется за общие слова и тащит похожий, но чужой по смыслу кусок.

Когда разбиения по абзацам уже достаточно?

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

В каких случаях лучше резать по разделам?

Разделы удобны на старте, когда документ держит чистую структуру и заголовки честно делят темы. Если раздел растягивает в один блок сроки, роли, штрафы и исключения, поиск принесет слишком много шума.

Как понять, что чанк получился хорошим?

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

Какие части текста нельзя расклеивать по разным чанкам?

Не разносите пары правило + исключение и условие + последствие. В договоре это часто штраф и оговорка о том, когда его не начисляют, а в регламенте — общий порядок и упрощенный режим для особого случая.

Нужен ли overlap и сколько его делать?

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

Что делать со списками, подпунктами и вложенными пунктами?

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

Как работать с определениями терминов?

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

Как быстро проверить чанкинг перед запуском?

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

Что обычно лучше для регламентов, а что для договоров?

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