В мире информационного поиска и семантических моделей долгое время доминировала парадигма «сжатия». Классические плотные эмбеддинги (dense embeddings) берут целый фрагмент текста — будь то короткое предложение или длинный абзац — и сжимают его в один фиксированный вектор. Этот вектор, состоящий из сотен или тысяч чисел, должен уместить в себе весь смысл исходного текста. Подобный подход работает удивительно хорошо для многих задач, но он обладает фундаментальным недостатком: сжатие является необратимым и «потерянным» (lossy). Редкие сущности, точные идентификаторы или критически важные детали могут быть «размыты» или потеряны при усреднении признаков в единой точке пространства.
На смену этой парадигме приходят multi-vector модели, также известные как модели late-interaction (позднего взаимодействия) или ColBERT-подобные модели. Вместо того чтобы сжимать текст в один вектор, они сохраняют отдельный вектор для каждого токена. Это позволяет сохранить детальную информацию на уровне токенов, которая обычно теряется при агрегации. В результате мы получаем значительно более точный поиск, особенно для сложных запросов с несколькими требованиями, хотя и ценой увеличения размера индекса. В этой статье мы подробно разберем, как работают эти модели, как их использовать в библиотеке Sentence Transformers v6.0 и какие компромиссы они предлагают.

01Что такое Multi-Vector Модели?
Чтобы понять разницу, давайте сравним два подхода. Плотная модель эмбеддинга читает текст и возвращает один вектор фиксированного размера (например, 384, 768 или 1024 измерения). Все, что заметила модель, должно уместиться в эти числа. Подобие между двумя текстами вычисляется как одно скалярное произведение между двумя такими «сжатыми» суммарными представлениями. Это работает хорошо, но сжатие происходит за счет потери информации. Например, если вы ищете «зеленый диван с деревянными ножками и округлыми подушками», единый вектор должен смешать все четыре требования в одну точку. В результате диван, который зеленый, но с металлическими ножками, может оказаться слишком близко к вашему запросу, потому что модель не смогла изолировать критический признак «деревянные ножки».
Multi-vector модель (название происходит от статьи ColBERT) пропускает это агрессивное сжатие. Она использует тот же трансформер, но вместо того чтобы пулить (aggregating) эмбеддинги токенов в один вектор, она проецирует каждый эмбеддинг токена в небольшое измерение (классически 128) и сохраняет все их. Документ из 9 токенов становится матрицей размером 9x128, а не вектором 1x128. Взаимодействие между запросом и документом откладывается до момента оценки (scoring time), откуда и происходит название «позднее взаимодействие» (late interaction).
Для сравнения, cross-encoder взаимодействует рано: оба текста проходят через модель вместе, что обеспечивает высокую точность, но не позволяет ничего предварительно вычислить, так как каждый документ должен быть перекодирован для каждого нового запроса. Bi-encoder (как обычные плотные эмбеддинги) взаимодействует минимально — одно скалярное произведение между готовыми суммарными представлениями, что позволяет закодировать коллекцию один раз и быстро ее опрашивать. Late-interaction находится посередине: документы все еще кодируются независимо и могут быть проиндексированы офлайн, но при оценке сравнивается каждый токен запроса с каждым токеном документа, что оставляет гораздо больше пространства для взаимодействия.
02Оператор MaxSim
Сердцем multi-vector моделей является оператор MaxSim. Он работает следующим образом: для каждого токена запроса находится его максимальное сходство с любым токеном документа, после чего эти максимумы суммируются по всем токенам запроса. Формула выглядит так:
MaxSim(Q, D) = Σ_{Q_i ∈ Q} max_{D_j ∈ D} (Q_i · D_j)Поскольку эмбеддинги токенов нормализованы по длине L2, каждое скалярное произведение представляет собой косинусное сходство в диапазоне [-1, 1]. Следовательно, вся сумма попадает в диапазон [-num_query_tokens, num_query_tokens].
Этот оператор можно интерпретировать как «мягкое выравнивание» (soft alignment). Каждый токен запроса указывает на тот токен документа, который лучше всего его объясняет, а итоговый балл показывает, насколько документ в целом поддерживает запрос. Важно отметить, что это выравнивание не обязательно является лексическим, так как эмбеддинги токенов контекстуализированы. Например, если закодировать запрос «Where do penguins live?» против документа «Penguins inhabit Antarctica.» с помощью модели lightonai/mLateOn, токен запроса live найдет свое лучшее совпадение с токеном документа inhabit с коэффициентом 0.94, несмотря на то, что у этих слов нет общих символов. Это то, чего не может сделать лексический поиск (такой как BM25), которому требуется совпадение самого термина. Плотные модели эмбеддингов также преодолевают этот разрыв, но late-interaction добавляет к этому то, что не отказывается от точного совпадения: когда важен точный матч (код продукта, фамилия, имя функции), MaxSim все еще видит этот токен отдельно, тогда как модель с одним вектором усредняла его со всем остальным.
03Что вы получаете и какова цена?
Главное преимущество — качество поиска. Это особенно заметно на запросах, где одна конкретная часть документа делает его релевантным, на запросах с несколькими требованиями (как пример с диваном, где каждое требование находит свое доказательство), и на данных вне домена (out-of-domain), где сжатие плотной модели было настроено на другое распределение. Эффект возрастает с длиной документа, так как больший объем текста должен уместиться в тот же фиксированный вектор.
Цена — это размер индекса. Один вектор на токен вместо одного вектора на документ — это гораздо больше векторов, что частично компенсируется меньшим размером измерения. Для примера, кодирование 4 874 отрывков из Natural Questions с помощью lightonai/LateOn дало 608 414 токенов-векторов, в среднем 124,8 на отрывок:
Однако индексы часто сжимаются. Например, те же 608 414 векторов занимают всего 92 МБ в индексе fast-plaid, так как PLAID хранит идентификатор центроида и квантованный остаток для каждого вектора, а не сам вектор. Для масштаба: плотная модель с 4096 измерениями (например, Qwen3-Embedding-8B) потребовала бы около 80 МБ для тех же 4 874 отрывков. Таким образом, сжатый multi-vector индекс находится в той же категории, что и плотные индексы, которые люди уже используют.
04Установка и загрузка модели
Multi-vector модели работают с обычной установкой библиотеки Sentence Transformers. Обновите пакет до последней версии:
pip install -U sentence-transformersДля визуального поиска документов в стиле ColPali также потребуются зависимости для изображений:

