Можно ли запустить современную 27-миллиардную модель и полноценного автономного агента на паре серверных ускорителей 2017 года, установленных в обычный десктоп через переходники? Короткий ответ — да, но с оговорками, которые важно знать заранее.
В этом материале я разбираю практический кейс: развёртывание Qwen3.6-27B на двух Tesla V100-SXM2-16GB под управлением автономного агента Hermes от Nous Research. Карты подключены к потребительской платформе через адаптеры SXM2→PCIe — конфигурация, которую несложно собрать дома, но которая накладывает жёсткие ограничения на доступную видеопамять и межкарточную пропускную способность.
По итогам эксперимента эту связку можно считать нижней границей практической применимости для локального запуска Hermes: всё работает, но ровно на пределе возможностей железа. Ниже — последовательный разбор всех подводных камней, рабочие конфигурации с готовыми командами и честный вывод о том, где проходит та самая стена, которую не обойти настройками.
Железо и цель
— Сервер: Proxmox, проброс (PCIe passthrough) двух карт в одну VM.
— GPU: 2× Tesla V100-SXM2-16GB через переходники SXM2→PCIe. CPU — Intel 6700k.
— Важная деталь: NVLink между картами нет (переходники выводят только PCIe-линии), и 6700k даёт всего 16 линий PCIe 3.0 → карты работают в режиме x8/x8.
— Цель: запустить Qwen3.6-27B-AWQ и подключить агента Hermes от Nous Research, которому нужно минимум 65 000 токенов контекста.
Проверить топологию и режим линий можно так (внутри VM, после установки драйвера):
nvidia-smi topo -m # между GPU0/GPU1 ждём NV*, а получили PHB = NVLink нетnvidia-smi -q | grep -A2 "Link Width" # Current: 8x = потолок межкарточного обмена
Грабля №1: «карты грузятся на 50%»
Классическая жалоба: при работе двух карт каждая загружена примерно наполовину. Причина — llama.cpp и подобные движки по умолчанию делят модель по слоям (pipeline/layer split): пока считает GPU0, GPU1 ждёт. Среднее — 50%.
Лечится переходом на tensor parallelism, где модель режется «поперёк» и обе карты считают каждый токен одновременно. В vLLM это флаг --tensor-parallel-size 2. Именно он даёт обеим картам реальные ~100% загрузки.
Грабля №2: новый vLLM не поддерживает Volta
Qwen3.6 требует vllm>=0.19.0, а свежий vLLM уже не поддерживает архитектуру Volta (sm_70) — падает при старте. Вдобавок AWQ-ядра (Marlin) требуют sm_80+. Решение — community-форк 1Cat-vLLM, который возвращает SM70-ядра внимания, AWQ под Volta и поддержку Qwen3.5/3.6.
Почему именно 1Cat-vLLM, а не другой движок
Здесь сходятся сразу несколько требований, и закрыть их все может только этот форк:
— Стоковый vLLM новых версий выкинул поддержку sm_70 — на V100 не стартует в принципе.
— Старый vLLM, который ещё поддерживал Volta, не знает архитектуру Qwen3.5/3.6 (Gated DeltaNet + MTP) — упадёт на «unknown architecture». Получается вилка: новый движок знает модель, но не знает железо; старый знает железо, но не знает модель.
— llama.cpp / GGUF заводится на V100, но Qwen3.6 в GGUF на момент экспериментов корректно не собиралась под этот гибрид, и tensor-parallelism там слабее.
— SGLang, TGI и прочие официально требуют sm_75+ для современных моделей.
1Cat-vLLM — единственный из доступных, кто одновременно закрывает обе стороны вилки: возвращает sm_70-ядра (TurboMind SM70 WMMA для AWQ) и содержит код под Qwen3.5/3.6 с MTP и mamba/GDN-слоями. Плюс он валидирован авторами именно на multi-GPU V100 (их бенчи — на 4×V100-16GB), то есть это не теоретическая совместимость, а проверенная на нашем же классе железа.
Установка — из готовых колёс (НЕ из исходников, это для разработчиков ядер):
# скачать оба.whl из релизаmkdir ‑p ~/wheels && cd ~/wheelscurl ‑s https://api.github.com/repos/1CatAI/1Cat‑vLLM/releases/latest \| grep browser_download_url | cut ‑d '“' ‑f4 | xargs ‑n1 wget”# поставить в conda‑средеpython ‑m pip install ‑prefer‑binary ‑no‑cache‑dir \‑extra‑index‑url https://download.pytorch.org/whl/cu128 \/flash_attn_v100-*.whl./vllm‑*.whl
Колёса тянут torch под CUDA 12.8 — это совместимо с рантайм-драйвером 580/CUDA 13, доустанавливать toolkit не нужно.
Почему именно AWQ, а не обычный 4-битный GPTQ
Это не вопрос вкуса — формат квантизации диктует само железо. На Volta (sm_70) большинство современных 4-битных схем просто не запускается:
— GPTQ-Int4 через Marlin-ядра требует sm_80+ (Ampere и новее). На V100 эти ядра не компилируются и не исполняются — стандартный «быстрый» путь GPTQ для нас закрыт.
— FP8-вычисления — это вообще Hopper (sm_90). На Volta из FP8 доступен только формат e5m2 для KV-кэша, и то с оговорками.
— GPTQ-Int8 заводится, но 8 бит на вес означают вдвое больший размер: 27B-модель в Int8 весит ~50+ ГБ и не влезает даже близко в 32 ГБ суммарной VRAM.
Остаётся AWQ 4-bit — и именно его «оживляет» форк 1Cat-vLLM: он интегрирует TurboMind SM70 WMMA-ядра и расширяет AWQ-слои vLLM так, чтобы 4-битный AWQ исполнялся на Volta. По сути это единственный 4-битный формат, который реально работает на V100.
Бонусом AWQ-4bit ужимает 27B до ~21 ГБ — только в таком виде модель вообще помещается в 2×16 ГБ. Поэтому весь поиск моделей шёл по простому правилу: Volta → только AWQ-4bit через 1Cat-форк → ищем AWQ-сборки нужных моделей (например, от QuantTrio).
Грабли по мелочи (на которых легко застрять)
— Мало RAM у VM. vLLM по умолчанию резервирует 4 ГБ swap на карту. Если у VM всего 8 ГБ RAM — падает с «Too large swap space». Дайте VM 24+ ГБ.
— fp8e4nv not supported. Volta умеет только FP8-формат e5m2. Поэтому KV-кэш в FP8 включается так: --kv-cache-dtype fp8_e5m2 (не просто fp8).
— No valid cudagraph sizes (кратность 5). Когда включён встроенный MTP (num_speculative_tokens=4), CUDA-графы должны захватываться размерами кратными 5. Ставьте --compilation-config '{"cudagraph_mode":"full_and_piecewise","cudagraph_capture_sizes":[5]}' или отключите MTP.
— Tool calling. Hermes шлёт tool_choice: auto, поэтому сервер надо поднимать с --enable-auto-tool-choice --tool-call-parser qwen3_coder --reasoning-parser qwen3.
Архитектурный сюрприз: почему 65k вообще влезают
Qwen3.6-27B — гибрид. Из 64 слоёв только 16 имеют обычное внимание с растущим KV-кэшем, остальные 48 — Gated DeltaNet (линейное внимание), у которого кэш не растёт с длиной контекста. Поэтому память под длинный контекст у неё в разы меньше, чем у обычной dense-модели, и 65k в принципе достижимы даже на 32 ГБ суммарной VRAM.
Что работает на 2×V100-16GB
После всех граблей мы получили рабочую конфигурацию: vLLM поднимается, отвечает по сети, Hermes ходит, tool-calls проходят, контекст 65k. Цена — отключённый prefix caching (об этом ниже).
CUDA_VISIBLE_DEVICES=0,1 \VLLM_DISABLE_PYNCCL=1 \VLLM_1CAT_DISABLE_QWEN35_MTP_DEFAULTS=1 \python -m vllm.entrypoints.openai.api_server \ --model ~/models/Qwen3.6-27B-AWQ \ --served-model-name qwen36 \ --tensor-parallel-size 2 \ --dtype float16 \ --kv-cache-dtype fp8_e5m2 \ --gpu-memory-utilization 0.92 \ --max-model-len 65536 \ --max-num-seqs 1 \ --max-num-batched-tokens 512 \ --trust-remote-code \ --attention-backend TRITON_ATTN \ --disable-custom-all-reduce \ --skip-mm-profiling \ --limit-mm-per-prompt '{"image":0,"video":0}' \ --enable-auto-tool-choice \ --tool-call-parser qwen3_coder \ --reasoning-parser qwen3 \ --compilation-config '{"cudagraph_mode":"full_and_piecewise","cudagraph_capture_sizes":[1]}' \ --host 0.0.0.0 --port 8000
Проверка контекста и теста:
curl -s http://127.0.0.1:8000/v1/models | python3 -m json.tool # max_model_lencurl http://127.0.0.1:8000/v1/chat/completions -H 'Content-Type: application/json' \ -d '{"model":"qwen36","messages":[{"role":"user","content":"Привет!"}],"max_tokens":100}'
Реальные показатели: декод ~45 ток/с, обе карты под нагрузкой. Минус — каждый ход агент заново обрабатывает весь промпт (медленный prefill), потому что кэш отключён.
Где стена: 65k + prefix caching одновременно не выходит
Логичный шаг — включить prefix caching, чтобы статичный системный промпт + 60 инструментов Hermes не пересчитывались каждый ход. Но на 2 картах это не работает, и вот почему.
Prefix caching на этой гибридной модели функционирует только в паре с --mamba-cache-mode align. А align-режим добавляет память под выровненный кэш Gated DeltaNet. В сумме «веса 21 ГБ + 65k KV + align-буферы + временные буферы GDN-ядра» не помещаются в 32 ГБ. Сервер стартует (проверка KV проходит), но падает на первом же запросе в ядре chunk_gated_delta_rule:
RuntimeError: Triton Error [CUDA]: out of memory
Мы проверили это при gpu-memory-utilization 0.95 и 0.88, с разным контекстом — результат один. На 2×16GB честно невозможно иметь одновременно 65k контекста и работающий prefix cache. Три доступных режима:
|
Режим |
65k? |
Prefix cache? |
Итог |
|
65k без кэша (fp8, без align/MTP) |
да |
нет |
работает, но медленный prefill |
|
Кэш + align, контекст <65k |
нет |
да |
Hermes не стартует (нужен минимум 64k) |
|
65k + align |
стартует |
да |
падает в рантайме (OOM в GDN) |
Развилка и решения
Вариант А — жить с тем, что есть. Qwen3.6-27B на 65k без кэша. Полностью рабочий агент, просто первый токен каждого хода идёт через полный prefill (на x8 PCIe это ощутимо).
Вариант Б — взять модель поменьше. Память под кэш освобождает только меньшее число параметров (MoE-модели с A3B весят как полная модель — для памяти не помогают). Отличный кандидат — Qwen3.5-9B-AWQ (~6 ГБ): влезает с огромным запасом, и 65k + prefix cache + MTP реально заработают. Цена — качество 9B вместо 27B.
CUDA_VISIBLE_DEVICES=0,1 VLLM_DISABLE_PYNCCL=1 \python -m vllm.entrypoints.openai.api_server \ --model ~/models/Qwen3.5-9B-AWQ --served-model-name qwen35-9b \ --tensor-parallel-size 2 --dtype float16 \ --gpu-memory-utilization 0.90 --max-model-len 65536 \ --enable-prefix-caching \ --trust-remote-code --attention-backend TRITON_ATTN --disable-custom-all-reduce \ --skip-mm-profiling --limit-mm-per-prompt '{"image":0,"video":0}' \ --enable-auto-tool-choice --tool-call-parser qwen3_coder --reasoning-parser qwen3 \ --host 0.0.0.0 --port 8000
Вариант В — 3-я карта. С pipeline-параллелизмом (--pipeline-parallel-size 3 --tensor-parallel-size 1) веса 21 ГБ размазываются по ~7 ГБ на карту, освобождая память под всё сразу: 65k + prefix cache + MTP. Это единственный путь получить «27B + быстрый агент». Нюанс: --tensor-parallel-size 3 для этой модели невалиден (4 KV-головы не делятся на 3), поэтому именно pipeline.
Выводы
1. Современные LLM на старых V100 реально запускаются — спасибо community-форку 1Cat-vLLM и гибридной архитектуре Qwen3.6.
2. Tensor parallelism (--tensor-parallel-size 2) лечит «50% загрузки».
3. На 2×16GB без NVLink есть жёсткая стена: 65k контекста и prefix caching одновременно не помещаются. Это ограничение памяти, а не настроек.
4. Практический выбор: 27B медленно (без кэша), 9B быстро (с кэшем), или 3-я карта — и тогда 27B быстро.
Если ваша задача — фоновый агент в мессенджере, медленный prefill терпим. Если нужен интерактив «как ChatGPT» — берите модель поменьше или добавляйте карту. Железо честно диктует правила.
Конфигурация на момент написания: Proxmox + Ubuntu 22.04/24.04 в VM, 2× Tesla V100-SXM2-16GB (sm_70, x8 PCIe, без NVLink), драйвер 580 / CUDA 13, 1Cat-vLLM 1.1.0, Qwen3.6-27B-AWQ, Hermes Agent.
ссылка на оригинал статьи https://habr.com/ru/articles/1043956/