Всем привет!
Я иногда занимаюсь построением RAG-пайплайнов и столкнулся с проблемой чанкинга. Часто чанкинг выполняется весьма примитивно: текст разбивается на группы токенов одинакового размера без учёта семантики. Люди же для повышения читабельности текстов делают свой "человеческий" чанкинг совершенно по-другому: на абзацы, то есть семантически однородные текстовые отрезки из одного или нескольких предложений ("сверхфразовые единства", как назвали бы это лингвисты).
Соответственно, я решил, что мне не помешает хороший, правильный чанкинг. Умный чанкинг. И я решил сделать его для себя. Основная идея умного чанкера - воспроизвести семантическое разбиение текста на чанки, характерное для людей, что повышает качество структуризации текстового корпуса и положительно влияет на работу RAG-системы.
Алгоритм умного чанкинга состоит из следующих шагов.
Шаг 1. Весь текст разбивается на отдельные предложения. Если язык текста - английский, то для разбиения на предложения используется функция sent_tokenize из библиотеки nltk, а если язык текста - русский, то для этой цели применяется функция sentenize из библиотеки razdel. Кроме того, дополнительным критерием завершения предложения может выступать наличие символа перехода на новую строку (опционально).
Шаг 2. Генерируется множество вариантов разбиения текста на два чанка:
вариант 1: первый чанк включает в себя первое предложение, а второй чанк - оставшиеся предложения со второго по последнее;
вариант 2: первый чанк включает в себя первое и второе предложение, а второй чанк - оставшиеся предложения с третьего по последнее;
вариант 3: первый чанк включает в себя первое, второе и третье предложения, а второй чанк - оставшиеся предложения с четвёртого по последнее;
и так далее…
Шаг 3. С помощью кросс-энкодера (например, BAAI/bge-reranker-v2-m3
или Alibaba-NLP/gte-multilingual-reranker-base
) для каждого из вариантов разбиения текста на пару чанков считается семантическое сходство между первым и вторым чанками.
Шаг 4. Итоговым вариантом разбиения текста на два чанка считается такой вариант, для которого семантическое сходство между первым и вторым чанками минимально.
Для каждого из двух выделенных чанков описанная процедура повторяется рекуррентно до тех пор, пока чанки не получатся достаточно маленькими (меньше, чем наперёд заданная максимально допустимая длина чанка).
Получилось, кажется, неплохо. Экспертная оценка тестовых текстов показывает весьма "семантическое" разбиение на чанки по границам семантических переходов.
Делал для себя, но если вдруг кому-то ещё этот умный чанкер окажется полезным, то буду рад 😊
https://github.com/bond005/smart_chunker
>>Click here to continue<<
