RAG GPU индекс CPU поиск: гибридный подход для экономии и масштабирования | AiManual
AiManual Logo Ai / Manual.
14 Янв 2026 Гайд

Гибридный подход к RAG: построение индекса на GPU и обслуживание на CPU для масштабируемости и экономии

Практическое руководство по разделению RAG-системы: быстрая сборка индекса на GPU и дешёвое обслуживание на CPU. Снижаем TCO на 60-70% без потери качества.

Почему ваша RAG-система сжирает бюджет и как это исправить

Вы запустили RAG в продакшен. Первые недели всё летает — пользователи довольны, точность релевантности на высоте. Потом приходит счёт за облако. Или вы смотрите на монитор ресурсов своего сервера и видите, как дорогущие GPU A100 простаивают 95% времени, ожидая очередного поискового запроса.

Классическая ошибка: использовать одни и те же GPU и для построения векторного индекса, и для его обслуживания. Это как покупать Ferrari, чтобы ездить в магазин за хлебом раз в неделю. Остальное время машина стоит в гараже и съедает деньги на страховке.

Проблема не в том, что GPU дорогие. Проблема в том, что мы используем их неэффективно. Построение индекса — тяжёлая, но редкая операция. Поиск — лёгкая, но частая. Смешивать их на одном железе — экономическое самоубийство.

Разделяй и властвуй: архитектура, которая не разорит

Гибридный подход прост до гениальности:

  1. Индексирование на GPU: Загружаем все документы, эмбеддим их с помощью модели на GPU (это быстро), строим оптимизированный индекс (HNSW, IVF). Используем всю мощь видеокарты для этой одноразовой тяжёлой работы.
  2. Экспорт индекса: Сохраняем готовую структуру в формат, который можно загрузить на машину без GPU.
  3. Обслуживание на CPU: Разворачиваем поисковый движок на дешёвых CPU-серверах. Они только и делают, что ищут по уже готовому индексу. Масштабируем горизонтально по мере роста запросов.

Результат? Стоимость инфраструктуры падает в 2-3 раза. GPU освобождаются для других задач (дообучение моделей, инференс тяжёлых LLM). А поиск становится даже стабильнее — CPU меньше греются, их проще охлаждать и масштабировать.

💡
Это не теоретическая конструкция. В одной из наших статей мы уже разбирали, как современные CPU вроде Intel Xeon 6 справляются с AI-нагрузками. Для поиска по готовому индексу их мощности более чем достаточно.

Шаг за шагом: от теории к работающему пайплайну

1Выбираем инструменты: не только Milvus

Milvus — отличный выбор, но не единственный. Главное, чтобы система поддерживала:

  • Отдельные роли для индексирования и запросов
  • Экспорт/импорт индексов
  • Эффективные алгоритмы вроде HNSW или IVF_PQ

Альтернативы: Weaviate, Qdrant, Vespa. Но сегодня сосредоточимся на Milvus — у него лучшая поддержка гибридного сценария.

2Настраиваем GPU-ноду для индексирования

Это наш «тяжеловес». Разворачиваем Milvus с поддержкой GPU:

# Устанавливаем Milvus с GPU-поддержкой
docker pull milvusdb/milvus:latest-gpu

# Запускаем с нужными параметрами
docker run -d \
  --name milvus-gpu \
  --gpus all \
  -p 19530:19530 \
  -p 9091:9091 \
  milvusdb/milvus:latest-gpu

Конфигурация для максимальной скорости построения индекса:

# milvus.yaml
engine:
  use_blas_threshold: 0  # Всегда использовать GPU
  gpu:
    enable: true
    cache_size: 4GB
    gpu_search_threshold: 0

index:
  build_index_resources: ["gpu0"]  # Строим индекс только на GPU

3Строим индекс на стероидах

Теперь загружаем данные и запускаем индексирование. Ключевой момент — выбираем правильные параметры индекса:

from pymilvus import connections, Collection, FieldSchema, CollectionSchema, DataType
import numpy as np

# Подключаемся к GPU-ноде
connections.connect(alias="default", host="gpu-node", port="19530")

# Создаём коллекцию
fields = [
    FieldSchema(name="id", dtype=DataType.INT64, is_primary=True),
    FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=768)
]
schema = CollectionSchema(fields, "documents")
collection = Collection("docs", schema)

# Загружаем эмбеддинги (уже сгенерированные на GPU)
embeddings = np.random.randn(1000000, 768).astype(np.float32)  # 1M векторов
ids = list(range(1000000))

collection.insert([ids, embeddings])

# Строим HNSW индекс на GPU
index_params = {
    "metric_type": "IP",
    "index_type": "HNSW",
    "params": {
        "M": 16,      # Высокая связность для качества
        "efConstruction": 200  # Больше = точнее, но медленнее
    }
}

collection.create_index("embedding", index_params)
print("Индекс построен на GPU")

# Важно: дожидаемся завершения
collection.load()

Параметр `efConstruction` — ваш главный рычаг. Чем выше значение, тем точнее индекс, но дольше построение. На GPU можно позволить себе 200-400. На CPU пришлось бы ждать вечность или снижать качество.

4Экспортируем и переносим

Теперь самое интересное — выгружаем готовый индекс:

