Как сделать RAG в 32 раза легче: бинарная квантизация на практике

Если вы работаете с RAG-системами, то наверняка сталкивались с проблемой: векторные индексы жрут память как не в себя. Миллионы эмбеддингов в float32 превращаются в десятки гигабайт, и масштабирование становится болью. Но есть простой прием, который уже используют Perplexity, Azure и HubSpot. Называется он бинарная квантизация (Binary Quantization), и он сокращает потребление памяти в 32 раза.

Идея элементарная: вместо того чтобы хранить каждый компонент вектора как 32-битное число с плавающей точкой, мы превращаем его в один бит. Положительное значение становится единицей, отрицательное или нулевое – нулем. Вектор из 1024 float32 (4096 байт) превращается в 1024 бита (128 байт). Вот вам и сжатие в 32 раза.

Звучит как будто мы теряем кучу информации? Да, теряем. Но на практике для задач поиска ближайших соседей этого достаточно. Особенно если использовать бинарный поиск как первый этап, а потом делать reranking по полным векторам для топ-кандидатов.

Как это работает на практике

Допустим, вы строите RAG-пайплайн. Вот что нужно сделать:

Сначала генерируем обычные эмбеддинги через любую модель, например BAAI/bge-large-en-v1.5. Получаем float32-векторы. Затем применяем бинарную квантизацию: проходим по каждому значению вектора и заменяем его на 1 (если больше нуля) или 0 (если меньше или равно нулю). После этого упаковываем биты через numpy.packbits, чтобы получить компактное байтовое представление.

Дальше эти бинарные векторы складываем в векторную базу. Milvus, например, нативно поддерживает бинарные индексы с метрикой Хэмминга. Расстояние Хэмминга между двумя бинарными векторами – это просто количество позиций, в которых биты различаются. Считается это через XOR и popcount, что на уровне процессора выполняется за наносекунды.

При поиске квантизуем запрос точно так же и ищем ближайших соседей по расстоянию Хэмминга. Скорость поиска по 36 миллионам векторов – менее 30 миллисекунд.

Что по качеству?

Понятно, что бинарная квантизация – это компромисс. Recall будет ниже, чем при полноценном поиске по float32. Но тут есть нюансы.

Во-первых, для большинства RAG-задач нам не нужен идеальный recall. Нам нужно, чтобы в топ-5 или топ-10 попали релевантные чанки, а дальше LLM разберется.

Во-вторых, можно использовать двухступенчатый подход: бинарный поиск дает грубый шорт-лист (скажем, топ-100), а потом мы пересчитываем расстояния по оригинальным float32-векторам только для этих ста кандидатов. Это дает почти такой же recall, как полный поиск, но при этом мы храним в индексе только бинарные векторы.

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

Стек для быстрого RAG

Рабочий стек, который позволяет запустить это в проде: LlamaIndex для оркестрации пайплайна, Milvus как векторная база с нативной поддержкой бинарных индексов, и любая быстрая LLM для генерации (например, Kimi-K2 через Groq для минимальной латенции).

Весь пайплайн выглядит так: загружаем документы, генерируем эмбеддинги и квантизуем их, складываем в Milvus с бинарным индексом, при запросе квантизуем запрос и ищем по Хэммингу, отдаем найденный контекст в LLM.

На датасете PubMed (36+ миллионов векторов) такой пайплайн выдает поиск менее чем за 30 мс и генерацию ответа менее чем за секунду.

Когда использовать

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

Для маленьких индексов (до миллиона векторов) это скорее всего overkill. А вот когда речь идет о десятках миллионов документов и выше – бинарная квантизация становится необходимостью.

Важно помнить: BQ оптимизирует только слой векторного поиска. В продакшн-системах retrieval – это не только эмбеддинги. Это еще и маршрутизация запросов, права доступа, синхронизация данных из разных источников, reranking. Чем легче и быстрее работает векторный слой, тем больше бюджета остается на все остальное.

Код примера доступен на GitHub: https://github.com/patchy631/ai-engineering-hub/tree/main/fastest-rag-milvus-groq

Оригинальный разбор от Avi Chawla: https://x.com/_avichawla/article/2040326889928356122

+1
0
+1
0
+1
0
+1
0
+1
0

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *