In diesem Beitrag vLLM auf zwei RTX A6000 installieren: Treiber, Setup und erster Start mit Qwen3.8-27B habe ich vLLM auf zwei RTX A6000 eingerichtet und drei Varianten von Qwen3.8-27B heruntergeladen. Volles BF16, eine INT4-Quantisierung und eine INT4-Variante mit MTP für Speculative Decoding. Nach einem Kommentar auf LinkedIn kam noch eine vierte dazu, eine GPTQ-INT4-Variante, die mir dort als qualitativ beste für die A6000 empfohlen wurde. Jetzt kommt die spannende Frage. Welche ist auf meiner Hardware mit ihrer spezifischen Konfiguration wirklich am schnellsten?
Ich messe die Geschwindigkeit sauber und vergleichbar. Als Werkzeug nutze ich llama-benchy, das ich in einem eigenen Beitrag (llama-benchy: LLM-Benchmarks im llama-bench-Stil für jeden OpenAI-kompatiblen Endpoint) vorgestellt habe. Llama-benchy misst gegen jeden OpenAI-kompatiblen Endpoint. Mein vLLM-Server ist genau so einer. Der Clou: llama-benchy behandelt MTP-Chunks korrekt und nutzt echten Buchtext statt Zufallstoken. Damit misst es Speculative Decoding fair würde ich einmal sagen.
Der Aufbau ist einfach. Der vLLM-Server läuft auf meinem Ubuntu-Rechner unter 192.168.2.57. llama-benchy starte ich von meinem Windows-Rechner aus. So sehe ich die Zahlen genau so, wie sie beim Arbeiten über das Netz ankommen.
Die vier Varianten im Überblick
Damit klar ist, was gegeneinander antritt.
| Variante | Modell | Setup |
|---|---|---|
| Full | Qwen/Qwen3.8-27B (BF16) | Zwei Karten, Tensor Parallel |
| GPTQ | abhishekchohan/Qwen3.8-27B-GPTQ-INT4 | Eine Karte, INT4 plus Speculative Decoding |
| Quant | Avesed/Qwen3.8-27B-INT4-W4A16 | Eine Karte, INT4 |
| MTP | Frozenlock/Qwen3.8-27B-int4-AutoRound | Eine Karte, INT4 plus Speculative Decoding |
Wichtig für den fairen Vergleich. Der Tokenizer ist bei allen Varianten identisch. Die Quantisierung ändert ihn nicht. Ich nutze deshalb überall Qwen/Qwen3.8-27B als Tokenizer. So sind die Token-Zahlen sauber vergleichbar.
Vier getrennte systemd-Services
Damit ich schnell zwischen den Varianten wechseln kann, lege ich getrennte Dienste an. So muss ich keine Datei mehr editieren, sondern schalte mit einem Befehl um.
Ein Hinweis vorweg. Die drei INT4-Varianten laufen auf einer Karte. Das steuere ich sauber über Environment=CUDA_VISIBLE_DEVICES. Die NCCL-Zeile und --disable-custom-all-reduce brauche ich dort nicht, weil es ohne zweite Karte nichts zu koordinieren gibt. Nur die Full-Variante hat beides. Und weil jede INT4-Variante nur eine Karte braucht, kann ich sogar zwei davon parallel laufen lassen, eine je Karte auf einem eigenen Port. Genau so habe ich die GPTQ-Variante auf GPU 1 und Port 8001 gemessen, während die MTP-Variante auf GPU 0 stand.
Den Benutzer DEINUSER und den Pfad /mnt/temp_03 passt du an dein System an.
Datei 1: Full (BF16, zwei Karten)
Befehl: sudo nano /etc/systemd/system/vllm-full.service
[Unit]
Description=vLLM Qwen3.8-27B BF16 (TP2)
After=network-online.target
Wants=network-online.target
[Service]
User=DEINUSER
WorkingDirectory=/home/DEINUSER
Environment=HF_HOME=/mnt/temp_03/vLLM/hf
Environment=VLLM_CACHE_ROOT=/mnt/temp_03/vLLM/cache
Environment=HF_HUB_DISABLE_XET=1
Environment=NCCL_P2P_DISABLE=1
Environment=PATH=/home/DEINUSER/vllm-env/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ExecStart=/home/DEINUSER/vllm-env/bin/vllm serve Qwen/Qwen3.8-27B --tensor-parallel-size 2 --max-model-len 131072 --disable-custom-all-reduce --enable-prefix-caching --enable-auto-tool-choice --tool-call-parser qwen3_coder --reasoning-parser qwen3 --default-chat-template-kwargs '{"reasoning_effort": "medium"}'
Restart=on-failure
TimeoutStartSec=1800
[Install]
WantedBy=multi-user.target
Datei 2: GPTQ (INT4 mit Speculative Decoding, eine Karte, Port 8001)
Befehl: sudo nano /etc/systemd/system/vllm-gptq.service
[Unit]
Description=vLLM Qwen3.8-27B GPTQ INT4 MTP (GPU 1, Port 8001)
After=network-online.target
Wants=network-online.target
[Service]
User=DEINUSER
WorkingDirectory=/home/DEINUSER
Environment=HF_HOME=/mnt/temp_03/vLLM/hf
Environment=VLLM_CACHE_ROOT=/mnt/temp_03/vLLM/cache
Environment=HF_HUB_DISABLE_XET=1
Environment=CUDA_VISIBLE_DEVICES=1
Environment=PATH=/home/DEINUSER/vllm-env/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ExecStart=/home/DEINUSER/vllm-env/bin/vllm serve abhishekchohan/Qwen3.8-27B-GPTQ-INT4 --port 8001 --max-model-len 131072 --kv-cache-dtype fp8 --enable-prefix-caching --enable-auto-tool-choice --tool-call-parser qwen3_coder --reasoning-parser qwen3 --trust-remote-code --speculative-config '{"method":"mtp","num_speculative_tokens":3}'
Restart=on-failure
TimeoutStartSec=1800
[Install]
WantedBy=multi-user.target
Zwei Dinge sind hier anders als bei den anderen Ein-Karten-Diensten. CUDA_VISIBLE_DEVICES=1 pinnt diese Variante auf die zweite Karte. Und --port 8001 gibt ihr einen eigenen Port. So kann sie neben der MTP-Variante auf GPU 0 und Port 8000 laufen. Kein --quantization Flag nötig, vLLM erkennt das GPTQ-Format automatisch aus der Config und nimmt auf Ampere den Marlin-Kernel.
Datei 3: Quant (INT4, eine Karte)
Befehl: sudo nano /etc/systemd/system/vllm-quant.service
[Unit]
Description=vLLM Qwen3.8-27B INT4 (1 GPU)
After=network-online.target
Wants=network-online.target
[Service]
User=DEINUSER
WorkingDirectory=/home/DEINUSER
Environment=HF_HOME=/mnt/temp_03/vLLM/hf
Environment=VLLM_CACHE_ROOT=/mnt/temp_03/vLLM/cache
Environment=HF_HUB_DISABLE_XET=1
Environment=CUDA_VISIBLE_DEVICES=0
Environment=PATH=/home/DEINUSER/vllm-env/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ExecStart=/home/DEINUSER/vllm-env/bin/vllm serve Avesed/Qwen3.8-27B-INT4-W4A16 --max-model-len 131072 --kv-cache-dtype fp8 --enable-prefix-caching --enable-auto-tool-choice --tool-call-parser qwen3_coder --reasoning-parser qwen3 --trust-remote-code --default-chat-template-kwargs '{"reasoning_effort": "medium"}'
Restart=on-failure
TimeoutStartSec=1800
[Install]
WantedBy=multi-user.target
Datei 4: MTP (INT4 mit Speculative Decoding, eine Karte)
Befehl: sudo nano /etc/systemd/system/vllm-mtp.service
[Unit]
Description=vLLM Qwen3.8-27B INT4 MTP (1 GPU)
After=network-online.target
Wants=network-online.target
[Service]
User=DEINUSER
WorkingDirectory=/home/DEINUSER
Environment=HF_HOME=/mnt/temp_03/vLLM/hf
Environment=VLLM_CACHE_ROOT=/mnt/temp_03/vLLM/cache
Environment=HF_HUB_DISABLE_XET=1
Environment=CUDA_VISIBLE_DEVICES=0
Environment=PATH=/home/DEINUSER/vllm-env/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ExecStart=/home/DEINUSER/vllm-env/bin/vllm serve Frozenlock/Qwen3.8-27B-int4-AutoRound --quantization auto_round --max-model-len 131072 --kv-cache-dtype fp8 --enable-prefix-caching --enable-auto-tool-choice --tool-call-parser qwen3_coder --reasoning-parser qwen3 --trust-remote-code --speculative-config '{"method":"mtp","num_speculative_tokens":3}'
Restart=on-failure
TimeoutStartSec=1800
[Install]
WantedBy=multi-user.target
Services einlesen und umschalten
Nach dem Anlegen alle Services einlesen.
Befehl: sudo systemctl daemon-reload
Wichtig. Ich aktiviere keinen der Services mit enable. Sonst würden beim Booten mehrere gleichzeitig starten und sich um die Karten streiten. Ich starte immer nur die Dienste von Hand, die ich gerade brauche.
Zum Wechseln stoppe ich erst alle Services, dann starte ich den gewünschten. Beispiel MTP.
Befehl: sudo systemctl stop vllm-full vllm-quant vllm-gptq vllm-mtp
Befehl: sudo systemctl start vllm-mtp
Ob der Server bereit ist, sehe ich im Log. Ich warte auf Application startup complete.
Befehl: journalctl -u vllm-mtp -f
Messen vom Windows-Rechner
Jetzt zur Messung. Auf dem Windows-Rechner brauche ich nur uv. Falls es noch fehlt, installiere ich es einmalig in der PowerShell.
Befehl: powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
Danach läuft llama-benchy direkt über uvx, ohne feste Installation. Der Endpoint ist bei allen Varianten gleich aufgebaut. Nur der Dienst auf dem Server wechselt, und bei der GPTQ-Variante der Port. Der Messbefehl bleibt sonst Wort für Wort identisch, damit die Zahlen vergleichbar sind.
Der Ablauf pro Variante ist immer derselbe. Erst auf dem Server umschalten, dann von Windows aus messen.
Server 192.168.2.57, Variante starten:
Befehl: sudo systemctl stop vllm-full vllm-quant vllm-gptq vllm-mtp
Befehl: sudo systemctl start vllm-mtp
Windows, benchmarken:
Jetzt führe für die Messung den folgenden Befehl auf z. B. Deinem Windowsrechner aus.
Befehl: uvx llama-benchy --base-url http://192.168.2.57:8000/v1 --tokenizer Qwen/Qwen3.8-27B --depth 0 4096 8192 --latency-mode generation --format md
Den --model lasse ich weg. llama-benchy erkennt ihn selbst über den /models-Endpoint. Für die anderen Varianten stoppe ich die alte, starte vllm-full oder vllm-quant und wiederhole exakt denselben Messbefehl. Für die GPTQ-Variante zeigt der Befehl auf Port 8001.
Befehl: uvx llama-benchy --base-url http://192.168.2.57:8001/v1 --tokenizer Qwen/Qwen3.8-27B --depth 0 4096 8192 --latency-mode generation --format md
Ein Hinweis zur Fairness. Beide Karten sind baugleiche A6000, die Zahlen sind also vergleichbar. Und obwohl zwei Dienste gleichzeitig geladen waren, habe ich immer nur einen zur Zeit gemessen. So teilen sich die Karten nicht CPU, PCIe und Stromversorgung während der Messung.
Die Ergebnisse
Hier die Daten der Testläufe als Tabellen für die bessere Übersicht aus llama-benchy, eine je getestete Variante. Die wichtigste Zeile ist tg, die Token-Generation. Das ist das reine Decode-Tempo.
Full (BF16, zwei Karten)
| test | t/s | peak t/s | e2e_ttft (ms) |
|---|---|---|---|
| pp2048 | 2507.80 | — | 925.68 |
| tg32 | 23.78 | 24.00 | — |
| pp2048 @ d4096 | 2346.44 | — | 2727.56 |
| tg32 @ d4096 | 23.51 | 25.00 | — |
| pp2048 @ d8192 | 2265.24 | — | 4629.80 |
| tg32 @ d8192 | 23.54 | 26.00 | — |
GPTQ (INT4 mit Speculative Decoding, eine Karte)
| test | t/s | peak t/s | e2e_ttft (ms) |
|---|---|---|---|
| pp2048 | 1857.06 | — | 1229.25 |
| tg32 | 40.79 | 42.10 | — |
| pp2048 @ d4096 | 1679.00 | — | 3786.58 |
| tg32 @ d4096 | 47.06 | 48.58 | — |
| pp2048 @ d8192 | 1682.59 | — | 6212.20 |
| tg32 @ d8192 | 46.22 | 52.17 | — |
Quant (INT4, eine Karte)
| test | t/s | peak t/s | e2e_ttft (ms) |
|---|---|---|---|
| pp2048 | 1949.64 | — | 1146.58 |
| tg32 | 37.42 | 38.62 | — |
| pp2048 @ d4096 | 1802.71 | — | 3505.49 |
| tg32 @ d4096 | 37.60 | 40.11 | — |
| pp2048 @ d8192 | 1729.89 | — | 6016.02 |
| tg32 @ d8192 | 36.82 | 42.08 | — |
MTP (INT4 mit Speculative Decoding, eine Karte)
| test | t/s | peak t/s | e2e_ttft (ms) |
|---|---|---|---|
| pp2048 | 1859.63 | — | 1215.98 |
| tg32 | 53.44 | 55.16 | — |
| pp2048 @ d4096 | 1766.59 | — | 3593.18 |
| tg32 @ d4096 | 57.38 | 65.59 | — |
| pp2048 @ d8192 | 1700.87 | — | 6134.71 |
| tg32 @ d8192 | 61.95 | 69.94 | — |
Der direkte Vergleich
Jetzt die Zahlen nebeneinander. Zuerst das Decode-Tempo, der wichtigste Wert fürs agentische Arbeiten.
Decode (tg) in Token pro Sekunde
| Kontext | Full (BF16, 2 Karten) | GPTQ (INT4 + Spec, 1 Karte) | Quant (INT4, 1 Karte) | MTP (INT4 + Spec, 1 Karte) |
|---|---|---|---|---|
| 0 | 23.78 | 40.79 | 37.42 | 53.44 |
| 4096 | 23.51 | 47.06 | 37.60 | 57.38 |
| 8192 | 23.54 | 46.22 | 36.82 | 61.95 |
Prefill (pp) in Token pro Sekunde
| Kontext | Full | GPTQ | Quant | MTP |
|---|---|---|---|---|
| 0 | 2508 | 1857 | 1950 | 1860 |
| 4096 | 2346 | 1679 | 1803 | 1767 |
| 8192 | 2265 | 1683 | 1730 | 1701 |
Was die Zahlen sagen
Beim Decode ist die Reihenfolge eindeutig. Full auf zwei Karten ist am langsamsten, mit rund 23,5 Token pro Sekunde. Das bremst die Karten-zu-Karten-Kommunikation ohne NVLink. Die reine INT4-Variante auf einer Karte ist rund 57 Prozent schneller. Und MTP legt noch einmal deutlich drauf. Mit 53 bis 62 Token pro Sekunde ist es grob das 2,5-fache von Full.
Die GPTQ-Variante landet dazwischen. Mit 41 bis 47 Token pro Sekunde ist sie schneller als das reine INT4 ohne Speculative Decoding, aber klar langsamer als Frozenlock. Das ist ein fairer Vergleich, denn beide nutzen den MTP-Kopf. Der Unterschied liegt in der Quantisierung. GPTQ arbeitet hier mit einer feineren Gruppierung von 32 statt 128 Gewichten pro Skalierungsfaktor. Das verspricht mehr Genauigkeit, kostet aber beim Lesen der Gewichte etwas Tempo. In den Zahlen sieht man deutlich das hier das Tempo sinkt.
Zwei Beobachtungen die mir noch aufgefallen sind.
MTP wird mit mehr Kontext schneller. Von 53 auf 62 Token pro Sekunde. Das ist ungewöhnlich, denn normal fällt Decode mit wachsendem Kontext. Der Grund ist die Trefferquote in der Architektur von MTP. Mit mehr Kontext rät der MTP-Kopf sicherer, also werden mehr Spekulationstoken akzeptiert. Bei vorhersehbarem Text stieg der Spitzenwert sogar auf fast 70 Token pro Sekunde. Bei der GPTQ-Variante zeigt sich derselbe Effekt, nur auf niedrigerem Niveau, von 41 auf 47 Token pro Sekunde.
Bei einer Sache gewinnt Full aber. Das Prefill, also die Zeit bis zum ersten Token. Zwei Karten teilen sich hier die rechenintensive Arbeit, und BF16 braucht keine Dequantisierung. Bei 8k Kontext bedeutet das rund 4,6 Sekunden bis zum ersten Token bei Full, gegen rund 6,1 Sekunden bei MTP und 6,2 Sekunden bei GPTQ.
Ein Hinweis zum MTP-Messen den ich hier noch geben möchte. Der Gewinn durch Speculative Decoding hängt stark vom Textinhalt hab der verarbeitet wird. llama-benchy nutzt Sherlock Holmes als Quelle, also Prosa. Bei Code ist die Trefferquote höher. Meine echten Coding-Sessions können also noch besser laufen als der Benchmark hier zeigt. Das erklärt auch die höhere Streuung bei den MTP- und GPTQ-Werten.
Fazit
Für das agentische Coden zählt das Decode-Tempo am meisten. Ein Agent produziert lange Ausgaben über viele Runden. Genau da schlägt MTP alle getesteten Varianten. Das 2,5-fache Decode-Tempo gegenüber dem vollen BF16-Setup, und dazu ist die zweite Karte frei, etwa für ComfyUI.
Der einzige Fall, in dem Full seinen Vorsprung ausspielt, ist ein sehr langer Prompt, bei dem mir die erste Antwortzeit wichtiger ist als das Streaming-Tempo. Für meinen Einsatz mit OpenCode ist das aber wohl eher selten.
Die GPTQ-Variante verdankt ihren Platz im Test einem Kommentar auf LinkedIn. Dort wurde sie mir als qualitativ beste INT4-Quantisierung für die A6000 empfohlen. Beim reinen Tempo liegt sie hinter Frozenlock. Ob die feinere Quantisierung dafür beim Coden sauberer arbeitet, kann ein Geschwindigkeitsbenchmark nicht beantworten. Diese Qualitätstests mit derselben Coding-Aufgabe in OpenCode stehen noch aus. Erst dann weiß ich, ob sich der Verzicht auf etwas Geschwindigkeit lohnt wenn ich im Ergebnis dann doch schneller zum Ziel komme.
Mein vorläufiges Urteil. Die MTP-Variante ist mein Alltagsmodell. Genau die Variante, die ich mir mit dem ganzen Aufwand aus dem vorigen Beitrag erarbeitet habe. Und llama-benchy hat mir den Unterschied zwischen allen vier Varianten nicht nur vermuten lassen, sondern in klaren Zahlen gezeigt.
(Dieser Artikel wurde mit Unterstützung von GenAI geschrieben.)






Ein toller Guide der leicht zugänglich und verständlich ist. Perfekt für ein kleines Side-Project geeignet. Aktuell half mir noch mein…
Thank you for this great tutorial, could you share n8n workflow and comfyui workflow please?
Hallo Anton, die Meldung besagt das in meinem Beisiel Methoden verwendet werden die veraltet (deprecated) sind. Also müsstest Du die…
Danke für das Tool! Ich habe erst kürzlich angefangen mich mit der Thematik zu beschäftigen und bin für meine Erwartungen…
Hallo, ich habe ihre Anleitung befolgt und bekomme im letzten Schritt leider immer folgende Meldung im Terminal: bash <(wget -qO-…