Тяжёлый трансформер в прод

Serving a 70B transformer

Кейс про то, что инференс LLM — отдельная инженерная дисциплина: здесь считают байты на токен и деньги на запрос, а не только качество ответа.

Senior 5 шагов разбора · 3 развилки · 5 поломок из прода

Вводная

Внутренний ассистент поддержки: отвечает по базе знаний, работает в чате, отвечает потоком.

Прототип на внешнем API показал качество, но данные клиентов наружу отдавать нельзя — модель нужно поднять в своём контуре.

Выбрана открытая модель на 70 млрд параметров: меньшие версии на длинных инструкциях заметно хуже.

Требования и ограничения
ЧтоЗначениеОткуда
Первый токенp95 TTFT ≤ 1.5 сДальше пользователь видит поток и ждёт спокойно.
Скорость потока≥ 20 токенов/с на сессиюПримерно скорость беглого чтения.
Нагрузка60 параллельных сессий в пике800 сотрудников поддержки, пик в первые часы смены.
Контекстдо 8 000 токеновИнструкция плюс 5–7 фрагментов из базы знаний.
Данныене покидают контурОтсюда собственный деплой вместо внешнего API.
Бюджетфиксированный парк GPUДокупать карты под пик нельзя — нужно уложиться в имеющиеся.

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

Разбор по шагам

Посчитать память до выбора железа

Влезет модель или нет — арифметика на одну строку, и она определяет весь дизайн.

Что означает каждый компонент
  • память только под веса: KV-кеш и активации считаются отдельно
  • число параметров модели — здесь 70 млрд
  • 2 байта для FP16 и BF16, 1 — для INT8, 0.5 — для INT4
70 млрд × 2 байта (FP16) = 140 ГБ — это только веса

В карту на 80 ГБ такая модель не помещается. Отсюда ровно три пути: тензорный параллелизм на несколько карт, , либо и то и другое.

ВариантПамять под весаЧто с качествомЧто с задержкой
FP16, тензорный параллелизм на 2 карты140 ГБ (по 70 на карту)ЭталонПлюс обмен между картами на каждом слое
INT8≈ 70 ГБПотери близки к нулюБыстрее за счёт памяти
INT4 (AWQ, GPTQ)≈ 35 ГБЗаметно на редких и длинных задачахЕщё быстрее
На практике

Под веса нельзя занимать всю карту: остаток нужен KV-кешу, а он растёт с числом сессий. Модель, которая «еле влезла», в проде упрётся в отказ обслуживания на десятой параллельной сессии.

KV-кеш — вот что ограничивает параллельность

Число одновременных сессий определяется не мощностью карты, а свободной памятью под кеш.

Что означает каждый компонент
  • память под кеш ключей и значений одной сессии
  • ключи и значения — две матрицы на каждый слой
  • число слоёв: 80 у модели на 70 млрд параметров
  • число KV-голов и размер головы: при GQA голов меньше, чем у обычного attention, — отсюда основная экономия
  • длина контекста в токенах: растёт с каждым сгенерированным токеном
  • 2 байта в FP16; кеш можно квантовать отдельно от весов
Для 80 слоёв и GQA на 8 KV-голов по 128 — около 0.33 МБ на токен

При контексте в 8 000 одна сессия съедает около 2.6 ГБ. Шестьдесят параллельных сессий — это 160 ГБ только под кеш, то есть больше, чем занимают сами веса.

  • PagedAttention хранит кеш страницами и убирает фрагментацию — на практике это кратный рост числа сессий на той же карте.
  • Prefix caching: общая системная инструкция считается один раз, а не для каждого запроса заново.
  • Ограничение контекста — тоже инженерное решение: 5 фрагментов вместо 15 экономят память линейно.
На практике

Ошибка «не хватило памяти» под нагрузкой почти всегда про KV-кеш, а не про веса: веса занимают фиксированный объём, кеш — переменный.

Непрерывный батчинг вместо статического

Утилизация карты определяется тем, как запросы складываются в батч.

