2tap2b

Mein lokaler LLM-Server mit AMD RX 7900XTX

Inhaltsverzeichnis

Hardware & System

Ich habe meinen alten Gaming-Rechner zu einem lokalen LLM-Server umgebaut. Die Specs:

  • Ubuntu 26.04.1 LTS, Kernel 7.0.0-31-generic
  • AMD Ryzen 7 5800X (8 Kerne / 16 Threads)
  • 32GB RAM
  • AMD Radeon RX 7900 XTX mit 24 GB VRAM

Der Hauptgrund für die AMD GPU war der Preis. Damit habe ich den besten VRAM-Preis pro Gigabyte bekommen, den es aktuell gibt. Für lokale LLM-Inferenz ist das viel wichtiger als die reine Rechenleistung - man muss die Gewichte und den KV-Cache im Speicher haben.

Warum AMD und nicht NVIDIA?

NVIDIA hat den CUDA-Monopol-Standard, aber AMDs ROCm hat sich in den letzten zwei Jahren enorm verbessert. Für lokale LLM-Inferenz mit llama.cpp funktioniert es jetzt wirklich gut - besonders wenn man ein Modell mit nur 16 Attention-Layern wie Qwen3.8-27B nutzt. Das spart massiv VRAM im KV-Cache.

Die Installation

Ich habe mich gegen das System-Paket entschieden und stattdessen eine eigenständige Installation in ~/.local/llama-rocm/ gemacht. Das hat den Vorteil, dass ich die Versionen unabhängig vom System aktualisieren kann und nichts global verschmutzt wird.

Die Umgebungsvariablen sind kritisch:

export ROCM_PATH=/opt/rocm
export HIP_PATH=/opt/rocm
export LD_LIBRARY_PATH=~/.local/llama-rocm/lib:/opt/rocm/core-7.14/lib
export PATH=~/.local/llama-rocm/bin:$PATH
export HIP_VISIBLE_DEVICES=0

Wichtig: Für den systemd-Service darf man export nicht verwenden - jede Zeile muss eine reine KEY=VALUE-Zuweisung sein. Das ist ein typischer Fehler, wenn man die Umgebungsvariablen für interaktive Sessions mit denen für Services verwechselt.

Das Modell: Qwen3.8-27B TURBO (MTP)

Ich nutze das DavidAU Fine-Tune von Qwen3.8-27B in Q4_K_M Quantisierung. Das Modell ist 18,5 GB groß und passt mit seinen Gewichten plus dem mmproj-Vision-Projektor knapp in den VRAM der 7900 XTX.

Qwen3.8-27B ist ein Hybrid-Modell: Von den 64 Layern sind nur 16 volle Attention-Layer, die restlichen sind Gated DeltaNet-Layer. Das macht es für lokale Hardware sehr effizient, weil der KV-Cache pro Token extrem klein wird - bei q4_0 Quantisierung nur ~18 KB pro Token. Zum Vergleich: Ein normales Modell mit voller Attention hätte bei gleicher Kontextgröße den 4-fachen VRAM-Bedarf.

systemd-Service

Der Server läuft als systemd-Service mit folgenden Flags:

llama-server \
  -m /path/to/model.gguf \
  --host 0.0.0.0 --port 8081 \
  --ctx-size 65536 -ngl 99 -fa on \
  --cache-type-k q4_0 --cache-type-v q4_0 \
  --mmproj /path/to/mmproj.gguf \
  --spec-type draft-mtp --spec-draft-n-max 2 \
  --temp 0.7 --top-p 0.80 --top-k 20 --presence-penalty 1.5

Die wichtigsten Flags:

  • -ngl 99 - alle Layer auf die GPU schieben
  • --ctx-size 65536 - 64k Kontextfenster (bewusst begrenzt, mehr dazu unten)
  • --cache-type-k/q4_0 --cache-type-v q4_0 - quantisierter KV-Cache
  • --spec-type draft-mtp --spec-draft-n-max 2 - MTP speculatives Decoding für schnellere Generierung

Die drei Fettnäpfchen, die ich gelernt habe

1. VRAM-Budget

Ich habe zuerst mit --ctx-size 180000 und q8_0 V-Cache probiert. Das hat den GPU-Speicher zu 99,8% belegt. Sobald dann das Reasoning-Feature aktiviert wurde, brauchte der Server zusätzliche Graph-Buffer - und crashte mit SIGABRT. Jeder Request brach als “connection reset by server” ab.

Die Lösung: Kontext auf 65536 begrenzen und V-Cache auf q4_0 senken. Das gibt 2-3 GB Headroom für Compute-Buffer und macht das System stabil.

2. reasoning_effort ist eine Whitelist

Das Qwen3.8-Template validiert den reasoning_effort Parameter streng. Es akzeptiert nur xhigh, medium oder low. Wenn ein Client high oder minimal sendet, crasht der Server mit HTTP 500. Die Validierung greift nur, wenn Thinking aktiviert ist - also wenn enable_thinking nicht explizit auf false gesetzt wird.

3. —reasoning off ist ein harter Switch

Wenn man den Server mit --reasoning off startet, kann kein Client per Request das Reasoning wieder einschalten. Das ist in neueren Builds beabsichtigt - das Per-Request-Hebelchen wird deprecating. Wenn du Reasoning manchmal brauchst, starte den Server ohne den Flag und begrenze es clientseitig.

Produktive Nutzung

Mit 30-45 Tokens pro Sekunde fühlt sich die Nutzung gut an. Jeder Prompt braucht ein paar Sekunden bis das Thinking startet, aber wenn dann Output generiert wird, ist die Geschwindigkeit akzeptabel. Meine Use Cases sind:

  • Code Refactoring
  • Mein eigenen Code gegenprüfen lassen
  • Security Checks in meinen Projekten
  • Alt Text Erstellung für Bilder (mit dem Vision-Projektor)
  • Rechtschreibprüfung und Übersetzung
  • Dokumenten-OCR in Verbindung mit Paperless-AI
  • NixOS Konfiguration schreiben

Das LLM verbessert meine minimalen Nix-Kenntnisse, sodass ich jetzt quasi alles an NixOS tweaken kann, was ich will - mit Hilfe der KI. Ohne den Server hätte ich nie so schnell in NixOS reinfinden können.

Performance

Mit der aktuellen Konfiguration:

  • Prompt-Processing: ~800 Tokens/s
  • Generation: ~35-45 Tokens/s mit MTP speculativem Decoding (Draft-Akzeptanz 66-93%)

Ohne MTP wäre es deutlich langsamer. Das speculative Decoding ist ein Gamechanger für die Antwortzeit.

API-Nutzung

Der Server spricht die OpenAI-kompatible API auf http://localhost:8081/v1. Kein API-Key nötig. Ich nutze das mit opencode als Client, konfiguriert in ~/.config/opencode/opencode.jsonc mit der baseURL und der Modell-ID.

Fazit

Ein lokaler LLM-Server auf AMD-Hardware ist jetzt wirklich machbar. Die Kombination aus llama.cpp, ROCm 7.14 und einem effizienten Hybrid-Modell wie Qwen3.8-27B liefert brauchbare Ergebnisse - besonders mit dem MTP speculative Decoding für die Geschwindigkeit.

Die VRAM-Budgetierung ist der kritischste Teil. Bei 24 GB muss man aufpassen, was man ins Modell packt und wie groß das Kontextfenster ist. Aber wenn es stabil läuft, hat man einen privaten, schnellen LLM-Server ohne Abhängigkeit von Cloud-APIs. Und mit dem richtigen Preis-Leistungs-Verhältnis bei AMD-GPUs ist das für jeden erschwinglich.