Технологии

Как резать текст для поиска: стратегии чанкинга и как подобрать размер

Размер чанка — компромисс между полнотой и точностью. Пять стратегий с их слабостями и процедура подбора размера на своём корпусе вместо универсального совета «512 токенов».

«Режьте по 512 токенов с перекрытием в 50» — самый частый совет по чанкингу и самый бесполезный. Он не спрашивает, что у вас за тексты и какие к ним задают вопросы, а от этих двух вещей зависит всё. На переписке в мессенджере кусок в 512 токенов склеит пять несвязанных разговоров. На техническом регламенте он разрежет пункт пополам, и в индекс попадёт условие без его следствия.

Этот текст — про то, как выбрать размер осознанно и как проверить выбор измерением, а не ощущением.

#Зачем вообще резать

Причин ровно три, и они разной природы.

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

Размывание смысла. Вектор длинного разнородного куска — это усреднение всех тем в нём. Такой вектор оказывается умеренно близок ко всему и по-настоящему близок ни к чему: длинные чанки систематически проигрывают в выдаче.

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

Обратная сторона: слишком мелкие куски теряют контекст. Фрагмент «да, согласен, делаем так» без предыдущей реплики не значит ничего, и вернуть его в выдаче — то же самое, что не вернуть.

#Пять стратегий и чем каждая платит

Стратегия Как режет Слабое место
Фиксированный размер N символов или токенов подряд Рвёт предложения и мысли посередине
С перекрытием То же, но соседние куски делят хвост Дубли в выдаче, индекс растёт
По структуре По абзацам, заголовкам, пунктам списка Требует, чтобы структура была; на переписке бесполезна
По смысловым границам Там, где меняется тема Дороже: нужна отдельная модель или эвристика
По естественной единице Сообщение, комментарий, запись Единицы очень разной длины

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

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

#Когда чанкинг не нужен вовсе

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

Persona так и устроена: единица индексации — одно сообщение чата целиком. Отдельного слоя чанкинга в коде нет. Перед отправкой в эмбеддер текст обрезается до восьми тысяч символов (app/memory_vec.py), и это не стратегия нарезки, а защита от аномально длинной вставки. Реального документного RAG — с загрузкой файлов, нарезкой и отдельной таблицей чанков — в продукте нет, и говорить, что он есть, было бы неправдой.

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

#Процедура подбора размера на своём корпусе

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

  1. Соберите двадцать реальных вопросов к своему корпусу. Не придуманных — тех, которые вы действительно задаёте. Двадцати достаточно, чтобы увидеть систематику; на пяти видно только шум.
  2. Для каждого вопроса выпишите эталон — какой именно фрагмент документа обязан оказаться в выдаче. Это самая трудоёмкая часть, и её нельзя пропустить: без эталона измерять нечего.
  3. Нарежьте корпус тремя способами — например, короткие куски, средние и по структуре — и постройте три отдельных индекса.
  4. Прогоните двадцать вопросов по каждому индексу и посчитайте одно число: в скольких случаях эталонный фрагмент попал в первые пять результатов.
  5. Посмотрите на промахи, а не на среднее. Если короткий вариант проигрывает только на вопросах «что решили в итоге», значит проблема не в размере, а в потере контекста — добавляйте к чанку заголовок раздела.

Шаг 5 важнее шага 4. Среднее по двадцати вопросам скажет вам, какой вариант лучше; разбор промахов скажет, что чинить.

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

#Что добавить к чанку кроме текста

Кусок, вырванный из документа, теряет всё, что было вокруг. Три дешёвых приёма возвращают потерянное.

Заголовок родителя в текст чанка. Не в метаданные, а прямо в индексируемую строку: «Регламент отпусков → Перенос дней → …». Вектор от этого становится осмысленнее, а выдача — читаемее.

Дата и источник. Для персональной памяти это обязательное поле: без даты нельзя понять, актуален ли факт. В Persona каждая строка выдачи recall выводится с датой и названием чата — форматирование задано в recall_by_terms, и это не косметика, а способ дать модели основание предпочесть свежее.

Роль говорящего. В диалоге «я предложил» и «мне предложили» — разные факты, и без пометки роли модель их путает.

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

#Как чанкинг связан со сжатием старого

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

Общая схема слоёв — что хранится дословно, что в сводке, что в виде отдельных фактов — описана в статье о том, как работает память у ИИ. Чанкинг относится только к первому слою; попытка решить им задачи двух других обречена.

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

#Какой размер чанка взять, если мерить некогда?

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

#Нужно ли перекрытие?

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

#Влияет ли размер чанка на скорость поиска?

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

#Можно ли резать по смыслу автоматически?

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

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

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

#Вывод

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

Хотите ИИ, который помнит вас?

Persona держит контекст между чатами и работает на вашем железе — если развернуть её у себя и подключить локальную модель.

Создать аккаунт