vLLM: hardware-agnostic слои для любого железа
Выжать максимум из новейшего железа и при этом не сломать поддержку всего остального. Это главный инженерный конфликт в мире открытых языковых моделей, и vLLM нашёл для него архитектурный ответ. Проект представил набор hardware-agnostic слоёв: движок продолжает работать на AMD, Intel, Google TPU, IBM Spyre и старых GPU, отставая на NVIDIA H100 от нативной реализации всего на 3,4%. Разбираем, зачем понадобилась такая страховка и как она устроена.
Что такое vLLM
vLLM это открытый движок инференса для больших языковых моделей (LLM) и один из де-факто стандартов для запуска открытых весов. Одна кодовая база обслуживает самые разные модели на самом разном железе: NVIDIA GPU, AMD GPU, Intel XPU, Google TPU, IBM Spyre, Huawei Ascend и не только. Держать это вместе удавалось за счёт продуманных абстракций и torch.compile, который берёт на себя оптимизацию и фьюжены. Поэтому внутренние реформы vLLM касаются не только его мейнтейнеров: от них зависит, какие модели и на каком железе смогут работать быстро и дёшево.
Фронтир против портируемости
Годами схема работала: модели описывались простыми строительными блоками, а скорость выжимал компилятор. Но архитектуры фронтирных открытых моделей начали расходиться всё сильнее. У каждой свои кастомные слои и оптимизированные кернелы, причём это касается даже ядра механизма внимания: DeepSeek V4 и Kimi K3 оба достигают контекста в миллион токенов, но принципиально разными способами.
Чтобы добавить такую модель в vLLM, её нужно собрать из общих слоёв в model_executor/layers и сохранить полную компилируемость графа: написать так, чтобы Dynamo мог трассировать модель, а каждый новый кернел был зарегистрирован как torch-операция с fake-реализацией и корректными аннотациями мутаций. Это налог на разработку, и платит его каждый, кто добавляет модель, включая продвинутых пользователей, которые приносят свои.
Параллельно NVIDIA Blackwell и стоечные системы вроде GB300 NVL72 требуют аккуратной кернел-инженерии, чтобы новые фичи и перекрытие вычислений с коммуникациями работали как задумано. А ещё появились кодинг-агенты вроде Claude Code и OpenAI Codex: они отлично генерируют оптимизации под конкретную модель на конкретном железе, но работают лучше всего, когда изменение не обязано оставаться безопасным для других моделей и ускорителей.
В сумме эти тренды ведут к тому, что ради рекордов на свежих GPU vLLM начинает поддерживать hardware-specific model definitions, или flat-модели. Вместо torch.compile они используют кастомные фьюжены и оптимизации под конкретное железо, и все новые фронтирные модели последних месяцев добавляются именно так. Критический момент: слои и операции, на которые опираются такие модели, будут рефакториться в сторону несовместимости с torch.compile.
Кому это создаёт проблемы
Первыми под удар попадают out-of-tree (OOT) плагины для внешних ускорителей. Пример из статьи, IBM Spyre: он опирается на TorchDynamo для трассировки графа и TorchInductor, который понижает граф до представлений, оптимальных для его железа. Кроме компиляции, таким ускорителям иногда нужно впрыскивать в слои собственное поведение, например кастомные layout'ы памяти. Для этого в vLLM есть два механизма: CustomOp, переопределяющий forward-функцию, и PluggableLayer, переопределяющий слой целиком. Если эту расширяемость убрать, каждому плагину придётся тащить собственный набор model definitions и слоёв. Добавление одной новой модели превратится в пул-реквесты в transformers, vLLM и каждый плагин по отдельности: сожжённые токен-бюджеты нескольких организаций без реальной выгоды.
Вторая группа это старые и экзотические модели. vLLM всё активнее полагается на transformers-бэкенд, чтобы их поддерживать: legacy-определения удаляются из model_executor/models, а записи реестра переводятся напрямую на модели из transformers. Без torch-совместимых слоёв производительность таких моделей на GPU заметно просядет.
Третья группа это владельцы старых и consumer/prosumer GPU. Flat-слои оптимизируют под фронтирное железо, и авторы прямо говорят, что не ожидают поддержки таких карт в новом пути. При этом статистика использования vLLM показывает: значимая часть базы продолжает работать именно на этом железе, и проект хочет развиваться так, чтобы учитывать её нужды.
Как устроен vLLM сегодня
Чтобы понять решение, полезно взглянуть на текущее состояние. В vLLM три разновидности model definitions: новые flat-модели в vllm/models/, legacy-модели в vllm/model_executor/models и transformers-бэкенд, импортирующий модели прямо из transformers. Во всех трёх случаях общие слои, а это attention, mixture-of-experts (MoE), линейные проекции, нормы и активации, реализованы в одном месте. Даже когда модуль приходит из transformers, его автоматически перепроводят на использование vLLM-слоёв. Например, RowParallelLinear существует в единственной реализации, а плагин вроде SpyreRowParallelLinear переопределяет её только на своём ускорителе.
Единая реализация это ещё и экономия: поддерживать десятки архитектур на десятках ускорителей можно только тогда, когда большая часть кода общая, а различия изолированы в опциях и плагинах. Без общего ядра каждая новая комбинация модели и железа грозила бы отдельным форком, а стоимость поддержки росла бы комбинаторно.
Именно эта общность делает реформу болезненной: сломать совместимость слоёв с torch.compile ради фронтирных нужд означает сломать её сразу для всех трёх путей.
Решение: hardware-agnostic слои
Ответ vLLM такой: построить набор hardware-agnostic слоёв прямо в дереве репозитория, в каталоге model_executor/hw_agnostic. У него четыре принципа дизайна:
- Compilable: определения моделей остаются полностью torch-компилируемыми, чтобы акселераторы, которым компиляция нужна для скорости, продолжали работать как раньше.
- Extensible: механизмы CustomOp и PluggableLayer сохраняются, чтобы OOT-плагины могли переопределять реализацию, когда это необходимо.
- Isolated: у hw-agnostic пути свои слои и операции, отдельные от hardware-specific, и обе линии разработки могут двигаться быстро, не мешая друг другу.
- Portable: все слои пишутся на нативном PyTorch или портируемых DSL вроде Triton и Helion, чтобы работать на любых ускорителях, где они поддерживаются.
Каждый из принципов закрывает свою боль: Compilable сохраняет скорость transformers-бэкенда и внешних ускорителей, Extensible оставляет плагинам возможность переопределять поведение под своё железо, Isolated означает, что эксперименты на фронтире не будут случайно ломать портируемый путь, а Portable делает модель независимой от конкретного вендора.
Часть работы уже влита в main. Процесс «перепроводки» transformers-моделей переключён на новые слои вместо старых из model_executor/layers, а включить путь можно одной переменной окружения:
USE_HW_AGNOSTIC=1 vllm serve google/gemma-4-31B --model-impl=transformers
Новый маршрут проверен на плагине Spyre с моделями Gemma 4, Qwen3 и Granite 4.2. Дальше авторы планируют включить hw-agnostic модели в CI и постепенно сделать этот путь дефолтным для сервинга на Spyre. Для flat-моделей появится отдельный model.py, собранный из hw-agnostic слоёв: общие слои переедут в model_executor/hw_agnostic, а специфичные для конкретной модели (в статье приводится пример DeepSeekV4FlashMLAAttention) останутся рядом с ней, но будут следовать тем же четырём принципам. Первый крупный шаг уже виден: hardware-agnostic реализация DeepSeek V4 проходит ревью.
Сколько это стоит в цифрах
Насколько портируемость медленнее? На NVIDIA H100 авторы сравнили transformers-бэкенд с USE_HW_AGNOSTIC=0 и USE_HW_AGNOSTIC=1 на трёх свежих моделях. Суммарная пропускная способность (total token throughput) у hardware-agnostic версии оказалась в пределах 3,4% от нативной по геометрическому среднему, а в некоторых случаях она даже немного быстрее. Речь при этом о реализации, собранной исключительно из портируемых слоёв, без CUDA-библиотек вроде FlashAttention и CUTLASS.
Авторы честно оговаривают: цель новых слоёв не SOTA на Blackwell, CDNA 4 и новее. Цель это переносимость и предсказуемая производительность на разнообразном железе, включая внешние ускорители, старые и потребительские GPU. Иными словами, это не замена нативного пути, а параллельная дорожка для тех, кому важна портируемость.
Практический вывод из замеров простой: портируемый путь не обязан быть медленным. Разница в 3,4% меньше, чем типичный разброс между версиями драйверов и конфигурациями батчинга, так что для большинства команд опора на hardware-agnostic путь не обернётся заметным ростом стоимости инференса.
Почему это важно за пределами vLLM
История vLLM иллюстрирует более общий сдвиг. Открытые веса перестали быть монокультурой: лаборатории выпускают модели с уникальными архитектурами, и инференс-стек превращается в место, где решается, будет ли железо взаимозаменяемым или привязанным к одному вендору. Подход с hw-agnostic слоями это ставка на взаимозаменяемость: одна модель, много бэкендов, минимальная цена в производительности.
Второй сюжет это экономика кернелов. Кодинг-агенты уже сейчас дёшево генерируют оптимизации под конкретное железо, и это меняет расчёты: то, что раньше требовало команды инженеров, может написать агент за одну сессию. Но эффект будет максимальным, только когда оптимизации для одного ускорителя не обязаны учитывать все остальные. Изоляция слоёв делает именно это.
Третий вывод для практиков: апгрейд vLLM перестаёт быть риском для команд на старом или не-NVIDIA железе. Если вы запускаете открытые модели на AMD, Intel, Spyre или подержанных GPU, у проекта теперь есть явное направление, в котором ваши сценарии это не второй сорт, а первый класс поддержки. Это и сигнал производителям железа: поддерживать новый ускоритель становится дешевле, когда не нужно тащить собственный набор моделей и слоёв.
И ещё один контекст: спор о том, кто контролирует ИИ-инфраструктуру, давно вышел за пределы CUDA-монополии. Vulkan и Mojo уже бросили вызов монополии одного вендора в графике и компиляции, а vLLM добавляет к этому списку инференс, самый чувствительный к цене участок стека.
Часто задаваемые вопросы
Что такое hardware-agnostic слои в vLLM?
Это набор общих слоёв движка (attention, MoE, линейные слои и другие), написанных на портируемых технологиях: нативном PyTorch, Triton или Helion. Они изолированы от hardware-specific оптимизаций и позволяют одной реализации модели работать на разных ускорителях без отдельного кода под каждый.
Означает ли это отказ vLLM от torch.compile?
Нет, наоборот. Flat-модели для фронтирного железа действительно обходятся без него, но hardware-agnostic путь целиком компилируемый. Более того, compile остаётся критичным для внешних акселераторов вроде Spyre и для скорости transformers-бэкенда на GPU. Теперь это просто не единственный путь в проекте.
Как попробовать hardware-agnostic путь?
Нужна свежая сборка vLLM из main: запустите сервер с переменной USE_HW_AGNOSTIC=1 и transformers-бэкендом, например на Gemma 4. Пока путь покрывает ограниченный набор слоёв и остаётся work-in-progress, так что для продакшена стоит дождаться расширения поддержки. Статус можно отслеживать по RFC и каналу #hw-agnostic-models в vLLM Slack.
Почему это происходит именно сейчас?
Сошлись три фактора: архитектуры фронтирных моделей перестали вписываться в общие абстракции, Blackwell и стоечные системы потребовали тонкой кернел-инженерии, а кодинг-агенты резко удешевили разработку оптимизаций под конкретное железо. Вместе это сделало быстрый hardware-specific путь экономически осмысленным, и vLLM понадобилась компенсирующая дорожка для всех остальных.
Итог
vLLM разводит два конфликтующих требования: выжимать максимум из новейшего железа и не терять всех остальных. Flat-модели дают первое, hardware-agnostic слои возвращают второе, а цена компромисса на H100 измеряется цифрой 3,4%. Для экосистемы открытых моделей это важный сигнал: гонка за производительностью не обязана заканчиваться привязкой к одному вендору.
Попробуйте USE_HW_AGNOSTIC=1 на своих моделях и сравните с нативным путём. Если цифры разойдутся с описанными 3,4%, расскажите об этом: публичных замеров на не-NVIDIA железе сейчас мало, и каждый такой результат делает экосистему честнее.