Почему эмбеддинги — отдельная статья расходов

В локальном RAG основное внимание обычно получает генеративная модель. Но до неё документы нужно разбить на фрагменты, превратить в векторы, загрузить в индекс и обновлять после каждого изменения. Запрос пользователя тоже получает вектор, а часть систем дополнительно запускает реранкер.

Эти операции выполняют модели-кодировщики. Они меньше LLM и часто хорошо работают на CPU, особенно после экспорта в ONNX или OpenVINO и квантования. GPU способен обработать большой пакет быстрее, но его преимущество зависит от размера модели, длины текста, партии, драйверов и реальной загрузки. Поэтому вопрос «что быстрее?» для бизнеса неполон. Нужен ответ на другой вопрос: какой контур выполняет требуемый объём в срок с минимальной стоимостью принятого результата.

Официальная документация Sentence Transformers прямо показывает, что рейтинг бэкендов меняется между локальным компьютером и облачной CPU-машиной, и рекомендует тестировать конфигурации на целевом железе с характерными входами. Это важнее любой универсальной таблицы: короткие товарные карточки и длинные регламенты создают разные вычислительные профили.

Сначала разделите три разных нагрузки

Одна надпись «эмбеддинги» часто скрывает три очереди с разной экономикой.

Первичная загрузка корпуса

Это большой, но редкий пакет. Для него важна общая длительность: успеет ли система обработать архив ночью или за выходные. Задержка одного документа почти не имеет значения, зато выгодны крупные партии и высокая утилизация оборудования.

Инкрементальные обновления

Новые договоры, карточки и инструкции появляются каждый час. Здесь нужен гарантированный срок свежести: например, документ должен попасть в поиск не позднее чем через 15 минут. Поток обычно неровный, поэтому важны очередь, повторная обработка и защита от дублей.

Векторизация пользовательских запросов

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

Покупать одну схему для всех трёх очередей — всё равно что назначить фуру и курьером, и складом, и личным автомобилем. Технически поедет, финансовая модель будет менее убедительной.

Что подтверждают инструменты

Sentence Transformers поддерживает PyTorch, ONNX и OpenVINO. В документации показаны варианты FP16 для GPU, оптимизированные ONNX-модели и INT8-конфигурации для CPU. Авторы отдельно сравнивают не только скорость, но и отношение качества к базовой FP32-модели на задачах семантического сходства и поиска.

Hugging Face Text Embeddings Inference предоставляет официальные образы и для CPU, и для нескольких поколений NVIDIA GPU, принимает пакеты входов и допускает развёртывание в изолированном контуре с локально смонтированными весами. FastEmbed от Qdrant также использует ONNX Runtime, умеет распараллеливать CPU-обработку и имеет отдельный GPU-вариант.

Из этого не следует, что один бэкенд всегда дешевле. Следует другое: сравнение можно провести на одном API, одной модели и одном наборе документов, не переписывая весь RAG-контур.

Минимальный честный бенчмарк

Для выбора достаточно четырёх кандидатов:

  • текущий PyTorch на CPU как базовая линия;
  • ONNX или OpenVINO на CPU;
  • та же модель на GPU;
  • квантованный CPU-вариант, если его качество проходит порог.

Каждый вариант тестируют на одинаковом корпусе. Полезный набор должен отражать распределение продакшена, а не состоять из ста коротких предложений:

  • 20–30% коротких карточек;
  • основная масса обычных фрагментов;
  • 10–20% длинных фрагментов у верхнего допустимого предела;
  • русский язык, таблицы и смешанные алфавиты, если они есть в данных;
  • повторяющиеся и почти одинаковые документы.

Перед замером нужен прогрев. Затем фиксируют размер партии, число потоков, версию модели, токенизатор, точность, библиотеку, драйвер и фактическое железо. Измеряют не только документы в секунду, но и токены в секунду: один договор и одна карточка не являются равными единицами работы.

Для онлайн-очереди отдельно нужны p50 и p95 задержки. Для пакетной — общая длительность, максимальная память и доля времени, когда устройство действительно занято. Если GPU ждёт документы 90% времени, его высокая пиковая скорость не превращается в высокую экономическую эффективность.

Считать нужно стоимость принятого вектора

Базовая формула на месяц:

**Стоимость контура = аренда или амортизация + электричество + сопровождение + хранение артефактов + стоимость повторной обработки.**

Затем стоимость делят не на число вызовов и не на число токенов, а на количество векторов, прошедших проверку качества и попавших в рабочий индекс.

