Главная / Статьи / Запуск Qwen3.8-27B на одной карте RTX 3090 с обновленным vLLM и DFlash2

Запуск Qwen3.8-27B на одной карте RTX 3090 с обновленным vLLM и DFlash2

Как форк vLLM 0.28.0 с фиксированным состоянием, использующий реквантизированные эмбеддинги и технологию DFlash2 для спекулятивных вычислений, позволяет запускать гибридную модель объемом 27 миллиардов параметров на карте с памятью 24 ГБ, и почему длинный контекст замедляет ее работу.

3193 слов

Модель с 27 миллиардами параметров, работающая на обычной потребительской видеокарте, как правило, требует трудного выбора между длиной контекста, одновременностью обработки и скоростью. Коммунити-версия vLLM, отрегулированная для Qwen3.8-27B, меняет ситуацию на видеокарте RTX 3090 объемом 24 ГБ: в задачах с использованием агентов она достигает скорости декодирования примерно 177 токенов в секунду на обычной карте (без серии Ti) с ограничением мощности в 300 Вт. В этом руководстве описывается установка без использования контейнеров, объясняются те оптимизации, которые обеспечивают такую скорость, и показано, на каком этапе данный подход перестает быть эффективным, чтобы вы могли решить, подходит ли он вашей задаче.

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

| Config     | Context   | Parallel requests | My measured decode speed |
|------------|-----------|-------------------|--------------------------|
| CTX=fast   | 65,536    | 8                 | ~177 tok/s               |
| CTX=long   | 131,072   | 4                 | ~122 tok/s               |

Поскольку сервер предоставляет API, совместимое с OpenAI, его интеграция в такие инструменты для управления агентами, как DeepSeek Harness, заключается в указании клиентом базового URL вида http://<host>:18020/v1 и предоставлении ключа-пропуска. Затем субагенты могут одновременно отправлять запросы к локальной модели, которая отвечает с такой скоростью, какая ранее требовала оборудования дата-центра.

Что на самом деле представляет собой проект qwen38-27b-rtx3090

Проект находится в репозитории syv-ai/qwen38-27b-rtx3090. Это ни новая модель, ни новый двигатель инференса. Это форк версии vLLM 0.28.0 с набором патчей, скриптов для реквантизации и профилей запуска, единственная цель которых — адаптировать эту конкретную гибридную модель к карте объемом 24 ГБ и обеспечить ее быструю работу.

Предоставляется образ Docker, и команда docker compose --profile single up -d является полным решением для установки, если вы довольствуетесь контейнерами. Репозиторий также позволяет выполнять те же действия вручную в виртуальной среде Python, что и было сделано здесь. Этот подход сохраняет логи в видимом формате, избегает создания ещё одного крупного образа на диске и упрощает отслеживание изменений при каждом шаге.

Почему показатель в виде одного tok/s мало что значит

Пропускная способность этой системы во многом зависит от задачи. Генерация кода происходит быстро, написание длинных прозаических текстов — медленнее, а воспроизведение уже имеющегося в запросе текста происходит значительно быстрее (причины этого объясняются в разделе ниже, посвящённом поиску и составлению черновика). В документации проекта также подчёркивается тот же момент: число пропускной способности для этой системы не имеет значения, если вы не знаете, какой именно запрос его породил. Значение 177 токов/с было получено при тестировании с заданиями для агента; ваши результаты будут зависеть гораздо больше от формулировок ваших запросов, чем от случайных факторов.

Установка нативно, без Docker

