Выбор фрагментов без запроса: использование алгоритма K-Means, когда у RAG нет вопросов для задания.
При отсутствии запроса от пользователя RAG не может выбрать контекст. Пусть K — это количество результатов; сгруппируйте эмбеддинги фрагментов с помощью метода k-средних, сохраняя фрагменты-центроиды и их исходные данные.
Источники: You Don’t Need RAG. You Need Semantic Compression.
Некоторые проблемы в области больших языковых моделей не имеют названия, специальных фреймворков или обширной литературы. Описываемая здесь проблема выглядит следующим образом: очень большой объем текста, отсутствие вопроса от пользователя, и необходимость выбрать те части текста, которые следует передать модели, чтобы были охвачены все темы и каждая часть могла быть отнесена к своему источнику.
Это не генерация с усилением с помощью поиска, поскольку ничего не ищут. Это не сжатие промптов и не краткое изложение. Исследовательское сообщество пока не дало для нее четкого определения, а стандартные инструменты не справляются с ней. Далее описывается сама проблема, показано, почему существующие методы недостаточны, и предлагается простое решение, которое совпадает с академическими идеями и заполняет пробел, оставленный в этих работах.
Когда нечего искать
Каждый, кто занимался разработкой с использованием больших языковых моделей в течение последних нескольких лет, знаком с циклом RAG: пользователь задаёт вопрос, запрос инкорпорируется, из векторного хранилища возвращаются похожие фрагменты, они включаются в промпт, и на их основе генерируется ответ. Эта схема элегантна, хорошо задокументирована и поддерживается всеми крупными фреймворками. Однако она косвенно предполагает наличие запроса.
Часто его нет. Фреймворки вроде LangChain и LlamaIndex построены вокруг запросов и процесса поиска информации, а большинство статей о сжатии контекста также исходят из наличия запроса. При поиске способов выбора наилучших фрагментов для большой языковой модели каждый найденный вариант предполагает наличие вопроса пользователя, который направляет процесс выбора.
Рассмотрим приложение для обучения. Студенты загружают учебные материалы: учебники, презентации, транскрипты видео, рукописные заметки — иногда сотни страниц. Они не ищут ничего конкретного; по сути, они говорят: «Вот мои курсы, сделайте для меня учебные материалы». Система должна затем генерировать структурированные результаты вроде тестовых листов, карточек для запоминания, кратких изложений и карт концепций. Каждый результат должен охватывать отдельную тему и указывать источник, при этом общий объем исходных данных значительно превышает размер окна контекста.
Три требования одновременно
Существующие подходы нарушают по крайней мере одно из трех ограничений, налагаемых одновременно в данном случае использования.
- Отсутствие сигнала запроса. Ничто из данных пользователя не направляет процесс выбора, поэтому системе приходится самостоятельно определять, что является важным, исходя только из данных.
- Гарантированный тематический охват. Результатом является набор материалов, в совокупности охватывающих всю тематику. Игнорирование целой темы — серьезная ошибка; тест по биологии, в котором совсем нет вопросов по генетике, бесполезен.
- Возможность отслеживания источника. Каждый результат должен указывать на конкретный фрагмент исходного текста, например: «основано на главе 3, страницах 12–14 учебника по биохимии». В образовании это не является факультативным, поскольку студентам необходимо знать, где продолжить чтение.
Ни один существующий метод не позволяет одновременно удовлетворить всем трем требованиям. В этом и заключается пробел.
Что предлагает литература и где она останавливается
Почему метод отправки всего материала неэффективен
Наивный подход заключается в том, чтобы поместить весь материал в окно контекста. Поскольку модели могут обрабатывать от 128 тыс. до 200 тыс. токенов, кажется логичным, что это сработает. Однако это не так. Исследование «Потеряно посередине» показало кривую производительности в форме буквы U: модели хорошо справляются с началом и концом контекста, но постоянно упускают информацию, находящуюся посередине. Точность снижалась более чем на 30%, когда ключевой контент перемещался с краев в центр, даже у моделей, разработанных для обработки длинных контекстов.
Таким образом, даже когда всё помещается в окно контекста, большие части материала игнорируются. В таком случае тест будет охватывать только первую и последнюю главы, игнорируя остальные. Больший объём контекста не означает лучшего контекста.
Компрессия промптов отвечает на другой вопрос
Всё больше исследований направлено на сокращение объёма входных данных путём удаления избыточных токенов до того, как они достигнут модели.
В методе Selective Context используется небольшая языковая модель для вычисления самоинформации лексических единиц — будь то токены, существительные или предложения, — и отбрасываются те, у которых эта величина невелика. Для его работы не требуется запрос, что соответствует первому ограничению. Однако он фильтрует информацию внутри существующего текста, создавая его сжатую копию, а не выборку репрезентативного контента по разным темам. Он не может гарантировать полное охват, к тому же изменённый текст теряет прямую связь с исходными фрагментами, поэтому второе и третье ограничения не соблюдаются.
LLMLingua и LLMLingua-2 развивают эту идею с помощью итеративного сжатия и классификаторов токенов, обучаемых на данных, достигая коэффициента сжатия до 20 раз. У них также присутствует одно и то же основное ограничение: текст сжимается для работы машины, а не для удобства человека. В результате получается запрос, который модель может обработать, но не структурированный набор контента, который можно было бы отследить.
RECOMP обучает компрессоры, способные кратко излагать содержимое или извлекать информацию из полученных документов как с использованием метода извлечения, так и метода абстракции. Это самый сложный из данной группы инструментов, однако ему явно требуется запрос, чтобы определить, что сохранять, поэтому он не соответствует первому ограничению.
Короче говоря, компрессия с использованием промптов снижает количество токенов. Она не выбирает репрезентативный контент, не гарантирует охвата темы и не сохраняет структуру исходного текста.
Ранжирование с использованием графов лишь отображает информацию, но не организует её
TextRank и LexRank создают граф сходства между предложениями и применяют алгоритм PageRank для выявления наиболее центральных из них, то есть тех, которые наилучшим образом отражают суть всего документа. Для их работы не требуется запрос, и в течение двух десятилетий они оставались стандартом для ненадзорного извлекательного резюмирования. Их известным недостатком является избыточность: похожие предложения получают схожий уровень центральности, поэтому лучшие варианты часто повторяют друг друга, но с другими словами. Резюме биологического учебника с использованием TextRank может включать три предложения об репликации ДНК и ни одного о синтезе белков, просто потому что репликация упоминается чаще.
Это снижает полноту охвата, даже если основные темы обычно присутствуют, к тому же поскольку методы работают с предложениями, возможность отслеживания информации обеспечивается лишь частично.
Кластеризация — наиболее близкий вариант
Суммаризация на основе кластеризации с использованием алгоритмов K-means, HDBSCAN или аналогичных, применяемых к эмбеддингам предложений, объединяет похожие предложения в тематические кластеры и выбирает по одному представителю из каждого. Это эффективно устраняет избыточность: каждый кластер вносит по одному предложению, причем разные кластеры охватывают разные темы.
Самый современный и эффективный метод в этой области — «Graphs in Clusters» — сочетает алгоритм K-means с TextRank. Сначала производится кластеризация для обеспечения полноты охвата, затем внутри каждого кластера определяется его важность с помощью ранжирования. Этот метод превосходит как чисто графовые, так и чисто кластерные методы на тестах с длинными документами, таких как ArXiv и PubMed.
Это ближайший аналог, но он отличается в нескольких важных аспектах. Его цель — получение одного однородного текстового резюме, тогда как здесь цель — N структурированных результатов. Здесь значение K подбирается с помощью метода локтя, в то время как здесь K определяется по запросу пользователя. Он работает с предложениями, тогда как здесь требуется более крупная гранулярность блоков для сохранения метаданных исходного текста. Его кластеры представляют собой невидимый промежуточный этап, тогда как здесь они являются окончательными результатами. Кроме того, у него нет концепции обязательного отслеживания исходного текста.
Сравнение
При наличии этих трех ограничений проявляется определенный паттерн. RAG сохраняет исходные источники, но требует запроса и не может гарантировать полный охват. Selective Context и LLMLingua не нуждаются в запросе, но утрачивают структуру источника и не могут обеспечить полный охват. RECOMP также требует запроса. TextRank и LexRank работают без него, но дают избыточный результат и слабую возможность отслеживания. Суммаризация с помощью кластеризации удовлетворяет первым двум ограничениям: не требует запроса и гарантирует полный охват, однако работает на уровне предложений, что прерывает связь с исходным источником.
Не существует устоявшегося метода выбора фрагментов, который бы не требовал запроса, гарантировал полный охват и позволял отслеживать источник.
Использование кластеризации в обратном порядке
Решение заключается в изменении способа использования кластеризации в обычных задачах обработки естественного языка. В литературе K считается гиперпараметром: исследователи пробуют значения K=5, K=10, K=50, строят графики оценок силуэта или кривых инерции и выбирают «лучшее» значение. Кластеры представляют собой математические объекты, служащие алгоритму, и пользователь никогда их не видит.
В данном подходе K является параметром, определяемым требованиями пользователя: если студент просит 10 тестовых листов, то K устанавливается равным 10; пять страниц резюме соответствуют K=5, а тридцать карточек для запоминания — K=30. Каждый кластер соответствует ровно одному результату. Кластер не является промежуточной абстракцией — он сам по себе является конечным продуктом. Тест по митозу существует потому, что в семантическом пространстве загруженного контента существует кластер фрагментов, связанных с митозом.
Существующие методы используют кластеризацию для сжатия текста для машины. Этот метод применяет кластеризацию для организации контента для человека.
На последующих этапах это меняет всё. Традиционно значение K настраивается математически, кластеры остаются скрытыми, а после кластеризации формируется однородное резюме. Здесь значение K определяется на основе запроса: каждый кластер становится тем, что получает пользователь, причём каждый кластер запускает один вызов большой языковой модели, в результате чего получается выходной результат с указанием источника.
Пятиэтапная процедура
1. Разбиение на фрагменты. Документы делятся с помощью стандартных инструментов из LlamaIndex или LangChain или по пользовательским правилам. Каждый фрагмент сохраняет свой текст, исходный файл, номер страницы, позицию и любые другие метаданные. Типичный размер составляет от 500 до 1000 токенов; соседние фрагменты перекрываются на 10–20%, что является компромиссом между сохранением целостности идей и высокой степенью детализации кластеров. Фрагменты по желанию можно дополнить резюме, ключевыми словами или метками сущностей, что способствует кластеризации, но не является обязательным.
2. Встраивание. Каждый фрагмент преобразуется в плотный вектор. Выбор модели зависит от конкретных требований: Sentence-Transformers — это быстрый и бесплатный базовый вариант, текст-embedding-3-small от OpenAI эффективен для разных языков, а Mistral Embed и Cohere Embed представляют собой конкурентоспособные альтернативы. Важно то, что семантически близкие фрагменты всегда дают близкие векторы, независимо от словарного запаса.
3. K-средние. Это ключевой этап. Метод K-средних делит пространство векторов на ровно K групп, причем значение K определяется количеством результатов, необходимых пользователю:
from sklearn.cluster import KMeans
n_outputs = 10 # User wants 10 quiz sheets
kmeans = KMeans(n_clusters=n_outputs, random_state=42, n_init=10)
kmeans.fit(embeddings)
Следуют три свойства, которые напрямую отвечают на три ограничения. Запросы не требуются, поскольку алгоритм K-means группирует элементы по степени их сходства, а не по релевантности к внешнему сигналу. Обеспечивается полное охват тем, поскольку каждый элемент попадает ровно в один кластер, и каждая тема в данных представлена. Устраняется избыточность, поскольку элементы, содержащие одинаковую информацию, имеют схожие векторы представления, собираются вместе и формируют один представительный пример.
4. Выбор представителя. Для каждого кластера берется элемент, находящийся ближе всего к центроиду, который наилучшим образом отражает тему кластера:
import numpy as np
selected = []
for i in range(n_outputs):
cluster_indices = np.where(kmeans.labels_ == i)[0]
centroid = kmeans.cluster_centers_[i]
distances = np.linalg.norm(
embeddings[cluster_indices] - centroid, axis=1
)
best_local_idx = np.argmin(distances)
best_global_idx = cluster_indices[best_local_idx]
selected.append(chunks[best_global_idx]) # Full chunk with metadata
Выбранный фрагмент сохраняет всю свою первоначальную метаданные, поэтому ничего не теряется, и всё можно цитировать. Для более подробных результатов вместо одного фрагмента можно использовать три самых близких фрагмента к центроиду; принцип остаётся прежним.
5. Генерация. Выбранные фрагменты каждого кластера передаются в LLM вместе с запросом, соответствующим типу результата, причём метаданные исходного материала также передаются, чтобы модель могла их цитировать. Кластер 1 генерирует тест №1, ссылаясь на страницы 12–14 первого PDF. Кластер 2 генерирует тест №2, ссылаясь на транскрипт видео в момент 14:30. Такой порядок повторяется до кластера K.
Когда количество не указано
Не каждый пользователь просит десять тестов; некоторые просто хотят «один тест» или «краткое резюме». Подойдут три альтернативных метода. Метод бюджета токенов заключается в разделении эффективного контекста модели на средний размер фрагментов: для модели с 16 тыс. токенов и фрагментами по 800 токенов значение K составляет примерно 20. Метод «локтя» предполагает пробу нескольких значений K и выбор того момента, когда снижение инерции прекращается значимым образом. Также сработает приблизительное правило — один кластер на 5–10 страниц исходного текста. На практике метод бюджета токенов является наиболее надежным, поскольку он напрямую связан с возможностями обработки модели.
Что гарантирует этот метод
Это математические свойства алгоритма K-means, а не эмпирические наблюдения.
- Покрытие. Каждая точка присваивается кластеру, поэтому ни один фрагмент не остается без принадлежности. Если тема существует, она относится к кластеру, имеющему её представителя. В отличие от этого, метод Top-K может вернуть K фрагментов, связанных с одной популярной темой, полностью проигнорировав другие.
- Отсутствие дублирования. Похожие фрагменты группируются вместе, причем каждая группа представлена лишь одним фрагментом. Два фрагмента, излагающих одно и то же, но с разными словами, находятся в одном кластере, при этом сохраняется только один из них.
- Регулируемая степень детализации. Небольшое значение K приводит к обширным кластерам для широких тем, а большое значение K — к более узким кластерам для конкретных понятий; пользователь может управлять этим параметром при формировании запроса.
- Сохранение исходных данных. Работа с фрагментами, а не с токенами или предложениями, позволяет сохранить полную цепочку метаданных для каждого выбранного элемента. Компрессия на уровне токенов по своей сути не может обеспечить такую сохранность.
Чего ему не хватает
Сферические предположения. Метод K-means предполагает примерно круглые кластеры, однако пространства эмбеддингов не всегда имеют такую структуру. Тема с сложной, неконвексной формой может быть разделена между несколькими кластерами. HDBSCAN или модели гауссовых смесей могут помочь, хотя они не гарантируют точное количество K кластеров.
Типичный, но не обязательно информативный. Фрагмент, находящийся ближе всего к центроиду, считается наиболее типичным. Запуск алгоритма TextRank внутри каждого кластера, как это делается в методе Graphs in Clusters, позволил бы сделать более тонкий выбор и является многообещающим улучшением.
Короткие темы сжимаются. Если материал на 95% состоит из биологии и на 5% — из химии, то химия, скорее всего, получит один кластер, в то время как биология — от K до 1. Кластер по химии существует, но сжат пропорционально. Для решения этой проблемы можно использовать взвешенную или стратифицированную схему.
Качество блоков определяет всё. Если разделение на блоки делит концепцию пополам или смешивает несвязанные темы, кластеризация наследует эти недостатки. Качественное разделение на блоки с семантическим разбиением, перекрытием и обогащением метаданными является обязательным требованием.
Сравнение за один проход
RAG работает быстро и сохраняет исходные источники, но требует запроса и может вернуть K фрагментов по одной теме. Selective Context и LLMLingua также быстры и не требуют запросов, однако они удаляют структуру источников и не могут гарантировать полное покрытие. RECOMP мощен, но зависит от запроса. TextRank и LexRank работают быстро и не требуют запросов, однако покрытие остается частичным из-за избыточности информации, а возможность отслеживания прерывается на уровне предложений. Метод Graphs in Clusters не требует запросов и обеспечивает хорошее покрытие, но работает только с предложениями и удаляет метаданные источников. Суммаризация с использованием MapReduce также не требует запросов, однако покрытие остается частичным, ссылки на источники исчезают в процессе суммаризации, к тому же этот метод медленный, так как требует нескольких проходов больших языковых моделей.
Описанный здесь метод выбора групп с использованием алгоритма K-means — единственный вариант, который работает без запроса, гарантирует тематическое покрытие по своей сути, сохраняет полную прослеживаемость на уровне групп, выполняется менее чем за секунду и не требует ни отрегулированных моделей, ни векторной базы данных.
Название проблемы
Проблема заключается не столько в технической сложности, сколько в отсутствии определенного названия. Если искать RAG, появляются тысячи результатов. Если искать методы сжатия промптов, находится LLMLingua. Если искать методы извлекающего резюмирования, появляются TextRank, LexRank и методы на основе BERT. Но если спросить, как выбрать лучшие группы из большого корпуса без запроса для максимизации тематического покрытия при сохранении прослеживаемости исходного текста, ответов практически нет.
Подходящим названием для этого явления является семантическое сжатие без запросов. Это не поиск, поскольку запрос отсутствует. Это не краткое изложение, поскольку на этом этапе не генерируется новый текст. Это не сжатие под вводные данные, поскольку из существующего текста не удаляются токены. Это выбор с гарантированным охватом: выбор наименьшего набора фрагментов, который отражает наибольший объем материала, при этом сохраняется связь с документами.
Проблема возникает там, где система преобразует большие объемы контента, предоставленные пользователем, в структурированные результаты без явной цели поиска. Примерами могут служить учебные материалы из курсов, отчеты из больших коллекций документов, краткие извлечения из часовых записей собраний, обзоры из большого количества запросов на изменения кода, а также юридический анализ, где важен охват всех положений, а не ответ на один вопрос.
Метод K-means является одним из решений, пожалуй, самым простым. Гибридные подходы, сочетающие кластеризацию с ранжированием на основе графов, оценкой информационной плотности или кратким использованием небольших языковых моделей для обнаружения тем, могут дать лучшие результаты, причем в этой области ещё много возможностей.
Всё в коде
Полный процесс отбора помещается менее чем в 50 строк:
from sentence_transformers import SentenceTransformer
from sklearn.cluster import KMeans
import numpy as np
def select_representative_chunks(chunks, n_outputs, model_name='all-MiniLM-L6-v2'):
"""
Select the most representative chunks from a large corpus
using K-means clustering. One cluster = one output.
Args:
chunks: list of dicts with 'text', 'source', 'page', etc.
n_outputs: number of outputs the user wants (= K)
model_name: embedding model to use
Returns:
list of selected chunks with cluster metadata
"""
# Embed
model = SentenceTransformer(model_name)
embeddings = model.encode([c['text'] for c in chunks], show_progress_bar=True)
# Cluster
kmeans = KMeans(n_clusters=n_outputs, random_state=42, n_init=10)
kmeans.fit(embeddings)
# Select representatives
selected = []
for i in range(n_outputs):
cluster_indices = np.where(kmeans.labels_ == i)[0]
centroid = kmeans.cluster_centers_[i]
distances = np.linalg.norm(embeddings[cluster_indices] - centroid, axis=1)
best_local_idx = np.argmin(distances)
best_global_idx = cluster_indices[best_local_idx]
selected.append({
'cluster': i,
'chunk': chunks[best_global_idx],
'distance_to_centroid': float(distances[best_local_idx]),
'cluster_size': len(cluster_indices),
})
return selected
На этапе выбора не используется никакая векторная база данных, никакой пайплайн по поиску, никакая отрегулированная модель и никакие вызовы LLM. Для этого достаточно эмбеддингов, кластеризации и выбора центроида.
Где это применялось на практике
Пайплайн был создан и опробован внутри учебного приложения, которое генерирует интерактивные учебные материалы — викторины, карточки для запоминания, краткие изложения и карты концепций — на основе всего, что загружает студент: конспектов лекций, учебников, транскриптов видео и слайдов. В приложении также предусмотрены инструменты, адаптированные для учащихся с дислексией, СДВГ или другими когнитивными трудностями, а также элементы геймификации. Проект все еще находится в стадии активных исследований и разработок, в настоящее время доступен на французском языке, планируется версия на английском.
В таких условиях слой K-means отвечает за выбор контента. Объединение 500 фрагментов занимает менее секунды, метод хорошо масштабируется, а тематическое покрытие сохраняется даже при работе с совершенно разными источниками — от подробных учебников по биологии до разрозненных записей лекций.
Почему концепция преднамеренно проста
Выбор репрезентативных фрагментов из большого корпуса без использования запросов, с обеспечением тематического покрытия и возможностью отслеживания источников — это более распространенная потребность, чем указывается в литературе. Любой, кто создает инструменты на основе больших языковых моделей для образования, составления отчетов, анализа собраний или юридического рассмотрения, вероятно, сталкивался с подобной задачей.
Подход преднамеренно прост. Метод K-means существует уже десятилетия, а векторизация предложений является стандартным инструментом. Особенность данного решения заключается в формулировке задачи: использовать намерение пользователя в качестве параметра K, рассматривать каждый кластер как результат обработки и сохранять цепочку связи между фрагментом и источником на протяжении всего процесса.
Ещё остаётся пространство для улучшений. Кластеризацию можно сочетать с ранжированием на основе графов, оценкой информационной плотности или использованием лёгких моделей LLM для обнаружения тем. Выбор центроида можно заменить на более тонкий подход, такой как ранжирование внутри кластеров, выбор на основе критерия разнообразия или вызов небольшой модели LLM для выбора наиболее информативного фрагмента. Эта идея предназначена для использования, адаптации и усовершенствования.
Связанные материалы
- Ponовление ранжирования в RAG: кросс-энкодеры против моделей LLM и их задержки — Как вторичный механизм ранжирования исправляет порядок кандидатов в RAG, сравнение кросс-энкодеров с моделями LLM, затраты на задержку, способы сбоев и способы их оценки.
- Получение данных для производственных систем RAG в банках: PDF-файлы, OCR, таблицы и соединители — Как загружать банковские документы в системы RAG: классификация PDF-файлов, выполнение OCR с флагами для проверки, сохранение структуры документов в формате Word, обработка таблиц и изображений, а также создание надежных соединителей.