Так в расчёт попадают скрытые потери:

  • ошибки токенизации и пустые входы;
  • повторная обработка после сбоя;
  • полная переиндексация при смене модели;
  • деградация поиска после квантования;
  • ручная проверка проблемных коллекций;
  • простой ускорителя между пакетами.

Подход соответствует логике unit economics: техническая метрика полезна, когда связана с бизнес-единицей. Для RAG такой единицей может быть обновлённый документ, принятый вектор или ответ, прошедший проверку, но определение должно оставаться стабильным.

Модельный расчёт без притворства, что это прайс-лист

Рассмотрим условную компанию. За месяц она обрабатывает 120 000 новых и изменённых фрагментов, в среднем по 750 токенов. Итого — 90 млн токенов. Замер на её данных дал:

  • оптимизированный CPU: 12 000 токенов в секунду;
  • GPU: 100 000 токенов в секунду;
  • расчётная стоимость CPU-ресурса: 60 рублей за час;
  • расчётная стоимость GPU-ресурса: 500 рублей за час.

Это не рыночные цены и не обещание производительности, а допущения для демонстрации метода.

Чистое вычислительное время без накладных расходов:

  • CPU: 90 000 000 / 12 000 = 7 500 секунд, или около 2,08 часа;
  • GPU: 90 000 000 / 100 000 = 900 секунд, или 0,25 часа.

Переменная стоимость одной месячной партии получается почти одинаковой:

  • CPU: около 125 рублей;
  • GPU: около 125 рублей.

Но вывод меняется после добавления реальности. Если GPU арендуется минимум на час, его партия стоит уже 500 рублей. Если ускоритель куплен и большую часть месяца простаивает, к задаче нужно отнести долю амортизации, питания и администрирования. Если же тот же GPU уже обслуживает локальную LLM и пакет эмбеддингов запускается в свободное окно, его предельная стоимость может оказаться ниже.

Поэтому точка безубыточности определяется не только скоростью. Для переменной аренды её можно оценить так:

**Объём × стоимость часа CPU / скорость CPU = объём × стоимость часа GPU / скорость GPU.**

Если обе стороны равны, решающими становятся срок выполнения, минимальный период тарификации и доступность ресурса. Для собственного оборудования вместо почасовой цены используют полностью нагруженную месячную стоимость и долю времени, реально занятую полезной работой.

Качество может съесть всю экономию

Переход с FP32 на INT8 способен ускорить CPU, но менять конфигурацию только по графику throughput опасно. Нужно повторить проверку поиска на размеченном наборе: recall@k, nDCG@k, доля правильных документов в первых позициях и итоговое качество ответов RAG.

Даже небольшое снижение retrieval-метрики может увеличить число ручных исправлений или пропущенных документов. Если быстрый вариант создаёт больше непринятых результатов, его стоимость на полезную единицу растёт.

Особенно осторожно следует менять саму embedding-модель. Векторы разных моделей обычно несовместимы: понадобится новый индекс, параллельный прогон и план переключения. Стоимость миграции нужно учитывать заранее, а старый индекс не удалять до проверки нового.

Практичная архитектура для малого бизнеса

Часто выигрывает не «CPU против GPU», а гибридная очередь:

  • запросы пользователей и небольшие обновления идут на CPU постоянно;
  • большие импорты накапливаются в очереди и уходят на GPU в доступное окно;
  • одинаковый API скрывает выбор бэкенда от RAG-приложения;
  • идентификатор модели и версии сохраняется с каждым вектором;
  • повторная задача идемпотентна и не создаёт дубликат;
  • метрики показывают токены, принятые векторы, p95, ошибки и загрузку оборудования.

Если отдельного GPU нет, начинать стоит с оптимизированного CPU. Это использует уже знакомую инфраструктуру и даёт базовую стоимость. Ускоритель добавляют только после измерения очереди, нарушения SLA или доказанного снижения цены на принятую единицу.

Пилот за одну неделю

1. Выгрузите репрезентативные 10–50 тысяч фрагментов и сохраните их длины.
2. Зафиксируйте одну модель и один токенизатор.
3. Сравните базовый CPU, оптимизированный CPU и доступный GPU.
4. Проверьте скорость, память, p95 и качество поиска на одном наборе.
5. Посчитайте полностью нагруженную стоимость, включая простой и переиндексацию.
6. Выберите контур отдельно для онлайн-запросов, обновлений и больших импортов.

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