Von Ollama zu llama.cpp
Wie ein llama.cpp-Eigenbau mit MTP die RTX 3090 deutlich schneller macht.
Wer ein großes Sprachmodell lokal betreibt, stößt irgendwann an die Grenzen von Ollama - nicht weil es schlecht wäre, sondern weil es als Komfort-Wrapper bewusst Optionen versteckt, die für maximale Performance nötig sind. Ein Wechsel zu llama.cpp, dem darunterliegenden Inference-Server, mit dem Ziel, aus einer RTX 3090 mehr Tokens pro Sekunde herauszuholen, offenbart dabei sowohl beeindruckende Geschwindigkeitsgewinne als auch einige harte Kompromisse. Im Zentrum steht eine noch recht neue Technik namens Multi-Token Prediction (MTP), die die Antwortgeschwindigkeit von Agenten-Workloads wie Hermes oder OpenCode spürbar erhöht.
Vom Wrapper zum eigenen Build
Ollama kompiliert llama.cpp im Hintergrund bereits mit sinnvollen Standardeinstellungen und bietet dafür Komfortfunktionen wie das schnelle Umschalten zwischen Modellen per API. Wer jedoch experimentelle Flags nutzen will, die noch nicht in Ollama integriert sind, kommt am direkten llama.cpp-Build nicht vorbei. Auf einem Debian-System mit RTX 3090 sieht ein CUDA-Build folgendermaßen aus:
# M. Meister - llama.cpp mit CUDA-Unterstuetzung fuer NVIDIA-GPUs bauen
set -e
apt-get update
apt-get install -y cmake build-essential git
TARGET_DIR="/opt/llama.cpp"
if [ -d "$TARGET_DIR" ]; then
cd "$TARGET_DIR" && git pull
else
git clone https://github.com/ggml-org/llama.cpp.git "$TARGET_DIR"
cd "$TARGET_DIR"
fi
cmake -B build -DGGML_CUDA=ON
cmake --build build --config Release -j"$(nproc)"
ln -sf "$TARGET_DIR"/build/bin/llama-cli /usr/local/bin/llama-cli
ln -sf "$TARGET_DIR"/build/bin/llama-server /usr/local/bin/llama-server
Der Parameter -DGGML_CUDA=ON sorgt dafür, dass beim Kompilieren die NVIDIA-Beschleunigung eingebaut wird; auf Systemen ohne dedizierte GPU entfällt dieser Parameter oder wird durch die passende Backend-Option ersetzt (Metal für Apple Silicon, ROCm für AMD).
Multi-Token Prediction als Geschwindigkeitsschub
Klassische Inferenz generiert ein Sprachmodell Token für Token: Ein kompletter Forward-Pass pro Wortfragment, das ist der limitierende Flaschenhals. Multi-Token Prediction durchbricht dieses Muster, indem das Modell zusätzliche, kleine "Draft-Heads" besitzt, die mehrere zukünftige Token gleichzeitig vorschlagen. Diese Vorschläge werden anschließend in einem einzigen Durchlauf verifiziert - passende Treffer werden im Block akzeptiert, nur bei Abweichungen fällt das System auf klassische Einzelschritte zurück. Support dafür wird über die Parameter --spec-type draft-mtp sowie --spec-draft-n-max aktiviert.
Wichtig dabei: MTP ist keine reine Software-Einstellung, sondern muss bereits beim Pretraining des Modells mitgelernt worden sein. Ein Standard-GGUF eines Modells reicht dafür nicht aus - benötigt wird eine spezielle Variante, die diese zusätzlichen Draft-Tensoren enthält, wie etwa Qwen3.6-27B-MTP-GGUF von Unsloth. Aktuell zählen unter anderem Qwen3.6 und Gemma 4 zu den MTP-fähigen Modellfamilien.
Ollama-Modelle ohne Umweg weiterverwenden
Praktisch: Ollama speichert heruntergeladene Modelle intern bereits als reine GGUF-Dateien ab, lediglich ohne die Dateiendung .gguf. Der entsprechende Blob im Ordner /usr/share/ollama/.ollama/models/blobs/ lässt sich also direkt an llama.cpp übergeben, ohne den Download erneut anzustoßen. Voraussetzung für MTP bleibt allerdings, dass das jeweilige Ollama-Modell tatsächlich mit den passenden Draft-Tensoren erstellt wurde - Standardmodelle enthalten diese meist nicht, da sie beim Quantisieren aus Platzgründen entfernt werden.
Der Wechsel von huggingface-cli zu hf
Wer die MTP-Variante eines Modells stattdessen direkt von HuggingFace laden will, landet bei einer weiteren Neuerung: Das klassische huggingface-cli wurde durch das neue, schlankere Kommandozeilentool hf abgelöst. Die grundlegende Syntax bleibt ähnlich, Befehle rund um Authentifizierung wandern jedoch unter ein gemeinsames hf auth-Präfix:
# M. Meister - MTP-Modell von HuggingFace laden
curl -LsSf https://hf.co/cli/install.sh | bash
source ~/.bashrc
mkdir -p /opt/llama.cpp/models
hf download unsloth/Qwen3.6-27B-MTP-GGUF --include "*Q4_K_M*.gguf" --local-dir /opt/llama.cpp/models
Auf frischen Debian-13-Systemen kollidiert eine parallele Installation über pip gerne mit dem systemweiten Paketmanager, da Debian die von apt verwalteten Python-Pakete gegen Überschreiben absichert. Ein isoliertes virtuelles Environment umgeht dieses Problem sauber, ist bei der direkten Installation über das offizielle hf.co/cli/install.sh-Skript aber ohnehin nicht mehr nötig, da dieses nach ~/.local/bin installiert.
VRAM-Fallstricke bei Kontext und Parallelität
Der größte Stolperstein beim Betrieb für Agenten-Workloads liegt im Zusammenspiel aus Kontextfenster, KV-Cache und paralleler Slot-Nutzung. Ein Modell wie Qwen3.6-27B trainiert zwar mit einem sehr großen nativen Kontext, doch jeder zusätzliche Token im Kurzzeitgedächtnis kostet VRAM - und das potenziert sich mit jedem parallelen Slot. Die 8-Bit-Quantisierung des KV-Cache über --cache-type-k q8_0 und --cache-type-v q8_0 reduziert diesen Bedarf spürbar, ersetzt eine realistische Kontextgröße für eine 24-GB-Karte aber nicht.

