Мануал по развёртыванию

Развернуть локальную LLM на Strix Halo (Ryzen AI Max+ 395): llama.cpp с нуля до первого ответа

Точный путь, которым мы разворачиваем на собственных коробках: настройка памяти, о которой молчит BIOS, запиненный контейнер llama.cpp на Vulkan и три проверки, что сервер действительно работает, — включая два отказа, которые прячутся за зелёными статусами.

Платформа:
Strix Halo (Ryzen AI Max+ 395)
Время на прохождение:
45 мин
Обновлено:
01.09.2026

Это путь развёртывания, который мы гоняем на собственных машинах с Ryzen AI Max+ 395 — тех же коробках, что стоят за нашими опубликованными цифрами. Без теории и каталога вариантов: один рабочий путь, с ловушками, размеченными там, где они ловили нас. Ожиданий по скорости здесь намеренно нет — они живут в отчётах, измеренные как положено.

Понадобятся: коробка на Strix Halo (любого вендора), Linux со свежим ядром, Docker и место на диске под выбранную модель.

Шаг 1 — сначала разберитесь с потолком памяти

На Linux ваши модели будут жить в GTT, а не в выделенном через BIOS куске VRAM, и потолок задаёт параметр ядра. Пропуск этого шага — самая частая причина, по которой большая модель отказывается грузиться на этом железе. Проверьте текущий лимит:

cat /sys/module/ttm/parameters/pages_limit

Умножьте на 4 KiB, чтобы получить байты. Если выходит лишь доля вашей RAM — поднимите через командную строку ядра (ttm.pages_limit=...) и перезагрузитесь. Полное объяснение, почему ползунок в BIOS не тот рычаг, — с показаниями нашей обслуживающей ноды — в отчёте про распределение памяти. Кусок в BIOS оставьте маленьким.

Шаг 2 — возьмите модель

Выберите GGUF-артефакт и запишите его точную ревизию. MoE класса 35B в Q4_K_M — та золотая середина, которую мы ежедневно обслуживаем на этом железе: остаётся место под контекст и вторую модель. Какой квант брать — вопрос измеренный; короткая версия: начните с Q4_K_M, а не с самого большого файла, который влезает.

mkdir -p /var/lib/llm/models
# скачайте выбранный .gguf сюда и запишите, ОТКУДА он взялся —
# репозиторий и ревизию. "main" переезжает; ваши записи — нет.

Шаг 3 — запустите сервер и запините его

Vulkan-сборка сервера llama.cpp работает на этом iGPU сразу:

docker run -d --name llm-server \
  --device /dev/dri --device /dev/kfd \
  -v /var/lib/llm/models:/models \
  -p 8080:8080 \
  ghcr.io/ggml-org/llama.cpp:server-vulkan \
  -m /models/YOUR-MODEL.gguf \
  -ngl 999 -fa on -c 32768 \
  --host 0.0.0.0 --port 8080 --jinja

Две привычки, которые спасут вас позже. Первая: когда всё заработает, вытяните образ заново по digest (ghcr.io/ggml-org/llama.cpp@sha256:...) вместо тега — теги переезжают, и когда будущее обновление изменит поведение, вам нужно будет знать, на какой именно сборке вы были. Вторая: если меняете --port, знайте, что встроенный healthcheck образа всё равно стучится в 8080 — контейнер будет показывать unhealthy, безупречно обслуживая запросы. Мы разобрали ровно эту ловушку после того, как она укусила нас, — либо держите внутренний порт на 8080, либо переопределите healthcheck.

Шаг 4 — спросите сервер, что он на самом деле запускает

Не доверяйте своей командной строке; доверяйте процессу:

curl -s localhost:8080/props | python3 -m json.tool | head -40

Прочитайте n_ctx, путь к модели и число слотов. Дефолты меняются между версиями llama.cpp, а флаг, который вы не выставили, всё равно часть вашей конфигурации — этот урок обошёлся нам дорого.

Шаг 5 — smoke-тест, который действительно что-то доказывает

HTTP 200 пока не доказывает ничего. Отправьте настоящий запрос и проверьте три вещи:

curl -s localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"messages":[{"role":"user","content":"Reply with one short sentence: what is inference?"}],
       "max_tokens":400,"temperature":0}' \
  | python3 -c "import json,sys; d=json.load(sys.stdin); m=d['choices'][0]['message']; \
    print('content:', repr(m.get('content','')[:120])); \
    print('finish:', d['choices'][0].get('finish_reason')); \
    print('tokens:', d.get('usage',{}).get('completion_tokens'))"

Проверка один: content не пуст. Рассуждающая модель может сжечь весь бюджет токенов на размышления и вернуть пустой ответ под безупречным HTTP 200 — мы измерили, как часто; если видите такое — поднимите max_tokens или отключите размышления. Проверка два: finish — это stop, а не length. Проверка три: если когда-нибудь будете что-то измерять, считайте токены из usage.completion_tokens — никогда из числа событий стрима.

Шаг 6 — решите про режим размышлений

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

Куда дальше

← Все мануалы