Прежде чем начинать, убедитесь, что у вашего компьютера есть:

  • Linux или WSL2 с видеокартой RTX 3090 любой версии (важна её объёмная память VRAM в 24 ГБ)
  • Актуальный драйвер NVIDIA, чтобы команда nvidia-smi выполнялась без ошибок
  • Python 3.12 или новее вместе с соответствующими заголовками для разработки
  • Набор инструментов CUDA 13, или по крайней мере его заголовочные файлы (см. подводные камни в шаге 2)
  • Около 60 ГБ свободного места на диске для моделей и кэша
  • Практический способ ускорения выполнения системных предпосылок — использовать агента для программирования с доступом к оболочке (Claude Code, Codex, OpenCode или аналоги) для управления процессом установки. Укажите ему репозиторий и попросите запустить необходимые компоненты на вашей карте 3090. При возникновении ошибок агент читает сообщение об ошибках и решает проблему на месте: будь то установка python3.12-dev или libssl с помощью apt, обновление драйвера или смена наборов инструментов CUDA. Это превращает поиск отсутствующих пакетов, требующий целого дня поисков в форумах, в обычную процедуру. Проверяйте, что выполняет агент, как вы бы делали с любым инструментом с доступом к оболочке.

    Шаг 1: клонирование репозитория

    Начните с загрузки репозитория и перехода в него.

    git clone https://github.com/syv-ai/qwen38-27b-rtx3090
    cd qwen38-27b-rtx3090
    

    Шаг 2: создание виртуальной среды и установка фиксированной версии vLLM

    Форк предназначен именно для версии vLLM 0.28.0, поскольку именно в этой версии спекулятивная декодировка DFlash2 стала частью основного кода vLLM (была объединена в PR #52816). Приведённые ниже команды создают новую виртуальную среду и устанавливают именно эту версию вместе с FlashInfer — инструментом загрузки с Hugging Face, ninja для сборки ядра и pandas.

    python3.12 -m venv venv
    venv/bin/pip install -U pip
    venv/bin/pip install vllm==0.28.0 huggingface_hub hf_transfer ninja \
      flashinfer-python flashinfer-cubin==0.6.13 pandas
    

    Здесь есть два момента, в которых легко ошибиться:

    • Не позволяйте pip перемещать flashinfer-python на другую версию. Запускающий скрипт устанавливает параметр FLASHINFER_DISABLE_VERSION_CHECK=1, и патчи были протестированы именно с учётом этой фиксированной пары версий.
  • Путь отбора проб DFlash2 компилирует ядро FlashInfer во время выполнения, и это ядро содержит файл curand.h. Если у вас установленная версия CUDA не включает заголовочные файлы curand, компиляция сразу после запуска завершается с ошибкой, и сервер тихо переключается на более медленный режим работы. Результат работы остаётся корректным, пропускная способность снижается примерно на 5%, но в логах об этом не указывается. На Ubuntu с CUDA 13 проблему удаётся решить, установив пакет libcurand-dev-13-0 с помощью apt.
  • Второй пример — хороший пример сбоя, который невозможно обнаружить с помощью проверок работоспособности. Если показатели немного ниже ожидаемых, сначала проверьте наличие этих заголовочных файлов.

    Шаг 3: скачивание базового чекпоинта

    Начальной точкой является чекпоинт dbirks/Qwen3.8-27B-W4A16-AutoRound объёмом около 19,5 ГБ. Включение режима передачи данных Xet с высокой производительностью значительно ускоряет загрузку.

    HF_XET_HIGH_PERFORMANCE=1 venv/bin/hf download \
      dbirks/Qwen3.8-27B-W4A16-AutoRound \
      --local-dir models/Qwen3.8-27B-W4A16-AutoRound
    

    Шаг 4: подготовка модели

    Скрипты в папке prepare/ модифицируют чекпоинт. Они переквантизируют матрицы вхождения и выхода, которые стандартные квантизированные чекпоинты сохраняют с полной точностью, пересоздают голову модели MTP с учётом более подходящего словаря, а затем загружают более быструю версию вместе с файлом DFlash2 размером 1,2 ГБ. Всё выполняется на процессоре, и каждый скрипт завершается в течение нескольких минут.

    M=models/Qwen3.8-27B-W4A16-AutoRound
    venv/bin/python prepare/quant_lm_head.py     $M
    venv/bin/python prepare/quant_embed.py       $M
    venv/bin/python prepare/quant_mtp.py         $M
    venv/bin/python prepare/build_draft_vocab.py $M --ids prepare/draft_vocab_ids.json
    venv/bin/python prepare/fetch_fast_variant.py
    venv/bin/python prepare/fetch_dflash2.py
    

    Шаг 5: применение стека патчей

    Директория patches/ содержит примерно пятнадцать файлов .patch, охватывающих настройки квантизации в процессе встраивания, механизм разделенного внимания KV для проверки черновиков, исправления ядер Marlin в формате int8, алгоритмы поиска DFlash2 и многое другое. Порядок этих файлов определен в файле patches/series. Приведенный ниже цикл удаляет комментарии и пустые строки из этого файла, а затем применяет каждый патч к пакету vLLM, находящемуся внутри среды venv. Он пропускает файл dflash2-backport.patch, существующий только для версий vLLM старше 0.28.0, когда DFlash2 еще не был встроен нативно.

    sed -e 's/#.*//' -e 's/^[[:space:]]*//;s/[[:space:]]*$//' -e '/^$/d' patches/series |
    while IFS= read -r name; do
      [ "$name" = "dflash2-backport.patch" ] && continue
      patch -p1 -d venv/lib/python3.12/site-packages/vllm < "patches/$name"
    done
    

    Если применение патча не удается, это почти всегда свидетельствует о несоответствии версий. Запустите команду venv/bin/pip show vllm и убедитесь, что в выводе указана ровно версия 0.28.0.

    Шаг 6: проверка установки

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

    openssl rand -hex 24 > api_key.txt
    bash verify.sh --no-server    # checks all patches applied + model shape correct
    

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

    Шаг 7: запуск сервера

    Вся настройка осуществляется с помощью переменных окружения. По умолчанию команда включает функции DFlash2 и кэширование префиксов на выбранной GPU; в комментарии объясняется, как переключиться на режим работы с длинным контекстом или на профиль объема 245 кб после выполнения команды kvarn/install.sh.

    CUDA_VISIBLE_DEVICES=0 SPEC=dflash2 PREFIX_CACHE=1 bash single-user/start_qwen.sh
    # add CTX=long for ~131k context (4 slots), or CTX=huge after kvarn/install.sh for 245k
    

    Всегда явно устанавливайте значение CUDA_VISIBLE_DEVICES. В противном случае vLLM склонен выбирать GPU с наибольшим количеством свободной памяти, что на машине с несколькими GPU может означать выбор не той карты, которую вы хотели использовать. Ключ-проводник считывается из файла api_key.txt или из переменной VLLM_API_KEY; установите его до того, как открыть порт для доступа извне localhost, поскольку без ключа сервер принимает непроверенные запросы. Остальные настройки берутся из файла .env. Через несколько минут после запуска появляется конечная точка, совместимая с OpenAI, которая обслуживает модель размером 27B на одной карте, стоимость которой меньше, чем у б/у велосипеда.

    Откуда берется скорость

    Запуск готовой версии vLLM с использованием квантизированных чекпоинтов тратит производительность в нескольких неочевидных местах. Документ с описанием оптимизаций проекта (docs/optimizations.md в репозитории) содержит девять изменений; четыре из них обеспечивают наибольшую прибавку к производительности.

    Квантизация эмбеддингов, которую все игнорируют

    Qwen3.8-27B использует нерелевантные эмбеддинги, то есть отдельные таблицы входных и выходных данных объемом по 2,5 ГБ каждая. Публичные «квантизированные» чекпоинты сохраняют обе таблицы в формате bf16, главным образом потому, что их квантизация затруднена. Скрипты подготовки преобразуют обе таблицы в формат int8, что позволяет освободить 2,6 ГБ VRAM без заметной потери качества. На карте с памятью 24 ГБ этого обычно достаточно для хранения контекста еще одного пользователя.

    Использование гибридной архитектуры

    Из 64 слоев модели только 16 являются традиционными слоями внимания, память которых увеличивается в зависимости от контекста. Оставшиеся 48 — это слои Gated DeltaNet, представляющие собой конструкцию на основе линейного внимания, у которой размер состояния на каждый диалог остается фиксированным, независимо от того, состоит ли диалог из 100 или 100 000 токенов. В версии stock vLLM это состояние хранилось в формате fp32, что требовало примерно 150 МБ на запрос, и модель не могла обрабатывать более 37 одновременных запросов, несмотря на установленный лимит в 64. В форке это состояние хранится в формате fp16, значение перплекситета остается неизменным с точностью до трех знаков после запятой, и все настроенные слоты становятся доступными для использования.

    DFlash2: формирование семи токенов за один проход

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

    Встроенный механизм MTP у Qwen подряд выполняет четыре предположения. Вместо него используется DFlash2 — пятиуровневый алгоритм генерации, который за один неавторегрессивный проход предсказывает целый блок из семи токенов, опираясь на скрытые состояния из пяти разных глубин целевой модели. Сам алгоритм был квантизирован с версии GPTQ с 3,85 ГБ до 1,19 ГБ, благодаря чему он может использовать ту же память без сильной конкуренции за пропускную способность. В результате на каждом шаге генерируется примерно три токена вместо одного. Поскольку стандартная спекулятивная декодировка принимает или отклоняет токены-проекты так, чтобы итоговое распределение выходных данных полностью соответствовало целевой модели, ускорение происходит без потерь качества; точность GSM8K остается на уровне от 96 до 96,5% во всех конфигурациях, указанных в репозитории.

    Словарь проектных токенов, сформированный на основе собственных выходов модели

    Создатель может предлагать только те токены, которые существуют в его сокращенном словаре вывода; всё, что находится за его пределами, по определению отклоняется. Исходный словарь был составлен на основе текстов из интернета и охватывал 92% токенов, которые фактически генерирует этот модель. Администраторы собрали 5,4 миллиона токенов из собственных выходных данных модели и воссоздали словарь на основе этих данных, достигнув покрытия в 97,5%. Уже одно это изменение увеличило производительность примерно на 10%, при этом не требовалось новое оборудование и никаких изменений в самой модели.

    Поиск токенов для текста, который цитирует модель

    Ещё один метод объясняет самые высокие показатели. Когда результат включает материал, уже присутствующий в запросе — например, исходный код, находящийся в процессе редактирования, или вставленный документ — этот метод обходит механизм формирования ответа и предлагает токены непосредственно из контекста. Воспроизведение документа объёмом 25 тыс. токенов позволяет достичь скорости 381 ток/с на устройстве-тестере. Агенты, занимающиеся программированием, тратят большую часть времени на воспроизведение кода, появившегося немного ранее в запросе — это идеальный случай для применения этого метода, и именно поэтому показатели эффективности агентов бывают такими высокими.

    Почему удвоение объёма контекста не приводит к исчерпанию VRAM

    Запускатель для одного пользователя по умолчанию использует объём контекста 65 тыс. единиц. Переключение на параметр CTX=long удваивает этот объём до 131 тыс., и казалось бы, следовало ожидать ошибки нехватки памяти на карте объёмом 24 ГБ. Однако сервер запускается нормально, просто с небольшой задержкой. Несколько дизайнерских решений объясняют это явление.

    • Веса имеют фиксированный размер. При квантизации W4A16 объем модели составляет примерно 15 ГБ, независимо от длины контекста.
    • Пул KV выделяется один раз, в байтах. Перед обработкой любого запроса форк выделяет фиксированный объем памяти — примерно 5,2 ГиБ в данном случае, — а vLLM фиксирует этот результат, например: «Размер кэша KV GPU: 136,429 токенов». Поскольку пул выделяется при запуске, либо он вмещает все данные, либо сервер отказывается запускаться. Не существует выделения памяти на каждый запрос, которое могло бы сорваться на середине выполнения задачи агента.
  • Режим long использует более дешевые токены, а не больше памяти. По умолчанию кэши внимания хранятся в формате bf16, тогда как при настройке CTX=long они сохраняются в формате int8, что примерно вдвое снижает стоимость обработки одного токена. Таким образом, на тех же 5,2 ГБ теперь помещается 136 429 токенов вместо 68 605, что вдвое увеличивает максимальный объем контекста до 131 тыс. Для одинакового отрывка показатель перплекситета, определяемый методом Teacher-forced, отличается всего на 0,2% между этими двумя режимами.
  • Большинство слоев не увеличиваются по мере роста объема контекста. Только 16 слоев внимания масштабируются с увеличением длины последовательности; 48 слоев DeltaNet сохраняют свое фиксированное состояние. Поэтому использование длинного контекста здесь значительно экономичнее, чем в чистых трансформерных моделях, и это во многом объясняет возможность размещения всей модели на одной видеокарте.
  • Почему лимит составляет 131 072, а не 136 429

    Не вся память буфера может быть выделена кэшу запросов. Каждый запрос также требует своего состояния DeltaNet фиксированного размера, а DFlash2 добавляет ещё восемь слотов для спекулятивных состояний на каждый запрос. Поскольку в режиме длинного профиля доступно четыре слота, запускающий модуль устанавливает максимальный объём контекста в 131 072 единицы, что примерно на 4% меньше объёма всего буфера, оставляя остаток для этих страниц состояний и для выравнивания блоков. Именно этот запас обеспечивает выполнение обещания отсутствия проблем с нехваткой памяти: при запуске проверяется самый сложный сценарий — один запрос максимальной длины при одновременном использовании всех оставшихся слотов.

    Что приходится жертвовать взамен

    Для более длинного контекста оплачивается скорость, а не количество сбоев. Токены хранятся в формате int8, и каждый запрос занимает страницы состояния из пула, теперь разделенного между меньшим количеством устройств. Количество одновременных операций сокращается с 8 до 4, а скорость декодирования падает примерно с 177 до 122 токенов в секунду. Карта обрабатывает больше данных при том же объеме памяти и взимает плату за пропускную способность, а не за количество исключений.

    В чем она уступает: глубокий контекст одного запроса

    Модель работает наилучшим образом с короткими и средними контекстами, которые обычно используются агентами. Однако запрос объемом около 100 тыс. токенов ведет себя иначе. На карте 3090 скорость декодирования одного запроса составляла примерно 107 токенов в секунду при коротком промпте, 78 токенов в секунду при объеме примерно 10 тыс. токенов и 38 токенов в секунду при объеме примерно 43 тыс. токенов; ближе к 100 тыс. токенам скорость снижалась до примерно 31 токена в секунду. Причиной является уровень принятия предложений моделью, который снижается по мере увеличения глубины контекста. В репозитории наблюдается аналогичный эффект: уровень принятия остается около 0,29 независимо от типа кэша, поэтому это свойство самой модели и глубины контекста, а не нерешенный баг.

    Для сравнения, форк на основе llama.cpp на аналогичной карте показывает стабильную скорость 65–80 токов в секунду при объеме контекста 150 тыс. элементов. В нем нет механизма генерации предположений, качество которых снижается со временем, и нет блока проверки, прерывающего работу, поэтому он никогда не бывает особенно быстрым, но и не медленным. В таблице ниже эти два варианта приведены рядом; обратите внимание, что в диапазоне короткого контекста vLLM суммируются показатели для одного запроса и для агента с несколькими слотами.

    | Context depth   | vLLM fork (DFlash2) | llama.cpp ATX fork |
    |-----------------|---------------------|--------------------|
    | short (<4k)     | 107–177 tok/s       | 65–80 tok/s        |
    | ~10k            | ~78 tok/s           | 65–80 tok/s        |
    | ~43k            | ~38 tok/s           | 65–80 tok/s        |
    | ~100k           | ~31 tok/s           | 65–80 tok/s        |
    

    Практическое правило вытекает из этого напрямую. Если ваша работа сводится к медленному чтению одного очень длинного документа, llama.cpp — более стабильный выбор; для ознакомления с аспектами этого компромисса прочитайте нашу статью о запуске модели Qwen3.8 MoE на картах RTX 3090 с использованием технологии откладывания вычислений llama.cpp. Если же ваша работа включает множество средне длинных кодинговых разговоров, форк vLLM значительно превосходит его.

    Почему это подходит для агентских харнесов

    Харнесы вроде Pi, Hermes или DeepSeek Harness не обрабатывают один диалог. Благодаря сабагентам они одновременно генерируют множество параллельных потоков — обычно от пяти до двенадцати, каждый из которых имеет среднюю длину; большинство из них используют один и тот же системный промпт и контекст кодовой базы. Именно такая нагрузка была учтена при настройке этой версии:

    • Общая пропускная способность растет с количеством одновременных операций. Четыре одновременные передачи данных обеспечивали совокупную скорость более 300 токов в секунду на одной карте 3090. Стандартные тесты из репозитория показывают скорость от 279 до 335 токов в секунду при четырех одновременных запросах, а с использованием MTP — до примерно 400 токов в секунду при восьми запросах.
  • Кэширование префиксов делает использование общего контекста практически бесплатным. При настройке PREFIX_CACHE=1 64 запроса, использующих общий системный промпт длиной 5,8 токенов, обрабатываются за 17 секунд вместо 222 секунд в тестах репозитория, причем среднее время отклика снижается с 95 с до 8 секунд. После первого запроса сабагенты практически не тратят ресурсов на обработку общих инструкций. В этой гибридной модели кэш также хранит состояние DeltaNet, а не только параметры внимания KV, поэтому обработка следующего запроса к документу длиной 24 токена занимает около 1 секунды вместо 23.
  • Метод подбора вариантов текста соответствует результатам работы агента. Функции переработки, переписывания и редактирования постоянно цитируют входные данные, из-за чего производительность системы достигает пика в 380+ токенов в секунду.
  • Существует определённый лимит. После примерно четырёх потоков обработки длинных контекстов вы ограничены способом разделения ресурсов пула, а не мощностью вычислений. В документации прямо указано, что восемь одновременных запросов на обработку длинных контекстов работают значительно хуже, чем четыре, и это описывается как «не компромисс, а потеря». Оптимальный результат достигается при использовании примерно четырёх параллельных процессоров средней глубины обработки, что позволяет максимально использовать возможности видеокарты. Пример того, что можно создать на локальной установке Qwen3.8-27B на практике, смотрите в статье о создании локальной копии игры Angry Birds с использованием Qwen3.8-27B и Pi.

    Основные выводы

    • Скорость обеспечивается программным обеспечением: реквантизированные эмбеддинги, состояние модели в формате fp16 DeltaNet, механизм DFlash2 на семь токенов и словарь, адаптированный под реальные выходы модели. Сама видеокарта при этом остаётся без изменений.
  • Закрепите все версии, которые закреплены в репозитории, установите соответствующие заголовки и запустите verify.sh, прежде чем доверять любым полученным результатам тестирования.
  • Пул KV, выделенный при запуске, превращает ошибки нехватки памяти в решение, принимаемое на этапе загрузки, а режим с глубоким профилем обеспечивает более полную информацию за счёт использования кэшей типа int8, что сопряжено с потерей количества слотов и ускорения.
  • Эффективность спекулятивного декодирования снижается с увеличением глубины контекста, поэтому для одиночных запросов с объёмом, значительно превышающим 40 тысяч токенов, настройка llama.cpp может оказаться более подходящей.
  • Ограничьте количество одновременно работающих агентов примерно четырьмя рабочими процессами средней глубины с включённым кэшированием префиксов, и всегда указывайте пропускную способность вместе с нагрузкой, которая её породила.
  • Для получения более подробной информации в папке docs/reproductions репозитория имеются инструкции по пошаговой реконструкции процесса без использования Docker на устройстве 3090.