vLLM ist eine schnelle Inferenz-Engine für lokale Sprachmodelle. In diesem Beitrag richte ich das Qwen3.8-27B Modell auf zwei RTX A6000 ein. Der Hauptgrund, warum ich von Ollama jetzt einmal weggehen möchte, ist das agentische Entwickeln von Software mit Qwen3.8-27B. Und ich kann nur bei vLLM das Reasoning etwas beschränken, was bei Ollama so nicht möglich ist. Denn aktuell denkt mir das Modell zu viel nach und ich verliere so viel Zeit. Ich zeige jeden Schritt. Installation, Konfiguration, Update und das saubere Abschalten. Alle Befehle sind für Ubuntu.

Voraussetzungen prüfen

Zuerst schaue ich, ob der Treiber sitzt. Und ob beide Karten erkannt werden.

Befehl: nvidia-smi

Wichtig sind zwei Dinge. Beide A6000 müssen in der Liste stehen. Und der Treiber muss neu genug sein. Das aktuelle vLLM-Wheel ist gegen CUDA 13 gebaut. Dafür brauchst du Treiber 580 oder neuer. Meldet nvidia-smi eine kleinere Nummer, hebst du den Treiber an. Wie das geht, zeige ich gleich im nächsten Schritt. Ein separates CUDA-Toolkit brauche ich nicht. vLLM bringt sein CUDA über die Wheels selbst mit.

Ein Hinweis zur Hardware. Die A6000 sind Ampere. Das ist gleich noch wichtig bei der Wahl des Modells.

Treiber auf CUDA 13 anheben

Das ist der Schritt, der mich zuerst ausgebremst hat. Mein Server lief auf Treiber 575. Der unterstützt nur bis CUDA 12.9. Beim ersten Start von vLLM kam deshalb ein Fehler.

libcudart.so.13: cannot open shared object file

Der Grund ist einfach. Das Standard-Wheel von vLLM ist gegen CUDA 13 gebaut. Die passende Bibliothek fehlte, weil mein Treiber zu alt war. Also hebe ich den Treiber an.

Für CUDA 13 brauche ich Treiber 580.65.06 oder neuer. Meine A6000 sind Ampere. Ampere wird von CUDA 13 voll unterstützt. Das passt also.

Ein Vorteil vorweg. Ein neuer Treiber ist abwärtskompatibel. Meine anderen Tools nutzen CUDA-12-Builds. ComfyUI, Automatic1111 und Ollama laufen danach ohne Änderung weiter.

Vor dem Wechsel beende ich alle GPU-Dienste. Denn am Ende steht ein Neustart. Zuerst schaue ich, welche Treiber verfügbar sind.

Befehl: ubuntu-drivers list

Dann installiere ich den 580er-Treiber. Für Ampere sind die offenen Kernelmodule die richtige Wahl. Deshalb die Variante mit -open.

Befehl: sudo apt update

Befehl: sudo apt install nvidia-driver-580-open

Taucht das Paket nicht auf, fehlt die passende Paketquelle. Dann füge ich die Grafiktreiber-PPA hinzu und versuche es erneut.

Befehl: sudo add-apt-repository ppa:graphics-drivers/ppa

Befehl: sudo apt update

Nach der Installation starte ich den Server neu.

Befehl: sudo reboot

Nach dem Neustart prüfe ich das Ergebnis.

Befehl: nvidia-smi

Jetzt sollte oben Driver Version 580.xx und CUDA Version 13.x stehen. Damit passt der CUDA-13-Build von vLLM.

Noch ein Hinweis für alle, die den Treiber nicht anheben können oder wollen. Es gibt den umgekehrten Weg. Du installierst vLLM gezielt als CUDA-12.9-Build. Der Schlüssel ist eine zusätzliche Paketquelle für das passende Wheel.

Befehl: uv pip install "vllm==DEINE_VERSION" --torch-backend=cu129 --extra-index-url https://wheels.vllm.ai/DEINE_VERSION/cu129/ --index-strategy unsafe-best-match

Der Flag --torch-backend=cu129 allein reicht dabei nicht. Er betrifft nur PyTorch. Erst die zusätzliche Paketquelle sorgt dafür, dass auch der Kern von vLLM für CUDA 12.9 gebaut ist.