Генерация идёт за токеном, и запросы заканчиваются в разное время. Статический ждёт самый длинный ответ — карта простаивает. Непрерывный подсаживает новый запрос в освободившийся слот на следующем шаге.

РежимУтилизация при нагрузке
По одному запросуНизкаяЛучшая для одного, катастрофа для
Статический СредняяЖдут все, пока не закончит самый длинный
Непрерывный ВысокаяСтабильная, деградирует плавно

Отсюда практический вывод: свой сервер писать не нужно. vLLM, TGI и TensorRT-LLM уже реализуют непрерывный и страничный KV-кеш; повторить это своими силами — месяцы работы и худший результат.

Считать деньги на запрос, а не на карту

Стоимость — такое же требование, как задержка, и она считается заранее.

Что означает каждый компонент
  • стоимость одного ответа
  • цена часа аренды карты
  • секунд в часе: переводит цену часа в цену секунды
  • сколько токенов сгенерировано — стоимость линейна по длине ответа
  • скорость генерации при текущем размере батча
Ответ на 400 токенов при 30 токенах/с и 3 $/час — около 0.011 $
  • Каскад моделей: маленькая модель отвечает на простые запросы, тяжёлая подключается по сигналу неуверенности. Самый недооценённый приём — средняя стоимость падает в разы.
  • RAG вместо длинного контекста: пять релевантных фрагментов дешевле и точнее, чем весь документ в .
  • Спекулятивное декодирование: черновик маленькой моделью, проверка большой — ускорение без потери качества.
  • Ограничение длины ответа: стоимость линейна по выходным , и лимит здесь — продуктовое решение.

Отказы, холодный старт и выкатка

У LLM-сервиса свои режимы отказа, которых нет у обычного микросервиса.

  • Холодный старт — минуты: 140 ГБ весов надо прочитать и разложить по картам. Автоскейлинг «по нагрузке» не успевает за пиком, поэтому держат тёплый резерв.
  • Очередь с ограничением: при переполнении лучше честно отказать с понятной ошибкой, чем принять запрос и отдать ответ через минуту.
  • Валидация выхода: пустой ответ, обрыв на середине, повтор одной фразы — штатные режимы генерации, и их надо отсекать до пользователя.
  • Логирование: полный лог и ответов стоит дорого и содержит персональные данные — сэмплирование плюс маскирование обязательны.
На практике

новой версии модели или проверяется shadow-режимом по задержке и офлайн-оценкой по набору эталонных диалогов: у генерации нет метрики «точность», поэтому набор регрессионных примеров — единственная защита от тихой деградации.

Развилки и выбор

На собеседовании ценится не сам выбор, а объяснение, почему отклонены остальные варианты.

Квантизовать или ставить вторую карту?

INT8 на одной карте, тензорный параллелизм — как запасной путь

INT8 сокращает веса до ≈70 ГБ, освобождает память под KV-кеш и убирает межкарточный обмен из критического пути. Потери качества на регрессионном наборе оказались в пределах шума.

Что отклонено и почему
  • FP16 на двух картахЭталонное качество, но вдвое дороже и добавляет синхронизацию на каждом слое; оправдано, если INT8 проваливает регрессионный набор.
  • INT4Влезло бы с запасом, но на длинных инструкциях качество просело заметно — для ассистента поддержки это прямой рост эскалаций.

Свой сервер инференса или готовый?

Готовый (vLLM)

Непрерывный батчинг и страничный KV-кеш — это и есть основная ценность; переписывать их своими силами дороже и хуже.

Что отклонено и почему
  • Самописный сервер на transformersПростой код, в 5–10 раз худшая утилизация карты под нагрузкой.
  • TensorRT-LLM сразуБыстрее на пике, но компиляция под каждую версию модели и железо усложняет выкатку; разумный второй шаг, когда конфигурация устоялась.

Что делать с пиком в начале смены?

Тёплый резерв плюс очередь с ограничением

