Ещё недавно «запустить LLM у себя» почти всегда означало одно: discrete GPU с парой десятков гигабайт VRAM. AMD Strix Halo с 128 ГБ унифицированной памяти эту привычку ломает — крупные MoE-модели на нём заводятся спокойно, если inference-движок умеет работать с общей памятью, memory mapping и своеобразием встроенной графики.
Ниже — практическая настройка Qwen3.8-Flash-Next на Fedora 43 Server через HALOGEN: OpenAI-совместимый API, ключ, четыре параллельные сессии и доступ снаружи через порт 9091.
Что за зверь Qwen3.8-Flash-Next
Это не «обычная» модель даже по меркам MoE. Внутри — смесь экспертов (MoE), гибридное внимание и отдельные N-gram embeddings. Если коротко:
|
Параметр |
Значение |
|---|---|
|
Основная модель |
125 млрд параметров |
|
Активируется на токен |
около 6 млрд параметров |
|
N-gram embedding table |
около 51 млрд параметров |
|
MTP-head |
около 4 млрд параметров |
|
Количество слоёв |
48 |
|
MoE-экспертов |
512 routed + 1 shared |
|
Активных routed-экспертов |
10 |
|
Нативный контекст |
262 144 токена |
|
Максимальный расширенный контекст |
до 1 000 000 токенов |
|
Возможности |
текст и опционально изображения |
В чём фокус MoE: суммарная ёмкость модели огромная, но на каждом токене она считает лишь малую часть весов. Поэтому и получается скорость выше, чем у плотной модели такого же полного размера.
Почему HALOGEN, а не llama.cpp
У Strix Halo unified memory architecture: CPU и встроенный GPU делят одну LPDDR5X-память. Отдельной физической VRAM, как у дискретных NVIDIA или Radeon, здесь просто нет.
HALOGEN рассчитан именно на такое устройство:
-
заточен под GPU gfx1151;
-
хранит веса в собственном формате
.hgn; -
не пытается копировать весь комплект весов в «VRAM»;
-
держит N-gram lookup table через memory mapping;
-
ускоряет генерацию с помощью MTP/speculative decoding;
-
отдаёт наружу OpenAI-совместимый HTTP API.
Это не универсальная замена llama.cpp или vLLM — все его преимущества вытекают из узкой заточки под одну архитектуру GPU и одну линейку моделей.
И сразу важный момент про BIOS: параметр UMA Frame Buffer выставляйте в минимальное фиксированное значение, а не оставляйте Auto. HALOGEN нужен доступ к обычной памяти хоста, а большой статический резерв под iGPU только съедает доступную RAM.
Сколько места нужно на диске
Стандартный набор весов HALOGEN выглядит так:
|
Файл |
Размер |
Назначение |
|---|---|---|
|
qwen38-flash-next-v2.hgn |
62,1 GiB |
Основной checkpoint |
|
qwen38-flash-next-ngram.hgn |
47,7 GiB |
N-gram lookup table |
|
tokenizer/ |
небольшой |
Токенизатор |
|
Всего |
около 110 GiB |
Текстовая модель |
|
qwen38-flash-next-vision.hgn |
0,84 GiB |
Опциональная поддержка изображений |
|
qwen38-flash-next-mtp.hgn |
1,42 GiB |
Draft-head для стороннего GGUF |
При первом запуске HALOGEN сам скачает нужные файлы, если передать ему:
-e HALOGEN_DOWNLOAD=peonist-ai/halogen-qwen3.8-flash-next
Свободного места закладывайте не меньше 120–140 ГБ: помимо самих весов понадобятся служебные файлы и запас под обновления.
Какую скорость ждать
По опубликованным результатам HALOGEN на Strix Halo ориентиры такие:
|
Сценарий |
Производительность |
|---|---|
|
Генерация текста |
около 54 токенов/с |
|
Благоприятный сценарий speculative decoding |
до 94 токенов/с |
|
Генерация при редактировании кода |
до 81 токена/с |
|
Генерация tool calls |
около 71 токена/с |
|
Prefill: промпт 8K токенов |
около 1 821 токена/с |
|
Prefill: промпт 32K токенов |
около 1 740 токенов/с |
|
Prefill: промпт 131K токенов |
около 1 675 токенов/с |
Что это значит на практике? Новый документ на 32K токенов обработается примерно за 19 секунд. Уже закэшированная история диалога продолжится заметно быстрее. Ответ на 1 000 токенов при 54 токенах/с будет крутиться секунд 18–19. А реальная скорость, конечно, зависит от текста, длины контекста, температуры, speculative decoding и того, что ещё грузит машину параллельно.
При четырёх одновременных сессиях HALOGEN просто делит вычислительный ресурс между потоками. Ориентир из документации: примерно 76 токенов/с суммарно и 11–19 токенов/с на поток. Так что четыре слота полезны для API-сервера с несколькими клиентами, но единичный запрос они не ускоряют.
Синтетические тесты: проверяем на живом сервере
Цифры из readme — это хорошо, но интереснее погонять бенчмарк по реальному эндпоинту. Подошёл LLMPerf от ray-project: он собирает промпты из случайных кусков Шекспира и меряет по каждому запросу время до первого токена (TTFT) и интервалы между токенами (ITL) — из них легко получить скорость чтения и записи.
По ходу дела выяснились две грабли, о которых стоит знать заранее:
-
SSE-парсер llmperf пришлось патчить. На длинных контекстах при c=4 стрим молчит достаточно долго, и прокси начинает слать keep-alive (
:ping), от которых наивный парсер падает. Лечится просто: игнорировать комментарии, разбирать только строкиdata:. -
Модель — reasoning-модель. Она «размышляет» перед ответом (поле
reasoning_content), и эти паузы искажают метрики: на 128k свободная генерация показывала жалкие 2.6 ток/с записи. Отключается штатным для Qwen3 параметромchat_template_kwargs: {"enable_thinking": false}, а чтобы модель не останавливалась по EOS после пары сотен токенов, добавлялиignore_eos: true.
Финальная серия — reasoning OFF, один поток, выход = 1/10 контекста, 12 запросов без единой ошибки:
|
Контекст |
Выход (факт) |
TTFT p50 |
Чтение |
Запись |
E2E p50 |
|---|---|---|---|---|---|
|
8k |
888 |
4.2 с |
1 965 ток/с |
96.4 ток/с |
13.3 с |
|
16k |
1 775 |
8.1 с |
2 040 ток/с |
98.1 ток/с |
26.6 с |
|
32k |
3 571 |
16.1 с |
2 048 ток/с |
96.5 ток/с |
53.4 с |
|
64k |
7 203 |
32.3 с |
2 035 ток/с |
96.5 ток/с |
121 с |
|
128k |
14 518 |
66.0 с |
1 992 ток/с |
94.5 ток/с |
230 с |
Что из этого следует:
-
Запись — константа ~95–98 ток/с на всём диапазоне контекстов. «Деградации от длины контекста» не существует — её имитировали паузы размышлений (разница до 36×). И обещанные до 94 токенов/с в благоприятном сценарии — не маркетинг: форсированный стрим стабильно выдаёт ~96.
-
Чтение — линейное, ~2 000 ток/с. TTFT растёт с контекстом (4.2 с на 8k → 66 с на 128k), и именно чтение здесь узкое место.
-
Параллелизм ведёт себя как заявлено. Короткие контексты при c=4 дают максимум суммарного throughput (+27% к одиночному потоку), но батчинг замедляет каждый запрос по TTFT в 2–5 раз, а c=16 сервер уже не переваривает. Длинные одиночные запросы выгоднее слать по одному.
-
Для агентского сценария (прочитать контекст + ответ ~150 токенов) шаг целиком занимает ~6 с при 8k, ~18 с при 32k и ~68 с при 128k — комфортный рабочий контекст где-то до 32k.
А если оставить reasoning включённым?
Для полноты картины ту же матрицу прогнали и с включёнными размышлениями. Картинка получается занятная:
|
Метрика |
Reasoning ON |
Reasoning OFF |
|---|---|---|
|
Запись @ 8k, форсированный вывод |
~90–99 ток/с |
96.4 ток/с |
|
Запись @ 8k, свободный вывод |
26.6 ток/с |
— |
|
Запись @ 128k, свободный вывод |
2.6 ток/с |
94.5 ток/с |
|
TTFT до контента на тривиальном вопросе |
6.76 с |
0.18–0.35 с |
Тонкость в том, что метрики здесь искажает сам способ измерения. TTFT отсчитывается до первого контентного токена, то есть включает все размышления целиком. А между контентными токенами вклиниваются паузы «подумать» — на 128k интервал доходит до 378 мс, что и выглядело как деградация до 2.6 ток/с. При форсированном выводе, когда паузы вымываются сплошным стримом, скорость записи почти не отличается от reasoning OFF (~90–99 против 96.4 ток/с): токены генерируются так же быстро — модель просто думает между ними.
Практический вывод: нужен быстрый и предсказуемый стрим — отключайте thinking. Если качество важнее latency — оставляйте, но помните, что свободная генерация с reasoning останавливается по EOS уже на 85–365 токенах, так что «честную» скорость записи вы в этом режиме всё равно не увидите.
И приятный бонус: за всё исследование — 150+ запросов, и после патча парсера ни одной ошибки и ни одного таймаута.
Готовим Fedora 43 Server
Ставим Podman и базовые утилиты:
sudo dnf upgrade --refresh -ysudo dnf install -y podman curl pciutilssudo reboot
После перезагрузки проверяем драйвер и GPU-устройства:
lspci -nnk | grep -A 4 -Ei 'VGA|Display|3D'ls -l /dev/kfd /dev/dri/renderD*free -h
Для работы с GPU пользователю обычно нужны группы render и video:
sudo usermod -aG render,video "$USER"
Дальше — важная мелочь, о которой часто забывают: полностью завершите SSH-сеанс и подключитесь заново, иначе новые группы не подхватятся.
Создаём API-ключ
HALOGEN умеет защищать API через переменную HALOGEN_API_KEY. Клиент передаёт её стандартным заголовком:
Authorization: Bearer ВАШ_КЛЮЧ
Создадим файл окружения с правами доступа только для текущего пользователя:
mkdir -p "$HOME/.config/halogen" "$HOME/halogen-models"chmod 700 "$HOME/.config/halogen"( umask 077 if [ ! -f "$HOME/.config/halogen/server.env" ]; then printf 'HALOGEN_API_KEY=%s\n' \ "$(head -c 32 /dev/urandom | od -An -tx1 | tr -d ' \n')" \ > "$HOME/.config/halogen/server.env" fi)chmod 600 "$HOME/.config/halogen/server.env"
Посмотреть ключ можно так:
cat "$HOME/.config/halogen/server.env"
И банальное, но необходимое: не добавляйте этот файл в Git, не пересылайте в мессенджерах и не держите в публичных конфигурациях.
Запускаем HALOGEN с четырьмя параллельными сессиями
HALOGEN слушает порт 8731 внутри контейнера. Если внешний API должен быть доступен через 9091, порт-маппинг выглядит так: 9091 на хосте → 8731 в контейнере.
Команда запуска:
podman run -d \ --name halogen \ -p 0.0.0.0:9091:8731 \ --device /dev/kfd \ --device /dev/dri \ --group-add keep-groups \ --security-opt label=disable \ --ipc=host \ --ulimit memlock=-1:-1 \ --env-file "$HOME/.config/halogen/server.env" \ -e HALOGEN_KV_SLOTS=4 \ -e HALOGEN_DOWNLOAD=peonist-ai/halogen-qwen3.8-flash-next \ -v "$HOME/halogen-models:/models" \ ghcr.io/peonist-ai/halogen-flash-server:0.18.5
Что здесь отвечает за что
|
Параметр |
Назначение |
|---|---|
|
|
Публикует API наружу на порту 9091 |
|
|
Доступ к AMD Compute Runtime |
|
|
Доступ к DRM/GPU |
|
|
Передаёт контейнеру права групп пользователя |
|
|
Обход ограничений SELinux-разметки для GPU-доступа |
|
|
Общий IPC namespace, как рекомендует quickstart-конфигурация |
|
|
Снимает лимит блокируемой памяти |
|
|
До четырёх одновременно генерирующих диалогов |
|
|
Автоматическая загрузка весов при первом старте |
|
|
Подключает API-ключ, не светя им в командной строке |
Посмотреть ход загрузки и инициализации модели:
podman logs -f halogen
И завершающий штрих — на мой взгляд, обязательная настройка. Разрешите пользователю работать в фоне, иначе при закрытии SSH-консоли сервер просто выключится:
sudo loginctl enable-linger "$USER"
Почему nvtop показывает всего ~27 ГБ «видеопамяти»
На Strix Halo показания nvtop регулярно вызывают вопросы. Модель занимает около 110 ГиБ на SSD, основной checkpoint требует примерно 62 ГиБ резидентной памяти — а nvtop показывает какие-то ~27 ГБ GPU memory.
Это нормально, и вот почему.
Отдельной физической VRAM у Strix Halo нет: iGPU использует RAM хоста, и HALOGEN не обязан отображать весь объём модели как классическую GPU VRAM. Память распределяется примерно так:
-
основные веса живут в резидентной памяти и занимают около 62 ГиБ;
-
N-gram table на 47,7 ГиБ подключена через mmap — Linux подтягивает её страницы по мере необходимости и греет их в page cache.
В nvtop при этом обычно хорошо видны буферы GPU, рабочие области вычислений, KV-cache и часть GPU memory mapping. При HALOGEN_KV_SLOTS=4 заметную долю тех самых ~27 ГБ съедает общий KV-pool и состояние слотов.
Так что цифра в nvtop не означает, что модель загрузилась «только на 27 ГБ» или работает не в полную силу.
Расширяем контекст до миллиона токенов через YaRN
Нативный контекст модели — 262 144 токена, но это не потолок. HALOGEN умеет растягивать позиционный контекст через YaRN, и задаётся это двумя переменными окружения:
-e HALOGEN_ROPE_YARN=4 \-e HALOGEN_CTX=1048576 \
В такой конфигурации максимальная длина контекста вырастает с 262 144 до 1 048 576 токенов. Важно: настройки читаются при запуске, поэтому контейнер нужно пересоздавать, а не просто перезапускать.
Сколько это съедает на практике? Живой замер при миллионном контексте и одном слоте: HALOGEN занимает 36,7 ГиБ по данным nvtop и 38,9 ГиБ по htop (для сравнения — около 27 ГиБ в nvtop на нативном контексте с четырьмя слотами). То есть сам по себе миллион запускается вполне уютно. Но «запускается» и «работает как станция» — вещи разные: если машина нужна именно как полноценная станция с миллионным контекстом, закладывайте порядка 96 ГиБ памяти — под веса, выросший KV-пул и запас под page cache. 128-гигабайтный Strix Halo такое закрывает с запасом, а на 64 ГБ замахиваться на миллион уже не стоит.
Для первого захода с таким контекстом советую один слот (HALOGEN_KV_SLOTS=1) — незачем делить и без того растянутый KV-пул между четырьмя запросами. Веса из $HOME/halogen-models и API-ключ из env-файла никуда не денутся, ничего заново качать не придётся. А чтобы не трогать исходный контейнер, второй заведём под другим именем — halogen-yarn:
podman run -d \ --name halogen-yarn \ -p 0.0.0.0:9091:8731 \ --device /dev/kfd \ --device /dev/dri \ --group-add keep-groups \ --security-opt label=disable \ --ipc=host \ --ulimit memlock=-1:-1 \ --env-file "$HOME/.config/halogen/server.env" \ -e HALOGEN_KV_SLOTS=1 \ -e HALOGEN_ROPE_YARN=4 \ -e HALOGEN_CTX=1048576 \ -e HALOGEN_DOWNLOAD=peonist-ai/halogen-qwen3.8-flash-next \ -v "$HOME/halogen-models:/models" \ ghcr.io/peonist-ai/halogen-flash-server:0.18.5
Единственный нюанс: если основной контейнер halogen всё ещё работает, порт 9091 у него занят — остановите его перед запуском второго, два контейнера не смогут слушать один и тот же порт.
Не публикуйте HTTP API в интернете без TLS
API-ключ защищает сервер от чужих запросов, но шифровать соединение он не умеет. По чистому HTTP токен и содержимое запросов может перехватить любой, кто стоит по пути.
Правильная production-схема выглядит так:
Интернет ↓ HTTPS :9091Caddy / Nginx / Traefik ↓ HTTP 127.0.0.1:8731HALOGEN
Вместо итога
Связка из AMD Strix Halo, 128 ГБ RAM, Fedora 43 Server и HALOGEN позволяет поднять быстрый локальный API для Qwen3.8-Flash-Next — без дискретной GPU. На выходе получается:
-
MoE-модель на 125B параметров с 6B активных на токен;
-
около 110 ГиБ весов на диске;
-
50+ токенов/с для одного интерактивного потока на рабочих задачах при отключенном reasoning;
-
до четырёх параллельных генераций через
HALOGEN_KV_SLOTS=4; -
OpenAI-совместимые
/v1/chat/completions,/v1/completionsи/v1/responses; -
доступ извне через порт 9091;
-
авторизация через
HALOGEN_API_KEY.
Главное отличие этой конфигурации от «просто LLM-сервера» — правильная работа с UMA-памятью: низкий UMA carve-out в BIOS, понимание роли memory-mapped N-gram table и отказ от идеи читать показания nvtop как полный объём памяти, занятой моделью.
ссылка на оригинал статьи https://habr.com/ru/articles/1098996/