С развитием искусственного интеллекта и ростом популярности больших языковых моделей (LLM) возникает необходимость их эффективного и масштабируемого обслуживания. Одним из передовых решений в этой области является open-source движок для инференса vLLM V1, разработанный Ubicloud. Эта система отличается высокой производительностью и уникальной архитектурой, которая позволяет быстро обрабатывать огромное количество запросов с максимальным использованием ресурсов GPU. В данной статье подробно рассматривается жизненный цикл запроса на вывод (инференс) в vLLM V1, что поможет понять, какие технологии и методы лежат в основе современного сервера для масштабного обслуживания LLM. Ubicloud, позиционируемый как открытая альтернатива AWS, реализует управляемые облачные сервисы, основанные на PostgreSQL, Kubernetes и vLLM.
Ключевая задача vLLM — эффективно обслуживать крупные языковые модели, такие как Llama 4, распределяя нагрузку по нескольким GPU-инстансам и обеспечивая балансировку трафика и устойчивость системы. Пользователи взаимодействуют с системой через OpenAI-совместимые API, которые принимают запросы, определяют, какой из инстансов vLLM обработает запрос, и возвращают результаты. Жизненный цикл запроса начинается с момента поступления HTTP-запроса в API-сервер vLLM. Обычно это POST-запрос на endpoint /v1/chat/completions, который содержит набор сообщений клиента, оформленных в формате, совместимом с OpenAI. Сервер обрабатывает аутентификацию, проверяет корректность данных и передает управление движку AsyncLLM, асинхронному обертке поверх EngineCore — центрального компонента, отвечающего за вычисления.
AsyncLLM занимается токенизацией входного текста, преобразуя его в числовые идентификаторы токенов через токенизатор Hugging Face и отправляет запрос в EngineCore с помощью высокопроизводительной межпроцессной коммуникации (IPC) по протоколу AsyncMPClient. Разделение AsyncLLM и EngineCore на различные процессы — важная архитектурная особенность. Это позволяет обойти глобальную блокировку интерпретатора Python (GIL) и эффективно распараллелить CPU-интенсивные задачи, такие как обработка HTTP и токенизация, и GPU-вычисления для инференса модели. Внутри EngineCore запросы попадают в внутреннюю очередь, откуда их забирает планировщик (Scheduler). Scheduler — сердце системы для управления одновременной обработкой множества запросов.
Он поддерживает очередь запросов, готовых к обработке, и список текущих в работе. В каждом цикле работы системы Scheduler решает, сколько токенов вычислить для каждого запроса, используя концепцию непрерывного бэтчинга (continuous batching). Эта технология позволяет максимально эффективно загружать GPU, объединяя запросы в батчи, при этом учитывая заданный лимит на максимальное количество токенов в одном бэтче. Такой подход отличается от классического обработки запросов по очереди и позволяет обеспечить справедливость и высокую производительность. Для иллюстрации: если есть три запроса с длиной промпта в 3, 5 и 12 токенов и существует ограничение в 10 токенов за бэтч, Scheduler может сформировать батч из 3 токенов первого запроса, 5 второго и 2 токенов третьего.
В следующем цикле он продолжит с оставшимися 10 токенами третьего запроса и начнет генерацию ответных токенов для первых двух запросов. Это повышает параллелизм и снижает задержки. Обработка запроса разделяется на две фазы: prefill и decode. В фазе prefill модель обрабатывает токены входящего промпта, вычисляя ключи и значения (KV-тензоры) механизма внимания трансформера и сохраняя их в KV-кэше, который представляет собой эффективное хранилище на GPU, оптимизированное для быстрого чтения и записи. После завершения обработки промпта начинается фаза decode, когда модель по одному генерирует новые токены ответа, повторно используя сохраненные KV-тензоры и вычисляя новые запросы (Query).
Такой поэтапный подход обеспечивает эффективность при работе с длинными последовательностями. KV-кэш реализован в виде блоков фиксированного размера — KV-блоков. Это позволяет эффективно управлять GPU-памятью, динамически выделяя и переиспользуя места под ключи и значения без необходимости резервации больших непрерывных блоков памяти. Управление этим кэшем принадлежит модулю KVCacheManager, который вместе с Scheduler определяет, какие блоки выделять для очередных токенов каждого запроса и передает идентификаторы блоков следующему звену — ModelRunner. Реализация загрузки и исполнения модели на GPU распределена между компонентами ModelExecutor и ModelRunner.
Каждый GPU выделяется отдельный worker-процесс под управлением ray — распределенной compute-библиотеки, которая оптимизирует параллельную обработку и распределение нагрузки на устройства. ModelRunner непосредственно загружает весовые коэффициенты модели, формирует батчи запросов, запускает вычисления вперед проходят в рамках трансформера. Послойная обработка входных данных происходит через 64 слоя трансформера (например, в модели DeepSeek R1 Distilled Qwen 32B), на каждом из которых вычисляются тензоры ключей (K), значений (V) и запросов (Q) с использованием высокоэффективной реализации FlashAttention-3. GPU прекрасно справляется с такими массовыми матричными операциями благодаря поддержке технологии SIMD(T), позволяющей одновременно обработать данные всех токенов в батче по разным ядрам CUDA. После формирования логитов (вероятностных распределений по следующим токенам) для каждого запроса применяется выбранная стратегия сэмплинга — например, жадный выбор наиболее вероятного токена или стохастическая выборка с учетом параметров температуры и топ-k.
Полученные токены направляются в внутреннюю очередь для дальнейшей передачи клиенту. Завершающий этап обработки происходит в AsyncLLM, который получает эти токены из EngineCore по IPC, выполняет детокенизацию — преобразование численных идентификаторов обратно в текст — и передает результаты API-серверу. В режиме потоковой передачи (streaming) клиенту отправляются частичные результаты по мере генерации каждого токена, что уменьшает задержки восприятия вывода и улучшает качество взаимодействия. В обычном режиме сервер накапливает все токены и возвращает ответ целиком после завершения генерации. Архитектура vLLM V1 выгодно отличается от предыдущих версий и других решений тем, что использует продвинутую модель распределения задач и управления памятью, позволяет выполнять непрерывное объединение запросов без значительного перепланирования, а также минимизирует накладные расходы на межпроцессное взаимодействие.