Hinweis, falls du vLLM schon vor dem Treiber-Wechsel installiert hattest. Dann hat PyTorch die CUDA-12-Laufzeit gezogen. Der Fehler libcudart.so.13 bleibt dann auch nach dem Treiber-Upgrade. Die Lösung ist ein sauberer Neuaufbau der Umgebung. Also rm -rf vllm-env und die Installationsschritte oben noch einmal. Das Modell bleibt im Cache und wird nicht neu geladen.

vLLM installieren

Ich installiere in einer eigenen Umgebung. So bleibt das System sauber. Der einfachste Weg führt über uv.

Befehl: curl -LsSf https://astral.sh/uv/install.sh | sh

Befehl: source ~/.bashrc

Befehl: uv venv --python 3.12 vllm-env

Befehl: source vllm-env/bin/activate

Befehl: uv pip install -U vllm --torch-backend=auto

Befehl: uv pip install -U "transformers>=5.8.0"

Mit dem 580er-Treiber wählt --torch-backend=auto jetzt korrekt den CUDA-13-Build. Die letzte Zeile ist wichtig. Führe sie unbedingt aus. Das Modell braucht transformers ab Version 5.8.0. Sonst kann vLLM die Konfiguration nicht lesen.

Installation prüfen

Jetzt kontrolliere ich, ob alles da ist.

Befehl: which vllm

Befehl: vllm --version

Die Version sollte 0.17.0 oder höher sein. Das ist die Mindestanforderung für dieses Modell. Bei mir zeigte ein frisches System vorher nur command not found. Nach der Installation erscheint die Versionsnummer.

(vllm-env) ingmar@A6000:~$ vllm –version
0.28.0

ninja fehlt: Abbruch beim Profiling

Ich greife hier kurz vor damit ihr nicht auch dieses Problem bekommt. Es ist ein kleinerer Stolperstein, aber einer, der den Start von vLLM ganz am Ende kippt. Kurz vor dem Ziel, beim Profiling, kompiliert vLLM einen Kernel zur Laufzeit. Dafür braucht es das Build-Werkzeug ninja. Fehlt es, bricht der Start ab.

FileNotFoundError: No such file or directory: 'ninja'

Die Lösung ist, ninja zu installieren. Am sichersten gleich auf beiden Wegen. Einmal im venv und einmal systemweit.

Befehl: uv pip install ninja

Diese Installation führt ihr wenn ich möchtet außerhalb der virtuellen Umgebung aus.

Befehl: sudo apt install ninja-build

Ein wichtiger Zusatz für den Dienst. Der systemd-Dienst kennt dein venv nicht und findet ninja sonst trotzdem nicht. Deshalb setze ich den PATH in der Unit. Wie das aussieht, steht unten im Autostart-Abschnitt.

vLLM aktualisieren

Wichtig ist mir auch immer die Software die ich installiere auch aktualisieren zu können. Updates von vLLM sind recht einfach eingespielt. Ich aktiviere die virtuelle Umgebung. Dann ziehe ich die neuen Pakete wie nachfolgend mit den Befehlen gezeigt.

Befehl: source vllm-env/bin/activate

Befehl: uv pip install -U vllm --torch-backend=auto

Befehl: uv pip install -U "transformers>=5.8.0"

Befehl: vllm --version

Danach prüfe ich die Version. Und starte den Server neu. Bei neuen Modellfamilien lohnt ein Update oft. Die Parser werden laufend verbessert.

Speicher auf den GPUs frei machen (optional)

Das ist der Schritt, den viele übersehen. Auf meinem Server liefen noch andere Dienste. ComfyUI, Automatic1111 und ein Ollama-Server. Der Ollama-Server war der größte Brocken. Er belegte fast 40 GB über beide Karten.

Erst schaue ich, was Ollama geladen hat.

Befehl: ollama ps

Dann entlade ich das Modell. Oder ich stoppe den ganzen Dienst.

Befehl: ollama stop MODELLNAME

Befehl: sudo systemctl stop ollama

Danach prüfe ich den Speicher erneut.

Befehl: nvidia-smi

Jetzt sollte auf jeder Karte reichlich frei sein. Rund 43 bis 47 GB. Das reicht für das Modell und viel Kontext.

Das richtige Modell für die A6000