pip install -U "sentence-transformers[image]"Обратите внимание, что Sentence Transformers v6.0 требует transformers v5.x, torch 2.2+ и huggingface-hub v1.x. Если вы фиксируете более старые версии, планируйте обновление заранее.
Загрузка multi-vector модели выглядит точно так же, как загрузка любой другой модели Sentence Transformers:
from sentence_transformers import MultiVectorEncoder
model = MultiVectorEncoder("lightonai/LateOn")Вы можете найти модели, которые работают, по тегам multi-vector и sentence-transformers на Hugging Face Hub. Любая модель с этими тегами загружается указанной выше строкой, независимо от того, была ли она изначально создана как чекпоинт PyLate, Stanford-NLP ColBERT или модель семейства ColPali для визуального поиска документов. Под капотом MultiVectorEncoder читает каждый из форматов, в которых эти чекпоинты публиковались годами, поэтому чекпоинты PyLate и Stanford-NLP загружаются напрямую.

05Исследование конфигурации чекпоинта
Multi-vector модели содержат ряд настроек, которые различаются для каждого чекпоинта: маркеры префиксов для запросов и документов, ограничения длины, необходимость дополнения запросов токенами [MASK] и какие токены пропускаются при оценке документов. Все они находятся в конфигурациях модулей, поэтому команда print(model) покажет вам точную конфигурацию. Например, для оригинального чекпоинта ColBERTv2:
from sentence_transformers import MultiVectorEncoder
model = MultiVectorEncoder("colbert-ir/colbertv2.0")
print(model)
"""
MultiVectorEncoder(
(0): Transformer({..., 'document_length': 180,
'query_expansion': {'strategy': 'fixed', 'attend': False, 'token': None, 'length': 32}})
(1): Dense({'in_features': 768, 'out_features': 128, 'bias': False, ...})
(2): MultiVectorMask({'skiplist_words': ['!', '"', '#', ...], 'skiplist_tasks': ['document'], ...})
(3): Normalize({...})
)
"""
print(model.prompts)
# {'query': '[unused0] ', 'document': '[unused1] '}
"""Это классический конвейер ColBERT: Transformer производит контекстуализированные эмбеддинги токенов, Dense проецирует каждый из них в 128 измерений, MultiVectorMask решает, какие токены учитываются при оценке, и Normalize нормализует токены. Другие чекпоинты заполняют эти значения по-разному. Например, lightonai/GTE-ModernColBERT-v1 использует те же четыре модуля с маркерами [Q] и [D], без расширения запроса и с ограничениями 48 и 300 соответственно.
Одно значение стоит проверить относительно ваших собственных данных — document_length. Он обрезает текст, поэтому все, что находится за этим пределом, никогда не достигает индекса. Если ваши фрагменты длиннее этого предела, вы можете поднять его для одного вызова с помощью encode_document(..., processing_kwargs={"text": {"max_length": 512}}), но имейте в виду, что вы запускаете модель за пределами длины, на которой она была обучена, и индекс растет примерно пропорционально.
06Кодирование запросов и документов
Multi-vector модели асимметричны: запросы и документы проходят через разные префиксы, разные ограничения длины и разные маски оценки. В отличие от многих плотных моделей, где два этих понятия взаимозаменяемы, encode_query() и encode_document() обязательны для получения правильных эмбеддингов:
from sentence_transformers import MultiVectorEncoder
model = MultiVectorEncoder("lightonai/mLateOn")
queries = ["What is the capital of France?"]
documents = [
"Paris is the capital of France.",
"Berlin is the capital and largest city of Germany, by both area and population."
]
query_embeddings = model.encode_query(queries)
document_embeddings = model.encode_document(documents)
print(query_embeddings[0].shape)
# (10, 128)
print(document_embeddings[0].shape, document_embeddings[1].shape)
# (10, 128) (19, 128)Обратите внимание, что вы получаете: список 2D-тензоров, по одному на каждый вход, каждый размером (num_tokens, embedding_dim). В отличие от плотных эмбеддингов, вы не можете сложить их в один прямоугольный тензор, потому что каждый вход имеет свое количество токенов. Второй документ длиннее первого, поэтому он возвращается как более высокая матрица. Каждый вызов применяет рецепт модели за вас: encode_query добавляет маркер запроса, расширяет запрос до фиксированной длины, если чекпоинт этого требует, и обрезает его по длине запроса. encode_document добавляет маркер документа, обрезает по длине документа и удаляет любые токены из списка исключений (пунктуацию для большинства чекпоинтов) из маски оценки.
07Оценка с помощью MaxSim
Метод model.similarity() вычисляет полную матрицу попарных MaxSim:
from sentence_transformers import MultiVectorEncoder
model = MultiVectorEncoder("lightonai/LateOn")
query_embeddings = model.encode_query(["Which planet is known as the Red Planet?"])
document_embeddings = model.encode_document([
"Venus is often called Earth's twin because of its similar size and proximity.",
"Mars, known for its reddish appearance, is often referred to as the Red Planet.",
"Jupiter, the largest planet in our solar system, is a gas giant."
])
scores = model.similarity(query_embeddings, document_embeddings)
print(scores)Результатом будет матрица, где каждая ячейка содержит балл MaxSim между соответствующим запросом и документом. Чем выше балл, тем выше релевантность документа запросу.
08Семантический поиск и Retrieve & Rerank
В контексте семантического поиска multi-vector модели часто используются в двухэтапных конвейерах. На первом этапе используется быстрый поиск по индексу (например, с помощью fast-plaid или других оптимизированных структур данных) для получения списка наиболее релевантных документов. На втором этапе эти документы могут быть переупорядочены (reranked) с помощью более точной модели, такой как cross-encoder, или с использованием самого multi-vector индекса с более строгими параметрами.
Подход Retrieve and Rerank позволяет избежать необходимости строить полный индекс для всех данных, если объем данных слишком велик. Вместо этого вы можете использовать multi-vector модели для точечной оценки релевантности только тех документов, которые прошли первичный отбор. Это особенно полезно в сценариях, где требуется высокая точность, а не просто скорость.

09Индексирование
Как упоминалось ранее, размер индекса multi-vector моделей значительно больше, чем у плотных моделей. Однако существуют эффективные методы сжатия, такие как fast-plaid, который использует квантование и хранение остатков для уменьшения занимаемого места. Это позволяет использовать multi-vector модели в продакшене, где объем данных может быть очень большим. Важно правильно настроить параметры индексации, чтобы найти баланс между скоростью поиска и точностью.
10Визуальный поиск документов
Multi-vector модели также применяются в визуальном поиске документов. Модели семейства ColPali позволяют сопоставлять текстовые запросы напрямую с изображениями страниц документов, без необходимости предварительного распознавания текста (OCR). Это открывает новые возможности для работы с отсканированными документами, изображениями и другими визуальными данными. Для использования таких моделей необходимо установить дополнительные зависимости для работы с изображениями.
11Аудио и видео поиск
Помимо текста и изображений, multi-vector модели могут быть применены для поиска в аудио и видео данных. Хотя это требует специфических моделей и подходов к кодированию, принцип late-interaction остается тем же: сохранение детальной информации на уровне токенов (или фреймов) позволяет более точно сопоставлять запросы с контентом. Это особенно актуально для мультимодальных приложений, где требуется поиск по нескольким типам данных одновременно.
12Интерпретируемость
Одним из преимуществ multi-vector моделей является их интерпретируемость. Поскольку каждый токен запроса сопоставляется с конкретными токенами документа, можно проанализировать, какие именно части документа повлияли на результат поиска. Это позволяет лучше понять, почему модель выдала тот или иной результат, и выявить возможные ошибки или смещения в данных.
13Пулинг токенов
Для уменьшения размера индекса и ускорения вычислений можно использовать пулинг токенов. Этот метод позволяет агрегировать эмбеддинги токенов в более крупные блоки, сохраняя при этом большую часть информации. Это компромисс между размером индекса и точностью поиска, который можно настроить в зависимости от требований приложения.
14Ускорение вывода
Для ускорения вывода multi-vector моделей можно использовать различные оптимизации, такие как квантование, прунинг и использование специализированных аппаратных ускорителей. Библиотека Sentence Transformers v6.0 предоставляет инструменты для оптимизации работы с этими моделями, что позволяет использовать их в реальном времени даже на ресурсоемких задачах.
15Оценка модели
Оценка multi-vector моделей проводится с использованием стандартных метрик, таких как NDCG (Normalized Discounted Cumulative Gain) и MRR (Mean Reciprocal Rank). Важно тестировать модели на различных наборах данных, чтобы убедиться в их устойчивости и точности в разных сценариях. Также следует учитывать влияние длины документа и запроса на качество поиска.
16Переход с PyLate или colpali-engine
Если вы ранее использовали библиотеки PyLate или colpali-engine, переход на Sentence Transformers v6.0 должен быть относительно простым. Основные функции, такие как загрузка моделей, кодирование и оценка, теперь доступны через единый интерфейс MultiVectorEncoder. Это упрощает интеграцию multi-vector моделей в существующие проекты и снижает порог входа для новых пользователей.
17Поддерживаемые модели
В настоящее время поддерживается широкий спектр multi-vector моделей, включая чекпоинты от LightOn, MixedBread, LiquidAI и других исследователей. Список поддерживаемых моделей постоянно расширяется. Рекомендуется проверять тег multi-vector на Hugging Face Hub для актуальной информации о доступных моделях.
18Благодарности
Авторы выражают благодарность сообществу Hugging Face и разработчикам библиотеки Sentence Transformers за вклад в развитие и поддержку multi-vector моделей. Особая благодарность команде LightOn за создание PyLate и fast-plaid, которые стали основой для интеграции late-interaction моделей в Sentence Transformers.
19Дополнительные ресурсы
Для получения дополнительной информации о multi-vector моделях, их настройке и оптимизации, рекомендуется ознакомиться с официальной документацией Sentence Transformers, статьями о ColBERT и ресурсами сообщества Hugging Face. Эти материалы помогут вам глубже понять принципы работы late-interaction моделей и применить их в своих проектах.
20Что это значит на практике
Для разработчиков, работающих над системами поиска, внедрение multi-vector моделей через Sentence Transformers v6.0 означает доступ к state-of-the-art технологиям без необходимости написания сложного кастомного кода. Вы можете загрузить готовую модель, закодировать свои данные и начать поиск с высокой точностью. Однако важно помнить о компромиссах: увеличенный размер индекса требует больше памяти и дискового пространства, а также может потребовать оптимизации для обеспечения приемлемой скорости поиска. Использование сжатых индексов, таких как fast-plaid, и правильная настройка параметров кодирования помогут минимизировать эти недостатки. В конечном итоге, multi-vector модели предлагают значительное улучшение качества поиска, особенно для сложных запросов и длинных документов, что делает их ценным инструментом в арсенале современного разработчика AI.
Источник: Hugging Face ↗
