Демо прошло отлично, ассистент поддержки работает — а через месяц финансы присылают счёт, как за трёх разработчиков, и продукт жалуется на 15–20 секунд до первого токена. nvidia-smi показывает утилизацию 100%, и кажется, что выход один — докупать GPU. Но чаще проблема в другом: карты снова и снова пересчитывают одни и те же длинные промпты.
Ниже — маршрут из шести шагов, который описал Сергей Прощаев (Tech Lead, преподаватель ОТУС) на примере реального стека: Llama 3.3 70B Instruct на двух репликах по 2×H100 SXM 80 GB, vLLM V1, Kubernetes, Envoy Gateway, Prometheus, Grafana, DCGM Exporter. Чекпойнт и парк карт не меняются — меняются конфигурация сервинга и точность весов.
Почему nvidia-smi врёт о реальной загрузке
GPU-Util в nvidia-smi показывает долю времени, когда на карте выполнялось хоть какое-то вычислительное ядро — не то, насколько она занята полезной работой. H100 выдаёт 3,35 ТБ/с пропускной способности памяти при 989 TFLOPS в FP16, но при генерации токенов используется лишь около 10–20% этой вычислительной мощности. Узкое место почти всегда в памяти, а не в вычислениях.
Для реальной диагностики нужны DCGM-метрики профилирования:
DCGM_FI_PROF_DRAM_ACTIVE— загрузка памятиDCGM_FI_PROF_SM_ACTIVE— активность вычислительных блоков
Главная экономическая метрика — GPU-часы на миллион выходных токенов при соблюдении SLA. Именно она показывает, подешевел ли токен после оптимизации, а не просто улучшился ли TTFT.
Шаг 1: снять базовую линию до любых изменений
Без замера до и после любая оптимизация — спор мнений. Сначала считаем стоимость одного миллиона токенов:
# GPU-only стоимость 1M выходных токенов за неделю
GPU_HOUR_PRICE = 2.0 # внутренняя ставка часа одной H100
GPUS = 4 # 2 реплики × 2 GPU
HOURS = 24 * 7 # тот же интервал, что и в PromQL ниже
TOKENS_WEEK = 907_200_000 # sum(increase(vllm:generation_tokens_total[7d]))
gpu_hours_per_1m = GPUS * HOURS / (TOKENS_WEEK / 1_000_000)
print(f"{gpu_hours_per_1m:.3f} GPU-ч на 1M токенов, "
f"{gpu_hours_per_1m * GPU_HOUR_PRICE:.2f} за 1M")
# 0.741 GPU-ч, 1.48 за 1MПараллельно снимаем метрики из Prometheus. Имена счётчиков в документации vLLM записаны без суффикса, в экспозиции Prometheus у них есть _total — сверяйте с /metrics своей версии:
# Все выходные токены за неделю — основа для стоимости
sum(increase(vllm:generation_tokens_total[7d]))
# TTFT p95 за неделю
histogram_quantile(0.95,
sum by (le) (increase(vllm:time_to_first_token_seconds_bucket[7d])))
# Hit rate префиксного кэша
sum(increase(vllm:prefix_cache_hits_total[7d])) /
sum(increase(vllm:prefix_cache_queries_total[7d]))
# Соотношение входных токенов к выходным — быстрый индикатор повторяемости промптов
sum(increase(vllm:prompt_tokens_total[7d])) /
sum(increase(vllm:generation_tokens_total[7d]))Шаг 2: включить и правильно настроить префиксный кэш
Префиксный кэш (prefix caching) в vLLM позволяет не пересчитывать KV-состояние для повторяющихся начал промптов. При системном промпте в 3 000 токенов и сотнях одновременных пользователей это прямая экономия prefill-времени на каждом запросе.
В конфигурации vLLM V1 кэш включается параметром запуска:
vllm serve meta-llama/Llama-3.3-70B-Instruct \
--enable-prefix-caching \
--max-model-len 8192 \
--gpu-memory-utilization 0.90После включения следите за vllm:prefix_cache_hits_total / vllm:prefix_cache_queries_total. Hit rate выше 60–70% при RAG-нагрузке с фиксированным системным промптом — нормальный результат.
Шаг 3: квантизация весов без смены чекпойнта
Квантизация снижает потребление памяти и увеличивает пропускную способность за счёт уменьшения точности весов. BF16-чекпойнт Llama 3.3 70B занимает около 140 ГБ; при переходе на FP8 — вдвое меньше, что на двух H100 по 80 ГБ принципиально меняет картину с тензорным параллелизмом.
vLLM поддерживает квантизацию на лету через флаг --quantization:
vllm serve meta-llama/Llama-3.3-70B-Instruct \
--quantization fp8 \
--enable-prefix-caching \
--tensor-parallel-size 2 \
--gpu-memory-utilization 0.90| Режим | VRAM на 70B | Потеря качества (MMLU) |
|---|---|---|
| BF16 | ~140 ГБ | baseline |
| FP8 | ~70 ГБ | < 1% |
| INT4 (AWQ/GPTQ) | ~35 ГБ | 1–3% |
Где это ломается
Промпты уникальны. Если каждый запрос содержит уникальный контекст и системный промпт меняется — hit rate кэша будет близок к нулю, шаги с префиксным кэшем не дадут эффекта. Проверяйте соотношение prompt/generation токенов до начала оптимизации.
Метрики не совпадают с версией vLLM. Имена счётчиков менялись между минорными версиями. Всегда сверяйте названия с /metrics вашего инстанса, а не с документацией другой версии.
GPU-Util растёт после квантизации. Это нормально: карта делает больше работы за то же время. Смотрите на GPU-часы на миллион токенов — если метрика снизилась, оптимизация работает.
Улучшился только TTFT, но не пропускная способность. Снижение TTFT само по себе не удешевляет токен. Деньги экономятся тогда, когда освобождённое время GPU превращается в большее число обслуженных запросов на тех же картах.
Что попробовать дальше
После базовых шагов стоит посмотреть на speculative decoding (ускорение decode-фазы через черновую модель), chunked prefill (разбивка длинных промптов на чанки для снижения TTFT при высокой нагрузке) и disaggregated serving — разделение prefill и decode на разные узлы, которое vLLM V1 начал поддерживать экспериментально.
Замкнутый контур «замер — изменение — повторный замер» обязателен на каждом шаге. Только цифры GPU-часов на миллион токенов дают обоснованный ответ на вопрос, нужны ли новые карты.
FAQ
Как быстро понять, поможет ли префиксный кэш в моём случае?
Посмотрите на соотношение vllm:prompt_tokens_total / vllm:generation_tokens_total за неделю. Если оно больше 5–10 и системный промпт фиксирован — префиксный кэш даст заметный эффект. Если промпты уникальны, hit rate будет близок к нулю.
Можно ли включить FP8-квантизацию без переобучения модели?
Да, vLLM поддерживает динамическую квантизацию через флаг --quantization fp8 без изменения чекпойнта. На H100 FP8 поддерживается аппаратно, деградация качества по MMLU обычно меньше 1%.
Что такое TTFT и почему p95, а не среднее?
TTFT (Time To First Token) — время от отправки запроса до получения первого токена ответа. p95 показывает, что испытывают 5% самых «невезучих» пользователей в пиковую нагрузку. Среднее скрывает хвосты распределения, которые и создают жалобы.
Почему nvidia-smi показывает 100%, а карта всё равно не справляется?
GPU-Util в nvidia-smi фиксирует любую активность ядра, а не полезную загрузку. При генерации токенов узкое место — пропускная способность памяти, а не вычисления. Используйте DCGM_FI_PROF_DRAM_ACTIVE для реальной диагностики.
Нужно ли менять код приложения для включения префиксного кэша?
Нет, если системный промпт уже передаётся первым сообщением в каждом запросе. Кэш включается на стороне vLLM одним флагом. Важно только не менять порядок сообщений и не добавлять динамические токены перед системным промптом.


