Что такое Multi-vector retrieval и зачем он нужен?
Краткий тезис
Multi-vector retrieval — это подход, при котором один документ (или чанк) представляется не одним эмбеддингом, а множеством векторов: эмбеддинги заголовков, ключевых фраз, предложений или даже каждого токена. Это решает проблему «сжатия смысла»: обычный эмбеддинг сжимает весь текст в один вектор, теряя детали. Multi-vector сохраняет больше информации, что улучшает поиск на сложных запросах. Самый известный пример — ColBERT, где каждый токен документа имеет свой эмбеддинг, и релевантность считается через late interaction (попарное сравнение токенов запроса и документа).
Ключевая идея Один вектор — это «средняя температура по больнице». Много векторов — это детальная карта.
1. Термин: Multi-vector retrieval
Что это Метод, при котором каждый документ (или чанк) индексируется с использованием нескольких эмбеддингов, а не одного.
Сравнение
| Подход | Количество эмбеддингов на документ | Что сохраняется |
|---|---|---|
| Single-vector (обычный RAG) | 1 (весь чанк) | Смысл в среднем |
| Multi-vector (ColBERT | N (каждый токен) | Каждый токен, порядок |
| Multi-vector (HyDE | 1 (гипотетический ответ) + 1 (оригинал) | Альтернативная перспектива |
| Multi-vector (Parent-child | 1 на дочерний, 1 на родительский | Иерархия |
Термин «Late interaction» (позднее взаимодействие Вместо того чтобы сворачивать документ в один вектор до поиска (early interaction), мы храним все векторы токенов документа, а при поиске сравниваем их с векторами токенов запроса попарно.
2. Проблема, которую решает Multi-vector retrieval
2.1 Проблема «сжатия» в одном векторе
Обычный подход (single-vector
Документ: "Кошка сидит на ковре. Собака бежит по траве."
→ Embedding модель → один вектор [0.12, -0.45, ...]
Потеря информации
- Порядок слов? Потерян
- Отношения между словами? Сглажены
- Тонкие семантические нюансы? Усреднены
Пример, где single-vector ошибается
Запрос: "Кошка бежит"
Документ: "Собака бежит. Кошка сидит."
Single-vector может найти этот документ (есть и "кошка", и "бежит"),
но на самом деле в документе кошка НЕ бежит.
Multi-vector (ColBERT) найдёт правильный документ, где кошка действительно бежит.
Термин «Token-level matching» Сравнение каждого токена запроса с каждым токеном документа. Это позволяет улавливать тонкие семантические отношения.
3. Пример реализации: ColBERT
Термин «ColBERT» (Contextualized Late Interaction over BERT Модель для chunks|multi-vector retrieval, где каждый токен документа и запроса получает свой эмбеддинг, а релевантность считается как сумма максимальных попарных сходств.
Как работает ColBERT
Шаг 1: Токенизация и эмбеддинги
Запрос: "кошка бежит"
→ Токены: [CLS] кошка бежит [SEP]
→ Эмбеддинги: E_query = [e_кошка, e_бежит] (2 вектора)
Документ: "Собака бежит. Кошка сидит."
→ Токены: [CLS] собака бежит . кошка сидит [SEP]
→ Эмбеддинги: E_doc = [e_собака, e_бежит, e_., e_кошка, e_сидит] (5 векторов)
Шаг 2: Late interaction (попарное сравнение)
Для каждого токена запроса:
max_sim = max(cosine_similarity(e_запроса, e_документа) for e_документа)
score_кошка = max(cos(e_кошка, e_собака), cos(e_кошка, e_бежит), cos(e_кошка, e_.), cos(e_кошка, e_кошка), cos(e_кошка, e_сидит))
= cos(e_кошка, e_кошка) = 1.0
score_бежит = max(cos(e_бежит, e_собака), cos(e_бежит, e_бежит), ...) = cos(e_бежит, e_бежит) = 1.0
Шаг 3: Итоговый score
total_score = score_кошка + score_бежит = 2.0
Шаг 4: Нормализация (обычно через сумму логарифмов или softmax)
Формула ColBERT (упрощённо
Score(q, d) = Σ_{i=[[1. Как бы вы спроектировали RAG-систему для 10 000 документов с разной структурой|1]]}^{|q|} max_{j=[[1. Как бы вы спроектировали RAG-систему для 10 000 документов с разной структурой|1]]}^{|d|} cos(E_q[i], E_d[j])
где:
|q|— количество токенов в запросе|d|— количество токенов в документеE_q[i]— эмбеддинг i-го токена запросаE_d[j]— эмбеддинг j-го токена документа
Почему это хорошо
- Токен "кошка" сопоставился с "кошка" (1.0)
- Токен "бежит" сопоставился с "бежит" (1.0)
- Модель НЕ сопоставила "кошка" с "собака" (низкий score)
Если бы в документе было "Кошка бежит
- Тот же score 2.0 (хорошо) Если бы в документе было "Кошка сидит
- score = 1.0 (кошка) + 0.2 (бежит vs сидит) = 1.2 (ниже, правильно)
4. Сравнение: Single-vector (Bi-encoder) vs ColBERT
| Характеристика | Bi-encoder (обычный RAG) | ColBERT (multi-vector) |
|---|---|---|
| Эмбеддингов на документ | 1 | |
| Память на 1 млн документов | 1.5 GB (768d) | 150+ GB (512 * 768d) |
| Время поиска | O(1) (косинусное расстояние) | O( |
| 10. Что такое Self-RAG и когда его использовать | 10]]. Что такое Self-RAG и когда его использовать | 10]]. Что такое Self-RAG и когда его использовать |
| Требования к GPU | Низкие | Высокие |
| Когда использовать | Большинство RAG | Сложные запросы, точность критична |
Термин «Bi-encoder» Два энкодера — один для запроса, один для документа. Каждый сворачивает свой вход в один вектор.
Термин «Cross-encoder» Один энкодер обрабатывает пару (запрос, документ) вместе. Очень точно, но O(n²) — не масштабируется.
Место ColBERT на спектре
Bi-encoder (быстро, грубо) → ColBERT (баланс) → Cross-encoder (медленно, точно)
5. Другие варианты Multi-vector retrieval
5.1 Parent-child retrieval (иерархический)
Идея Документ разбивается на маленькие чанки (children) для поиска, но в LLM возвращается большой родительский чанк (parent).
# Индексируем маленькие чанки
child_embeddings = embed(child_chunks)
# При поиске: находим child
retrieved_child = search(query_emb, child_embeddings)
# Возвращаем родителя (большой чанк, содержащий этого ребёнка)
parent_chunk = get_parent(retrieved_child)
2 Как вы решаете проблему lost in the middle при работе с длинными контекстами|2 Как вы решаете проблему lost in the middle при работе с длинными контекстами|2 Как вы решаете проблему lost in the middle при работе с длинными контекстами|2 (Multi-vector retrieval в контексте lost in the middle|См. вопрос 2 (Multi-vector retrieval в контексте lost in the middle
5.2 HyDE как multi-vector
Идея Храним не только оригинальный чанк, но и гипотетический ответ на запрос.
- Что такое Hypothetical Document Embeddings (HyDE) и зачем|11. Что такое Hypothetical Document Embeddings (HyDE) и зачем|11. Что такое Hypothetical Document Embeddings (HyDE) и зачем|11 (HyDE|См. вопрос 11 (HyDE
5.3 Sparse + Dense (гибридный)
Идея Два вектора на чанк: dense (семантический) и sparse (лексический, например, SPLADE).
- Что такое гибридный поиск и когда он нужен|6. Что такое гибридный поиск и когда он нужен|6. Что такое гибридный поиск и когда он нужен|6 (гибридный поиск|См. вопрос 6 (гибридный поиск
6. Плюсы и минусы Multi-vector retrieval
Плюсы
| Плюс | Объяснение |
|---|---|
| Точность (recall | На 5-15% выше, чем у single-vector |
| Token-level matching | Улавливает тонкие семантические отношения |
| Устойчивость к перефразированию | Лучше находит смысл при разных формулировках |
| Работа с длинными документами | Может находить релевантный токен внутри длинного документа |
Минусы
| Минус | Объяснение |
|---|---|
| Память | В 100-500 раз больше, чем у single-vector |
| Скорость поиска | Медленнее, особенно на больших коллекциях |
| Сложность индексации | Нужно хранить и искать по множеству векторов |
| Инструменты | Меньше поддержки в векторных БД (Qdrant начинает поддерживать) |
7. Когда использовать Multi-vector retrieval?
| Сценарий | Рекомендация |
|---|---|
| Сложные запросы с отрицаниями | ColBERT лучше отличает "не" |
| Поиск по длинным документам | Token-level matching находит релевантный кусок |
| Высокие требования к точности (медицина, юриспруденция | Multi-vector может быть оправдан |
| Маленькая коллекция (<1 млн документов) | Память не проблема |
| Есть ресурсы (GPU, память | ColBERT требует мощного железа |
| Стандартный RAG (новости, поддержка | Single-vector достаточно |
8. ColBERT в действии (код)
# Установка: pip install colbert-ai
from colbert import Indexer, Searcher
from colbert.infra import Run, RunConfig
# Инициализация
with Run().context(RunConfig(nranks=1, experiment="notebook")):
# Индексация документов
indexer = Indexer(checkpoint="colbert-ir/colbertv2.0")
indexer.index(name="my_index", collection=["doc1.txt", "doc2.txt"], overwrite=True)
# Поиск
searcher = Searcher(index="my_index", checkpoint="colbert-ir/colbertv2.0")
results = searcher.search("кошка бежит", k=10)
for passage, score, rank in zip(*results):
print(f"{rank}: {passage} (score={score})")
Важно ColBERT требует много памяти. Для 1 млн документов (по 512 токенов) → 512 * 1M = 512M векторов × 128 байт = 65 GB памяти.
9. Пет-проект для закрепления
Задача Сравнить single-vector retrieval (BGE-m3) с ColBERT на 100 сложных запросах.
Инструменты Python, ColBERT, sentence-transformers, Qdrant
Шаги
- Подготовить коллекцию из 1000 документов (можно новости, статьи)
- Составить 100 запросов, которые требуют тонкого понимания:
- С отрицаниями ("не содержит X")
- С отношениями ("A связан с B")
- Перефразированные
- Реализовать два подхода:
- Single-vector: BGE-m3 + Qdrant
- Multi-vector: ColBERT (colbert-ai библиотека)
- Для каждого запроса найти top-10 документов
- Вручную оценить recall@10 для каждого подхода
- Замерить время индексации, память, время поиска
- Сделать вывод: когда ColBERT оправдывает затраты
Ожидаемый результат ColBERT даст recall@10 на 5-15% выше, но потребует в 100 раз больше памяти и будет в 10 раз медленнее.
Связь с другими вопросами
| Вопрос | Тема |
|---|---|
| 1 | RAG архитектура (retrieval этап) |
| 2 | Lost in the middle (parent-child multi-vector) |
| 5 | Оценка retrieval (recall) |
| 6 | Гибридный поиск (sparse + dense) |
| 11 | HyDE (альтернативный multi-vector подход) |
| 221-235 | ANN internals (как ускорить multi-vector поиск) |
18. Что такое Multi-vector retrieval и зачем он нужен|18. Что такое Multi-vector retrieval и зачем он нужен|18. Что такое Multi-vector retrieval и зачем он нужен|18 полностью разобран. Переходим к вопросу 19, когда будете готовы|Вопрос 18 полностью разобран. Переходим к вопросу 19, когда будете готовы]]
Навигация
- Предыдущий: 17
- Следующий: 19
- Индекс: 00. Индекс разборов