Wird der Server ohne Modellpfad gestartet (etwa durch eine leere Variable in einem Skript), springt llama.cpp zudem automatisch in einen sogenannten Router-Modus, der auf ein später dynamisch übergebenes Modell wartet - ein Verhalten, das leicht zu Verwirrung führt, wenn man eigentlich einen klassischen Server-Start erwartet.
Aber diese Neuheit läßt sich nutzen, um einen Nachteil gegenüber ollama auszugleichen: Die Auswahl des Modells über die API oder das Entladen des VRAMs.
Ein Setup, das sich in der Praxis für zwei parallele Agenten-Slots auf einer RTX 3090 bewährt hat:
# M. Meister - llama.cpp Server fuer Agenten-Workloads auf einer RTX 3090
/opt/llama.cpp/build/bin/llama-server \
-m "/opt/llama.cpp/models/Qwen3.6-27B-Q4_K_M.gguf" \
-c 131072 \
-ngl 99 \
-fa on \
--cache-type-k q8_0 \
--cache-type-v q8_0 \
--parallel 2 \
--reasoning-preserve \
--metrics \
--spec-type draft-mtp \
--spec-draft-n-max 2 \
--host 0.0.0.0 \
--port 11434
Der Parameter -ngl 99 schiebt praktisch alle Layer auf die GPU, -fa on aktiviert Flash-Attention, und --metrics öffnet den Endpunkt /metrics, über den sich unter anderem die Annahmequote der gedrafteten Token beobachten lässt.
Ergebnisse im Vergleich
Bei identischem Modell (Qwen3.6-27B, Q4_K_M-Quantisierung) lagen die gemessenen Werte bei Ollama im Schnitt bei knapp 39 Tokens pro Sekunde.
total duration: 1m50.070461029s
load duration: 536.05832ms
prompt eval count: 42 token(s)
prompt eval duration: 250.137ms
prompt eval rate: 167.91 tokens/s
eval count: 4278 token(s)
eval duration: 1m49.271468s
eval rate: 39.15 tokens/sMit dem nativen llama.cpp-Build inklusive MTP stiegen die Werte auf einen Bereich von etwa 56 bis 67 Tokens pro Sekunde - je nach Anteil erfolgreich akzeptierter Draft-Token.
root@ai:/opt/llama.cpp # /opt/llama.cpp/build/bin/llama-server \
-m "/opt/llama.cpp/models/Qwen3.6-27B-Q4_K_M.gguf" \
-c 131072 \
-ngl 99 \
-fa on \
--cache-type-k q8_0 \
--cache-type-v q8_0 \
--parallel 2 \
--reasoning-preserve \
--metrics \
--spec-type draft-mtp \
--spec-draft-n-max 2 \
--host 0.0.0.0 \
--port 11434
0.00.009.484 I cmn common_param: common_params_print_info: verbosity = 3 (adjust with the `-lv N` CLI arg)
...
6.32.644.800 I slot print_timing: id 1 | task 510 | n_decoded = 1414, tg = 52.04 t/s, tg_3s = 56.73 t/s
6.35.669.863 I slot print_timing: id 1 | task 510 | n_decoded = 1605, tg = 53.15 t/s, tg_3s = 63.14 t/s
6.38.688.649 I slot print_timing: id 1 | task 510 | n_decoded = 1789, tg = 53.86 t/s, tg_3s = 60.95 t/s
6.41.718.679 I slot print_timing: id 1 | task 510 | n_decoded = 1960, tg = 54.07 t/s, tg_3s = 56.44 t/s
...Das ist bei meiner Nutzung also im Durchschnitt ein Performance-Gewinn von über 65%. Gerade bei OpenCode wird das besonders deutlich, da MTP meist mit der Behauptung Recht behält, dass nach einer schließenden Klammer meist ein ; und eine neue Zeile folgt. So dauert es nicht mehr eine Stunde, bis ein Programm fertig erstellt ist, sondern lediglich 35 Minuten.
Dieser Sprung liegt deutlich über dem, was durch reine Speicherbandbreite einer RTX 3090 (rund 936 GB/s) für sequenzielle Token-für-Token-Generierung physikalisch zu erwarten wäre, und bestätigt damit, dass MTP tatsächlich mehrere Token pro Durchlauf verifiziert statt sie einzeln zu erzeugen. Bei Agenten-Frameworks wie Hermes oder OpenCode, die viele kurze Anfragen mit strukturierten Ausgaben verarbeiten, macht sich dieser Unterschied besonders bemerkbar.
Die Kehrseite von MTP
Der Geschwindigkeitsgewinn hat einen Preis: In vielen aktuellen llama.cpp-Builds schließen sich MTP und multimodale Eingaben (also Bilderkennung über ein --mmproj-Vision-Modul) gegenseitig aus - wer MTP aktiviert, verliert vorerst die Fähigkeit des Modells, Bilder zu verarbeiten, auch wenn das zugrunde liegende Modell dies eigentlich unterstützt. Neuere llama.cpp-Versionen beheben diese Einschränkung schrittweise, der Fortschritt hängt aber vom jeweiligen Build-Stand ab. Zusätzlich fällt bei einem dedizierten llama.cpp-Server der dynamische Modellwechsel weg, den Ollama über seine API bietet: Ein laufender Server bedient in der Regel genau ein geladenes Modell, während bei Ollama verschiedene Modelle je nach Anfrage automatisch nachgeladen werden können.
Fazit
Der Umstieg von Ollama auf einen selbst kompilierten llama.cpp-Server bringt für Agenten-lastige Workloads auf einer RTX 3090 einen spürbaren Geschwindigkeitsgewinn, der maßgeblich auf Multi-Token Prediction zurückzuführen ist. Wer diesen Weg geht, tauscht dafür bewusst Komfortfunktionen wie dynamischen Modellwechsel und - je nach Build-Stand - Bilderkennung gegen reine Performance ein. Für reine Text-Agenten mit hohem Durchsatzbedarf ist dieser Tausch meist die richtige Entscheidung, für gemischte Multimodal-Workloads lohnt sich vorerst ein Blick auf den aktuellen Entwicklungsstand der Vision-MTP-Kompatibilität.