Hier passt der wichtigste Hinweis rein. Für Qwen3.8-27B gibt es mehrere Varianten. NVFP4, FP8 und volles BF16.

Die quantisierten Varianten NVFP4 und FP8 sind für neuere Karten gebaut. Blackwell und Hopper. Auf Ampere laufen sie nicht sauber. Die A6000 hat weder FP4- noch native FP8-Kerne.

Für die A6000 ist deshalb BF16 die richtige Wahl. Das ist der Basis-Checkpoint ohne Zusatz im Namen. Also schlicht Qwen/Qwen3.8-27B. vLLM sucht sich nichts automatisch aus. Es lädt genau den Namen, den ich angebe.

Noch ein Punkt zum Download. Das Modell steht unter Apache-2.0. Es ist offen. Ich brauche keinen HuggingFace-Token. Der Download läuft ohne Anmeldung.

vLLM starten und konfigurieren

Zwei Dinge zuerst, und zwar in jeder neuen Terminal-Sitzung. Ich aktiviere die virtuelle Umgebung. Und ich setze die drei Umgebungsvariablen. Sonst landet der Cache wieder auf der Root-Platte und der Download kann hängen.

Befehl: source vllm-env/bin/activate

Befehl: export HF_HOME=/mnt/temp_03/vLLM/hf

Befehl: export VLLM_CACHE_ROOT=/mnt/temp_03/vLLM/cache

Befehl: export HF_HUB_DISABLE_XET=1

Diese Variablen gelten nur in der aktuellen Shell. Öffnest du ein neues Fenster, setzt du sie erneut. Oder du schreibst sie dauerhaft in die bashrc, wie im Cache-Abschnitt gezeigt. Dann fällt der Export-Schritt künftig weg. Die Umgebung musst du aber in jeder neuen Sitzung erneut aktivieren.

Jetzt der eigentliche Start. Beim ersten Mal lädt vLLM das Modell herunter. Rund 55 GB. Das dauert einmalig. Danach liegt es im Cache auf deinem schnellen Laufwerk.

Befehl: vllm serve Qwen/Qwen3.8-27B --tensor-parallel-size 2 --max-model-len 131072 --reasoning-parser qwen3 --default-chat-template-kwargs '{"reasoning_effort": "medium"}'

Ein wichtiger Hinweis vorweg, falls du wie ich zwei Karten ohne NVLink hast. Genau dieser Start hängt dann beim Zusammenschalten der Karten. Du brauchst zwei zusätzliche Angaben. Welche und warum, steht weiter unten im Abschnitt zu den zwei Karten ohne NVLink.

Die Flags im Einzelnen:

  • tensor-parallel-size 2 verteilt das Modell über beide Karten.
  • max-model-len 131072 setzt den Kontext auf 128k. Das Modell kann nativ bis 256k. Der Wert lässt sich also erhöhen.
  • reasoning-parser qwen3 trennt den Denkblock von der Antwort. Ohne das landet das Denken mitten im Antworttext.
  • default-chat-template-kwargs setzt die Denktiefe für alle Anfragen.

Ein Wort zum Speicheranteil. vLLM hat einen Default von 0.9. Es beansprucht also 90 Prozent jeder Karte. Der Wert bezieht sich auf den gesamten Speicher, nicht auf den freien. Wenn andere Dienste weiterlaufen, senke ich den Wert mit --gpu-memory-utilization 0.75.

Bei Tensor Parallel gilt der Wert für beide Karten gleich. vLLM richtet sich nach der volleren Karte. Sind die Karten ungleich belegt, wähle ich den Wert passend zur engeren Karte.

Wenn beim Start scheinbar nichts passiert

Beim ersten Start kann es wirken, als hinge vLLM. Das Terminal steht still. Die letzte Zeile ist meist der nccl-Hinweis. Das ist oft normal. vLLM lädt gerade im Hintergrund die rund 55 GB Gewichte. Über SSH werden die Fortschrittsbalken dabei häufig nicht sauber angezeigt.

Ob wirklich etwas passiert, sehe ich am wachsenden Cache. Dafür öffne ich ein zweites Terminal. Das laufende Fenster lasse ich in Ruhe. Also kein Strg und C. Dann beobachte ich den Zielordner.

Befehl: watch -n 5 'du -sh /mnt/temp_03/vLLM/hf'