Холодный старт в минуты делает реактивный автоскейлинг бесполезным, а пик предсказуем по расписанию смен.

Что отклонено и почему
  • Автоскейлинг по загрузке GPUРеплика поднимается дольше, чем длится пик; пользователи получают отказы ровно тогда, когда система «уже масштабируется».
  • Держать парк под пик постоянноКарты простаивают большую часть суток — самая дорогая из возможных стратегий.

Что ломается в проде

Память кончается не там, где её считали

Веса занимают фиксированный объём, а KV-кеш растёт с числом и длиной сессий. Нагрузочный тест на коротких запросах ничего не докажет: ломается система на длинных контекстах.

Квантизация ломает хвост, а не среднее

На типовых запросах INT4 неотличим от FP16, а на редких и длинных проваливается. Проверять надо на наборе сложных случаев, иначе деградация всплывёт у самых требовательных пользователей.

Средняя задержка скрывает очередь

При росте нагрузки TTFT растёт быстрее, чем скорость генерации: запрос ждёт слота в батче. Мерить нужно и время до первого токена, и время между токенами.

Логи промптов — это деньги и персональные данные

Полное логирование LLM-трафика способно стоить дороже самого инференса и почти наверняка содержит данные клиентов. Сэмплирование и маскирование закладывают сразу, а не после аудита.

Нет регрессионного набора — нет выкатки

У генерации нет одной метрики качества. Без фиксированного набора эталонных диалогов любое обновление модели или параметров декодирования — прыжок в темноте.

По чему видно, что система здорова

МетрикаЗначениеЗачем
TTFTp50 / p95 времени до первого токенаГлавная воспринимаемая метрика чата.
TPOTвремя между токенамиОпределяет, читается ли поток комфортно.
Утилизация KV-кеша% занятой памяти под кешРанний сигнал приближения к отказам.
Отказы по очередидоля отклонённых запросовЧестный отказ лучше ответа через минуту, но его надо считать.
Стоимость запроса$ на 1000 ответовСчитается по выходным токенам и цене часа GPU.
Регрессия качестваоценка на эталонном наборе диалоговГейт перед выкаткой любой новой конфигурации.

Что спрашивают по этому кейсу

  1. Модель на 70 млрд параметров, карта на 80 ГБ. Ваши варианты и что выберете?
  2. Сколько параллельных сессий выдержит система и от чего это число зависит?
  3. TTFT вырос вдвое при том же RPS. Где искать причину?
  4. Как проверить, что квантизация не испортила качество?
  5. Пик приходит в 9 утра и длится 40 минут. Как обслуживать его без простоя карт весь день?

Проверить себя: тест «NLP», тест «Генеративный ИИ и LLM», тест «MLOps и инженерия». Открытые задачи там же — под тестом.

Темы атласа, из которых собран кейс

LLM Serving

Обслуживание LLMиз «Системный дизайн ML-сервисов»

KV-кеш, непрерывный батчинг, потоковая отдача.

GPU Inference

GPU-инференсиз «Системный дизайн ML-сервисов»

Квантизация, компиляция, мультиарендность на карте.

Cost Model

Экономика сервисаиз «Системный дизайн ML-сервисов»

Как считают стоимость запроса и где она прячется.

Batching and Queues

Батчинг и очередииз «Системный дизайн ML-сервисов»

Очереди, ограничение нагрузки и деградация.

GPU Architecture

Архитектура GPUиз «Вычислительная инфраструктура»

Почему декодирование упирается в память, а не в вычисления.

AI Accelerators

Ускорители: GPU, TPU, NPUиз «Вычислительная инфраструктура»

Что выбирать под инференс и чем карты различаются.

RAG

RAGиз «Генеративный ИИ»

RAG как способ сократить контекст и стоимость.

LLM Evaluation

Оценка языковых моделейиз «Генеративный ИИ»

Регрессионный набор вместо метрики «точность».

Prompt Injection

Промпт-инъекциииз «Безопасность ИИ»

Риски, специфичные для LLM в контуре компании.