# Экспортируем коллекцию с индексом
collection.release()

# В реальности используем backup/restore или прямой экспорт файлов
# Milvus хранит индекс в папке /var/lib/milvus/index_files
# Просто копируем её на CPU-ноду

# Альтернатива: используем встроенный backup
docker exec milvus-gpu milvus-backup create -n backup_001

Переносим файлы индекса на CPU-сервер. Это просто бинарные файлы — никакой магии.

5Запускаем CPU-ферму для поиска

На CPU-нодах запускаем облегчённый Milvus:

# CPU-версия, без зависимостей от CUDA
docker pull milvusdb/milvus:latest-cpu

docker run -d \
  --name milvus-cpu \
  -p 19530:19530 \
  -v /path/to/index_files:/var/lib/milvus/index_files \
  milvusdb/milvus:latest-cpu

Конфигурация для поиска:

# milvus-cpu.yaml
engine:
  use_blas_threshold: 1000  # Используем CPU оптимизации
gpu:
  enable: false  # Важно: отключаем GPU

# Оптимизируем для поиска
queryNode:
  gracefulTime: 1000
  cache:
    enabled: true
    cache_size: 2GB  # Кэшируем часто запрашиваемые векторы

Теперь у вас есть масштабируемый кластер CPU-нод, каждая с готовым индексом. Добавляете балансировщик нагрузки — и можете обслуживать тысячи запросов в секунду.

Подводные камни, которые разорвут ваш пайплайн

Кажется просто? На практике всё сложнее. Вот что идёт не так в 90% случаев:

ОшибкаПоследствиеРешение
Несовместимость версий MilvusИндекс с GPU-ноды не загружается на CPUФиксировать версии (2.3.4 → 2.3.4)
Разные параметры компиляции FAISSПадение производительности на 50%Собирать из одних исходников
Забыть про метаданныеID векторов не соответствуют документамЭкспортировать mapping отдельно
Слишком агрессивное кэшированиеCPU-нода падает по памятиНастраивать cache_size под RAM

Самая коварная ошибка — думать, что можно один раз построить индекс и забыть. Данные меняются. Новые документы добавляются ежедневно. Что делать?

Два подхода:

  1. Инкрементальное обновление: Строим маленький индекс на новых документах, потом мерджим с основным. Сложно, но эффективно.
  2. Периодическая пересборка: Раз в неделю/месяц запускаем полную переиндексацию на GPU. Между обновлениями используем гибридный поиск, как в этой статье, чтобы компенсировать устаревание.

Цифры, которые заставят вашего CFO улыбнуться

Давайте посчитаем. Допустим, у вас:

  • 10 млн документов
  • 1000 запросов в минуту в пик
  • Эмбеддинги по 768 размерности
АрхитектураИнфраструктураМесячная стоимость (AWS)Задержка поиска
Всё на GPU2× g5.2xlarge (постоянно)~$2,50015 мс
Гибридная1× g5.2xlarge (на 2 часа/день) + 3× c6i.2xlarge~$80022 мс

Экономия 68%. Задержка увеличивается на 7 мс — для большинства RAG-систем это не критично. А если оптимизировать индекс под CPU (например, использовать IVF_PQ вместо HNSW), разница сократится до 3-4 мс.

💡
Эти 7 мс — плата за архитектурную гибкость. Но её можно «отыграть» другими методами: кэшированием частых запросов, префильтрацией по метаданным, или вообще выносом поиска ближе к пользователю через локальные RAG-системы.

Когда это не сработает (и что делать вместо)

Гибридный подход — не серебряная пуля. Он проигрывает в трёх сценариях:

  1. Real-time индексирование: Если документы добавляются каждую секунду и должны сразу быть доступны для поиска. Решение: оставить всё на GPU или использовать специализированные движки вроде Redis.
  2. Экстремально низкие задержки: Торговые системы, где каждый миллисекунд на счету. Тут GPU оправданы.
  3. Очень маленькие объёмы: Если у вас 10 тысяч документов и 100 запросов в день — не усложняйте. Запустите всё на одной дешёвой GPU.

Но для 95% production RAG-систем — от корпоративных чат-ботов до поиска по технической документации — гибридный подход идеален.

Что дальше? RAG эволюционирует быстрее, чем вы успеваете читать

Через год этот подход может устареть. Уже сейчас появляются:

  • Квантованные индексы, которые работают в 10 раз быстрее на CPU
  • Аппаратные ускорители для векторного поиска (не GPU!)
  • Распределённые индексы, которые вообще не требуют центрального сервера

Но сегодня, в 2024-2025, разделение индексирования и поиска между GPU и CPU — самый практичный способ снизить TCO без потери качества. Это не хак, а инженерная зрелость.

Ваш следующий шаг — не слепо копировать код из статьи. А проанализировать свою RAG-систему: сколько времени GPU простаивают? Как часто обновляются данные? Какая реальная задержка поиска acceptable для пользователей?

Потом взять одну маленькую коллекцию — не production, а тестовую — и попробовать. Сравнить цифры. Увидеть разницу. И только потом масштабировать на всю систему.

Потому что в мире AI-оптимизаций самое дорогое — не железо. А время, потраченное на неправильную архитектуру.