Steigt die Zahl Richtung 55 GB, läuft der Download. Bleibt sie bei ein paar hundert Megabyte stehen, hängt er. Dann sind nur die kleinen Dateien da, aber nicht die Gewichte.

Zwei Dinge helfen dagegen. Bei mir habe ich beide gebraucht.

Erstens schalte ich hf-xet ab. Das ist der neue Downloadweg von HuggingFace. In manchen Netzen bleibt er ohne Fehlermeldung stehen. Die Variable hast du im Start-Abschnitt schon gesetzt. Falls nicht, hier noch einmal.

Befehl: export HF_HUB_DISABLE_XET=1

Zweitens, und das war bei mir der eigentliche Fix, lade ich das Modell vorab von Hand. vLLM zieht beim Start viele Dateien parallel. Genau dieser parallele Weg blieb bei mir hängen. Der klassische hf download lädt dagegen sauber, seriell und mit echtem Fortschritt. Wichtig ist, dass die Variablen aus dem Start-Abschnitt gesetzt sind. Dann landet der Download im richtigen Ordner.

Befehl: hf download Qwen/Qwen3.8-27B

Das dauert einmalig ein paar Minuten. Bei mir mit rund 11 MB pro Sekunde etwa anderthalb Stunden. Den Fortschritt verfolge ich im zweiten Terminal mit dem du -sh Befehl von oben. Ist der Download durch, starte ich vLLM ganz normal. Es findet die Gewichte im Cache, überspringt den Download und geht direkt zum Laden in die Karten und zum Kompilieren.

Befehl: vllm serve Qwen/Qwen3.8-27B --tensor-parallel-size 2 --max-model-len 131072 --reasoning-parser qwen3 --default-chat-template-kwargs '{"reasoning_effort": "medium"}'

Für das agentische Arbeiten habe ich das Reasoning auf medium gesetzt. Hier müsst ihr selber ausprobieren was für euch gut funktioniert. Es kann auch gut sein das low als Einstellung besser funktioniert. Ein Agent macht viele Runden. Kurze Runden halten die Session flott.

Läufst du auf zwei Karten ohne NVLink, ergänze auch hier --disable-custom-all-reduce und setze NCCL_P2P_DISABLE=1, wie im NVLink-Abschnitt beschrieben.

Den Server testen

Läuft der Server, teste ich diesen einem einfachen Aufruf.

Befehl: curl http://localhost:8000/v1/chat/completions -H "Content-Type: application/json" -d '{"model": "Qwen/Qwen3.8-27B", "messages": [{"role": "user", "content": "Nenne drei Primzahlen über 100."}]}'

Kommt eine saubere Antwort zurück, steht der Server. vLLM bietet eine OpenAI-kompatible API. OpenCode und andere Clients binden sich also leicht an.

Jetzt kannst Du Deine Werkzeuge mit der vLLM Instanz verbinden und loslegen.

Fazit

Der größte Brocken auf dem Weg war der fehlende NVLink zwischen meinen Karten. Ohne NCCL_P2P_DISABLE=1 und das Flag --disable-custom-all-reduce hängt der Start beim Zusammenschalten der beiden GPUs. Wer zwei A6000 auf reinem PCIe fährt, sollte das von Anfang an setzen. Das spart Dir ein paar Minuten den Fehler zu erkennen, die es mich gekostet hat.

vLLM läuft bei mir jetzt als systemd-Dienst und übernimmt den Platz von Ollama. Dank Cache sind die Neustarts schnell. Kein Docker nötig. Für mich ist die feine Reasoning-Steuerung der eigentliche Alltagsgewinn. Ich drehe die Denktiefe genau so weit, wie die Aufgabe es braucht. Zusammen mit dem Tempo der quantisierten Variante macht das den lokalen Betrieb im Alltag richtig angenehm.

Aber die eigentliche Erkenntnis dieses Setups war eine andere. Das volle BF16-Modell auf zwei Karten war mir für agentisches Arbeiten zu langsam, und ich wollte eine GPU wieder frei bekommen. Mit einer INT4-Quantisierung auf nur einer Karte habe ich beides erreicht. Spürbar mehr Tempo beim Decode, und die zweite A6000 steht wieder für andere Aufgaben zur Verfügung.