vLLM auf Strix Halo
Einrichtung, Konfiguration und Betrieb von vLLM auf einer Strix-Halo-APU unter Linux — von den Kernel-Parametern bis zum systemd-Service. Stand: August 2026.
TL;DR — der schnellste Weg
1) Kernel-Parameter in /etc/default/grub an GRUB_CMDLINE_LINUX anhängen:
amd_iommu=off amdgpu.gttsize=126976 ttm.pages_limit=32505856
2) Toolbox-Repo holen und Container anlegen
3) Rein und Modell starten
4) Testen
$sudo grub2-mkconfig -o /boot/grub2/grub.cfg
$sudo reboot
$sudo dnf install -y git toolbox
$git clone https://github.com/kyuz0/amd-strix-halo-vllm-toolboxes.git
$cd amd-strix-halo-vllm-toolboxes
$./refresh_toolbox.sh
$toolbox enter vllm
$start-vllm # interaktiver TUI-Assistent
$curl -s http://localhost:8000/v1/models | jq
Warum das überhaupt fummelig ist
2.1 Es ist eine APU mit Unified Memory
| Begriff | Bedeutung |
|---|---|
| VRAM / Carve-out / GART | Der im BIOS fest für die GPU reservierte Block. Permanent weg vom OS. |
| GTT | Der Pool an System-RAM, der dynamisch in GPU-Adressräume gemappt werden darf. Das ist der Topf, aus dem PyTorch und vLLM sich bedienen. Standardmäßig ca. 50 % des RAM. |
2.2 gfx1151 war lange ein Sonderfall
amdsmi. Diese Bibliothek kannte gfx1151 lange nicht, und Build-Systeme kompilierten per Default für gfx1200/gfx1201 (RDNA4) statt für RDNA3.5. Deshalb kursieren so viele Anleitungen mit Patch-Orgien.AMDGPU_TARGETS=gfx1151 bauen kann. Die Community-Toolbox bleibt trotzdem der bequemste Weg, weil dort zusätzlich AITER-, Triton- und RCCL-Anpassungen für RDNA-APUs drinstecken.2.3 Der Kernel muss neu genug sein
| Distribution | Mindest-Kernel |
|---|---|
| Ubuntu 24.04 HWE | 6.17.0-19.19~24.04.2 |
| Ubuntu 24.04 OEM | 6.14.0-1018 |
| Alle anderen (Fedora, Arch, …) | 6.18.4 |
Voraussetzungen
Hardware
- AMD Ryzen AI Max / Max+ (Strix Halo, gfx1151) — z. B. Framework Desktop, GMKtec EVO-X2, HP ZBook Ultra G1a
- Idealerweise 128 GB LPDDR5X-8000 (64 GB geht, limitiert aber die Modellgröße hart)
- Speicherbandbreite ~256 GB/s theoretisch, real eher ~215 GB/s — das ist dein eigentliches Limit bei der Token-Rate
Software
- Fedora 43 (am besten getestet) oder Ubuntu 26.04 / 24.04 HWE
- Kernel gemäß Tabelle oben
podman(Fedora) bzw.docker+distrobox(Ubuntu)- Genug Plattenplatz: ein 120B-Modell in BF16 sind ~120 GB Download
Vorab prüfen
$uname -r # Kernel-Version
$lspci | grep -i vga # sollte "Radeon 8060S" o. ä. zeigen
$rocminfo | grep gfx # sollte gfx1151 melden (falls ROCm auf dem Host)
$free -g # verfügbarer RAM
Schritt 1: Host konfigurieren (der wichtigste Teil)
4.1 BIOS
4.2 Kernel-Parameter
/etc/default/grub bei GRUB_CMDLINE_LINUX diese drei Parameter ein:$amd_iommu=off amdgpu.gttsize=126976 ttm.pages_limit=32505856
| Parameter | Zweck |
|---|---|
amd_iommu=off | Schaltet die IOMMU ab. Community-Benchmarks zeigen 5–12 % Vorteil gegenüber iommu=pt bzw. eingeschalteter IOMMU. Reduziert Overhead beim Unified-Memory-Zugriff (und bei RDMA-NICs). |
amdgpu.gttsize=126976 | Deckelt den GTT-Pool auf 124 GiB (126976 MiB ÷ 1024). |
ttm.pages_limit=32505856 | Deckelt den pinbaren Speicher auf dieselben 124 GiB (32505856 × 4 KiB). Beide Werte müssen zusammenpassen. |
gttsize = 60 × 1024 = 61440 und pages_limit = 61440 × 1024 / 4 = 15728640.$sudo grub2-mkconfig -o /boot/grub2/grub.cfg # Fedora
$# Ubuntu: sudo update-grub
$sudo reboot
$cat /proc/cmdline | grep gttsize
$cat /sys/module/ttm/parameters/pages_limit
4.3 Alternative: amd-ttm statt Kernel-Parametern
/etc/modprobe.d/ttm.conf setzt — bequemer als GRUB-Gefummel:$sudo apt install pipx # bzw. dnf install pipx
$pipx ensurepath
$pipx install amd-debug-tools
$amd-ttm # zeigt aktuelles Limit + Gesamt-RAM
$amd-ttm --set 120 # 120 GB freigeben
$# danach rebooten
$amd-ttm --clear # zurück auf Kernel-Default
Schritt 2: Container anlegen (Weg A — empfohlen)
5.1 Warum Container?
- ROCm-Nightlies und die passenden PyTorch-Wheels sind eine sehr spezifische Kombination. Auf dem Host installiert zerschießt dir das früher oder später die Systempakete.
- Toolbx/Distrobox teilen dein
$HOMEund deinen User mit dem Container. Modelle landen also in~/.cache/huggingfaceauf dem Host und überleben jedes Image-Update. - Für den Produktivbetrieb kannst du dasselbe Image auch als reinen Docker/Podman-Container mit Host-Networking fahren.
5.2 Image-Kanäle
| Tag | Beschreibung |
|---|---|
:latest | Letzter verifizierter Build. Für die meisten Leute die richtige Wahl. |
:dev | Bleeding Edge. Kann Upstream-Regressionen enthalten. |
5.3 Fedora (Toolbx)
$sudo dnf install -y git toolbox
$git clone https://github.com/kyuz0/amd-strix-halo-vllm-toolboxes.git
$cd amd-strix-halo-vllm-toolboxes
$./refresh_toolbox.sh # interaktiv; oder: ./refresh_toolbox.sh latest
/dev/infiniband existiert, und reicht die Geräte für RDMA-Clustering durch. Manuell geht’s genauso:$toolbox create vllm \
$ --image docker.io/kyuz0/vllm-therock-gfx1151:latest \
$ -- --device /dev/dri --device /dev/kfd \
$ --group-add video --group-add render \
$ --security-opt seccomp=unconfined
$toolbox enter vllm
| Flag | Zweck |
|---|---|
--device /dev/kfd | Kernel-Fusion-Driver — das eigentliche Compute-Interface von ROCm |
--device /dev/dri | Direct-Rendering-Interface — Zugriff auf die GPU-Knoten |
--group-add video --group-add render | Gruppenrechte für den GPU-Zugriff |
--security-opt seccomp=unconfined | ROCm braucht Syscalls, die das Default-seccomp-Profil blockt |
5.4 Ubuntu / Debian / Arch (Distrobox)
toolbox-Paket unter Ubuntu bricht den GPU-Zugriff — nimm Distrobox:$distrobox create -n vllm \
$ --image docker.io/kyuz0/vllm-therock-gfx1151:latest \
$ --additional-flags "--device /dev/kfd --device /dev/dri \
$ --group-add video --group-add render --security-opt seccomp=unconfined"
$distrobox enter vllm
5.5 GPU im Container verifizieren
$rocm-smi
$rocminfo | grep -i gfx
$python -c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))"
Schritt 3: Modell starten
6.1 Variante A: TUI-Assistent
start-vllm mit — ein interaktiver Launcher mit vorkonfigurierten Modellen, der die passenden Flags, Attention-Backends und Cache-Einstellungen selbst setzt:$start-vllm
6.2 Variante B: Manueller Start
$vllm serve Qwen/Qwen3.6-35B-A3B \
$ --host 0.0.0.0 \
$ --port 8000 \
$ --tensor-parallel-size 1 \
$ --max-num-seqs 1 \
$ --max-model-len 32768 \
$ --gpu-memory-utilization 0.95 \
$ --dtype auto \
$ --trust-remote-code \
$ --attention-backend TRITON_ATTN
6.3 Die Flags im Detail
| Flag | Erklärung |
|---|---|
--host 0.0.0.0 | Lauscht auf allen Interfaces. Nur setzen, wenn du wirklich von außen zugreifen willst — vLLM hat standardmäßig keine Authentifizierung. Sonst 127.0.0.1 + SSH-Tunnel. |
--port 8000 | Standardport der OpenAI-kompatiblen API |
--tensor-parallel-size 1 | Eine „GPU“. Unified Memory heißt: kein TP nötig. TP=2 nur im Multi-Node-Cluster. |
--max-num-seqs 1 | Maximal 1 Anfrage gleichzeitig → niedrigste Latenz für Einzelnutzer. Für Mehrbenutzer/Agenten unbedingt hochsetzen (8–32), sonst verschenkst du genau die Stärke von vLLM. |
--max-model-len 32768 | Kontextfenster. Direkt proportional zum KV-Cache-Verbrauch — der erste Hebel bei OOM. |
--gpu-memory-utilization 0.95 | Anteil des GPU-Speichers für Gewichte + KV-Cache. Bei Instabilität auf 0.90 oder 0.85. |
--dtype auto | Nimmt den im Modell hinterlegten Typ (meist BF16). |
--trust-remote-code | Nötig für Modelle mit eigenem Python-Code im Repo (Qwen, MiniMax u. a.). Nur bei Repos, denen du vertraust. |
--attention-backend TRITON_ATTN | Attention-Implementierung — siehe nächster Abschnitt. |
Schritt 4: Konfiguration verstehen und tunen
7.1 Attention-Backends
| Backend | Charakteristik |
|---|---|
TRITON_ATTN | Triton-Kernel. Der solide Default auf gfx1151, breiteste Modellkompatibilität. |
ROCM_ATTN | Routet in der Toolbox auf AITER Flash Attention. Kann schneller sein, aber nicht bei jedem Modell stabil. |
ROCM_AITER_UNIFIED_ATTN | AITERs Unified-Attention-Pfad. Ausprobieren, benchmarken, dann entscheiden. |
VLLM_ROCM_USE_AITER=1, weil AITER CDNA-spezifische Assembly für MoE- und CustomOps JIT-kompilieren will, die RDNA-Hardware schlicht nicht hat. Die Toolbox setzt dafür gezielte Guards: AITER-MoE und FP8-Linear werden auf gfx1x deaktiviert, das Env-Var-Override wird blockiert, und die RMSNorm-Custom-Op-Registrierung wird umgangen (die sonst beim CUDA-Graph-Capture während der Modellinitialisierung crasht). Ergebnis: Attention läuft über AITER, MoE-Matrizen fallen sicher auf Triton zurück.7.2 Nützliche Environment-Variablen
Speichermodell von Strix Halo — praktisch immer sinnvoll
Experimentelle AOTriton-Kernel, für gfx1151 nötig
Spürbarer Durchsatzgewinn durch besseren Allocator
hipBLASLt statt rocBLAS
Autotuning der GEMM-Kernel (langsamer erster Lauf, danach schneller)
$export HIP_FORCE_DEV_KERNARG=1
$export TORCH_ROCM_AOTRITON_ENABLE_EXPERIMENTAL=1
$export LD_PRELOAD=/usr/lib64/libtcmalloc_minimal.so.4
$export ROCBLAS_USE_HIPBLASLT=1
$export PYTORCH_TUNABLEOP_ENABLED=1
vllm/envs.py.7.3 Kernel-Cache
~/.cache/vllm/ und werden danach wiederverwendet. Nach einem Image-Update lohnt es sich, diesen Cache zu leeren:$rm -rf ~/.cache/vllm/
Schritt 5: API testen + Web-UI
8.1 API-Check
Welches Modell läuft gerade?
Chat-Completion
$curl -s http://localhost:8000/v1/models | jq -r '.data[0].id'
$MODEL=$(curl -s http://localhost:8000/v1/models | jq -r '.data[0].id')
$curl -X POST http://localhost:8000/v1/chat/completions \
$ -H "Content-Type: application/json" \
$ -d "{
$ \"model\": \"$MODEL\",
$ \"messages\": [{\"role\": \"user\", \"content\": \"Erklär mir GTT in zwei Sätzen.\"}]
$ }" | jq -r '.choices[0].message.content'
base_url="http://localhost:8000/v1" und einem beliebigen Dummy-Key.8.2 Remote-Zugriff
$ssh -L 8000:localhost:8000 user@strix-halo-host
http://localhost:8000 auf deinem Rechner auf den Server.8.3 Web-UI
$docker run -p 3000:3000 \
$ --add-host=host.docker.internal:host-gateway \
$ -e OPENAI_BASE_URL=http://host.docker.internal:8000/v1 \
$ -e OPENAI_API_KEY=dummy \
$ -v chat-ui-data:/data \
$ ghcr.io/huggingface/chat-ui-db
OPENAI_API_BASE_URL.Dauerbetrieb: systemd-Service
# ~/.config/systemd/user/vllm.service
[Unit]
Description=vLLM (Strix Halo, gfx1151)
After=network-online.target
Wants=network-online.target
[Service]
Restart=always
RestartSec=10
TimeoutStartSec=900
ExecStartPre=-/usr/bin/podman rm -f vllm-server
ExecStart=/usr/bin/podman run --rm --name vllm-server \
--device /dev/kfd --device /dev/dri \
--group-add keep-groups \
--security-opt seccomp=unconfined \
--ipc=host \
--network=host \
-v %h/.cache/huggingface:/root/.cache/huggingface:z \
-v %h/.cache/vllm:/root/.cache/vllm:z \
-e HIP_FORCE_DEV_KERNARG=1 \
-e TORCH_ROCM_AOTRITON_ENABLE_EXPERIMENTAL=1 \
docker.io/kyuz0/vllm-therock-gfx1151:latest \
vllm serve Qwen/Qwen3.6-35B-A3B \
--host 127.0.0.1 --port 8000 \
--max-num-seqs 8 \
--max-model-len 32768 \
--gpu-memory-utilization 0.92 \
--attention-backend TRITON_ATTN
ExecStop=/usr/bin/podman stop -t 30 vllm-server
[Install]
WantedBy=default.target$systemctl --user daemon-reload
$systemctl --user enable --now vllm.service
$loginctl enable-linger $USER # damit's ohne aktive Session läuft
$journalctl --user -u vllm -f
Weg B: Eigenes Image aus vLLM-Upstream bauen
$git clone https://github.com/vllm-project/vllm.git
$cd vllm
$DOCKER_BUILDKIT=1 docker build \
$ --build-arg AMDGPU_TARGETS=gfx1151 \
$ -f docker/Dockerfile.rocm \
$ -t vllm-rocm-strix-halo .
vllm-rocm-strix-halo als Image.Weg C: Bare Metal aus dem Quellcode
1) Build-Abhängigkeiten
2) ROCm aus TheRock-Nightlies (nach GFX-Target indiziert)
3) PyTorch aus dem target-spezifischen Nightly-Index
4) vLLM bauen — WICHTIG: ROCms clang, nicht Fedoras GCC
$sudo dnf install -y python3.13 python3.13-devel libatomic gcc gcc-c++ make \
$ ffmpeg-free aria2 libdrm-devel zlib-devel openssl-devel procps-ng \
$ numactl-devel gperftools-libs libibverbs-utils
$GFX=gfx1151
$ROCM_PATH=/opt/rocm
$S3="https://therock-nightly-tarball.s3.amazonaws.com"
$KEY="$(curl -s "${S3}?list-type=2&prefix=therock-dist-linux-${GFX}-7" \
$ | grep -oP '(?<=<Key>)[^<]+' | sort -V | tail -n1)"
$aria2c -x 16 -s 16 -j 16 "${S3}/${KEY}" -o therock.tar.gz
$sudo mkdir -p "$ROCM_PATH"
$sudo tar xzf therock.tar.gz -C "$ROCM_PATH" --strip-components=1
$python -m pip install --pre torch torchaudio torchvision \
$ --index-url "https://rocm.nightlies.amd.com/v2-staging/${GFX}/"
$export CC="$ROCM_PATH/llvm/bin/clang"
$export CXX="$ROCM_PATH/llvm/bin/clang++"
$export PYTORCH_ROCM_ARCH="$GFX" AMDGPU_TARGETS="$GFX" HIP_ARCHITECTURES="$GFX"
$export VLLM_TARGET_DEVICE=rocm
$git clone https://github.com/vllm-project/vllm.git && cd vllm
$python -m pip wheel --no-build-isolation --no-deps -w /tmp/dist -v .
$python -m pip install /tmp/dist/*.whl
- Compiler-ABI: Mit GCC gebaute vLLM-Extensions sind inkompatibel zu dem mit Clang gebauten PyTorch. Immer ROCms Clang nehmen.
- Bitcode-Pfad: TheRock-Nightlies haben keinen stabilen Pfad zum Device-Bitcode. Dynamisch suchen:
find "$ROCM_PATH" -type d -name bitcode -print -quitund alsHIP_DEVICE_LIB_PATHsetzen.
Modellauswahl für 128 GB Unified Memory
| Modell | Größe / Quant | Anforderung |
|---|---|---|
meta-llama/Meta-Llama-3.1-8B-Instruct | 8B / BF16 | 1 GPU |
google/gemma-4-26B-A4B-it | 26B / BF16 | 1 GPU |
openai/gpt-oss-20b | 20B / BF16 | 1 GPU |
openai/gpt-oss-120b | 120B / BF16 | 1 GPU |
Qwen/Qwen3.6-35B-A3B | 35B / BF16 | 1 GPU |
cyankiwi/Qwen3.5-122B-A10B-AWQ-4bit | 122B / AWQ 4-bit | 1 GPU |
cyankiwi/Qwen3.5-122B-A10B-AWQ-8bit | 122B / AWQ 8-bit | nur 2 Nodes (TP=2) |
cyankiwi/MiniMax-M2.7-AWQ-4bit | AWQ 4-bit | nur 2 Nodes (TP=2) |
Warum MoE-Modelle hier besonders gut passen
Qwen3.6-35B-A3B stehen 35B Gesamtparameter nur ~3B aktiven Parametern pro Forward-Pass gegenüber. Auf Strix Halo ist das ideal: Der große Gesamtumfang lebt bequem im Unified Memory, aber pro Token muss nur ein Bruchteil davon durch die Speicherbandbreite — und die Bandbreite ist auf dieser Plattform der Flaschenhals, nicht die Rechenleistung. Du bekommst also annähernd Qualität eines großen Modells bei der Geschwindigkeit eines kleinen.Zu den Benchmark-Zahlen im Netz
Troubleshooting
| Symptom | Ursache & Lösung |
|---|---|
rocm-smi findet nichts im Container | Container ohne --device /dev/kfd --device /dev/dri angelegt; oder User nicht in video/render; oder unter rootless Podman → --group-add keep-groups statt der benannten Gruppen |
| OOM beim Modell-Laden | Kernel-Parameter prüfen (cat /proc/cmdline). Dann --gpu-memory-utilization auf 0.90/0.85, --max-model-len halbieren |
| OOM erst mitten im Betrieb | --max-num-seqs zu hoch — jede parallele Sequenz braucht eigenen KV-Cache |
| Container startet gar nicht (rootless) | Die benannten GPU-Gruppen können unter rootless Podman den Start blockieren → --group-add keep-groups |
| Crash beim Init mit CUDA-Graph-Capture | Bekanntes RMSNorm-/AITER-Problem auf RDNA. Toolbox-Image nutzen (bringt den Guard mit) oder AITER abschalten |
| Erste Inferenz extrem langsam | Triton-Kernel werden kompiliert. Normal. Cache liegt in ~/.cache/vllm/ |
| Nach Image-Update seltsame Fehler | Kernel-Cache leeren: rm -rf ~/.cache/vllm/ |
| Instabilität, zufällige Hänger | Kernel < 6.18.4? Upgraden. Auf gfx1151 gibt es dort einen bekannten Bug |
| Nur ~64 GB nutzbar trotz korrekter Parameter | Bekannter Bug in manchen ROCm-Nightlies, der die Allokation deckelt. Auf einen stabilen ROCm-7.x-Build wechseln |
unrecognized environment variable | Image zu alt für die Variable. Aktualisieren oder Variable weglassen |
| Modell lädt, Ausgabe ist Kauderwelsch | Falsches Attention-Backend oder inkompatible Quantisierung. Auf TRITON_ATTN + BF16 zurückfallen und von dort neu tunen |
$cat /proc/cmdline # Kernel-Parameter aktiv?
$cat /sys/module/ttm/parameters/pages_limit # TTM-Limit
$rocm-smi --showmeminfo vram # was sieht ROCm?
$uname -r # Kernel neu genug?
$journalctl -k | grep -i amdgpu | tail -50 # Treiberfehler
Realistische Erwartungen: vLLM vs. llama.cpp
Quellen
- kyuz0/amd-strix-halo-vllm-toolboxes — das Toolbox-Projekt (Image, Launcher, Patches, RDMA-Cluster)
- Benchmark-Übersicht des Projekts
- AMD ROCm: RDNA3.5 System Optimization — offizielle Doku zu GTT/TTM/VRAM und Kernel-Anforderungen
- blog.jreb.nl: Running vLLM on AMD Ryzen AI Max+ 395 — durchgängiges Setup-Walkthrough
- blog.epheo.eu: Running vLLM on Strix Halo — Build aus dem Quellcode inkl. Patches
- iqreactor.com: vLLM with native support on Strix Halo — Upstream-Build mit AMDGPU_TARGETS=gfx1151
- nerds-run/strix_halo_vllm — Ansible-Automatisierung
- llm-tracker.info: Strix Halo — laufend gepflegte Sammlung zum Plattform-Stand
- ROCm/TheRock — AMDs Nightly-Builds inkl. gfx1151-Targets
- vLLM-Doku + vllm/envs.py — maßgebliche Liste aller Environment-Variablen