# Lokale LLM-Inferenz optimieren: Von 5 auf 100 Token/s mit llama.cpp

> Lokale LLMs schneller machen: RAM-Takt, Quantisierung, KV-Cache, Layer-Placement und MTP-Decoding – die wirksamsten llama.cpp-Hebel nach Impact sortiert.

- URL: https://thevibe-coding.de/guides/lokale-llm-inferenz-optimieren-llama-cpp-2026
- Typ: guides | Veroeffentlicht: 2026-07-16 | Aktualisiert: 2026-07-16
- Autor: Vita Legne | Site: VIBE CODING — thevibe-coding.de

---

# Lokale LLM-Inferenz optimieren: Von 5 auf 100 Token/s mit llama.cpp

**Lokale LLM-Inferenz** heißt: Ein [Sprachmodell](/glossar/llm) läuft zu
100 % auf deiner eigenen Hardware — Prompts verlassen nie deinen Rechner.
Homelab-Entwickler Kartikey Chauhan dokumentierte im Juni 2026, wie
Gemma 4 26B auf einer RTX 4070 (12 GB) von 38,5 auf über 100 Token/s
beschleunigt. Dieser Guide sortiert seine wirksamsten Hebel nach Impact —
inklusive Vision, Multi-GPU und Quant-Messung.

Alle konkreten Messwerte stammen aus Chauhans Referenz-Setup: RTX 4070
(12 GB), Intel i5-12600K, 32 GB DDR5-6000, Linux mit CUDA und aktuellem
llama.cpp-Build. Auf anderer Hardware verschieben sich die Zahlen, die
Mechanik dahinter bleibt gleich. Zur Einordnung der Kosten: Hosted APIs
liegen bei 1–15 US-Dollar pro Million Token, lokale Inferenz kostet Strom
plus einmalig 500–3.000 US-Dollar Hardware — dafür gewinnst du
Datenschutz, Offline-Betrieb und freie Modellwahl ohne Rate-Limits. Die
meisten Power-User fahren zweigleisig: Cloud für Frontier-Aufgaben, lokal
für alles Sensible und Experimentelle.

## Was du brauchst

- Eine GPU mit mindestens 8 GB VRAM (NVIDIA/CUDA für diesen Guide; AMD und
  Apple Silicon funktionieren mit anderen Backends)
- 32 GB System-RAM oder mehr, wenn du MoE-Modelle mit CPU-Offload fahren willst
- Linux bevorzugt (15–20 % schneller als Windows), Windows geht mit
  angepasstem Energieprofil
- 2 Stunden Zeit für Build, Setup und erste Benchmarks

## Die drei Kennzahlen: TTFT, PP und TG

Optimieren ohne Messen ist Stochern im Nebel. Lokale
[Inferenz](/glossar/inference) hat drei Phasen mit unterschiedlichen
Engpässen: **TTFT** (Time to First Token) — wie lange bis zur ersten
Ausgabe. **PP** (Prompt Processing) — wie schnell das Modell deinen Input
liest, GPU-limitiert. **TG** (Token Generation) — wie schnell die Antwort
strömt, limitiert durch Speicherbandbreite. TG ist das, was du beim
Arbeiten spürst.

| TG-Geschwindigkeit | Gefühl |
|---|---|
| unter 5 Token/s | quälend, kaum nutzbar |
| 5–10 Token/s | funktional — Lesegeschwindigkeit liegt bei ~7 Token/s |
| 10–20 Token/s | angenehm für interaktiven Chat |
| 20–40 Token/s | Coding-Agents fühlen sich flott an |
| über 40 Token/s | quasi instant |

Zum Messen bringt llama.cpp eigene Werkzeuge mit: `llama-bench` für
synthetische PP/TG-Benchmarks, `llama-fit-params` als Trockenlauf für die
VRAM-Verteilung und `llama-server` mit Timing-Ausgabe im Log. Benchmarke
immer bei der Kontextlänge, die du wirklich nutzt — kurze Test-Prompts
verstecken KV-Cache-Kosten, Speicherwachstum in langen Sessions und die
Kosten paralleler Slots.

## Die Prioritäten-Checkliste: 10 Hebel nach Impact sortiert

Wer nur fünf Minuten hat, arbeitet diese Liste von oben ab — sie sortiert
alle Maßnahmen dieses Guides nach typischem Effekt, gemessen auf dem
RTX-4070-Referenzsystem:

| # | Maßnahme | Typischer Effekt |
|---|---|---|
| 1 | XMP/EXPO im BIOS aktivieren | bis zu 2–3× TG, wenn RAM auf Basistakt lief |
| 2 | MTP-Speculative-Decoding | 2,0–2,6× TG bei Gemma 4 / Qwen 3.6 |
| 3 | QAT-Q4-Modelle statt PTQ-Q4 | Q8-nahe Qualität, ~20 % kleinere Datei |
| 4 | Linux statt Windows (oder Energieprofil tunen) | ~15–20 % TPS |
| 5 | `tuned-ppd` statt `power-profiles-daemon` | eliminiert 20–30 % TG-Schwankung |
| 6 | llama.cpp frisch aus Source bauen | MoE-Kernel-Gewinne pro Release |
| 7 | `--fit on` für VRAM-Placement | maximale GPU-Layer ohne Handarbeit |
| 8 | KV-Cache auf `q8_0` | halbiert KV-VRAM, +1–2 GPU-Layer |
| 9 | `--parallel 1` (Einzelnutzer) | KV-VRAM zurück für Gewichte |
| 10 | P-Core-Pinning per `taskset` | +20–30 % TG auf Intel-Hybrid |

Danach folgen Feinschliff-Maßnahmen: `--flash-attn on` (Pflicht für lange
Kontexte), `--no-mmap`/`--mlock`, Headless-Betrieb, ubatch-Sweeps und
N-Gram-Decoding für Code-Sessions.

## Tool-Wahl: llama.cpp, Ollama, LM Studio oder vLLM?

llama.cpp ist das Werkzeug für maximale Kontrolle — jede Stellschraube in
diesem Guide setzt darauf auf. Ollama nutzt llama.cpp intern, verdeckt aber
genau die Flags, um die es hier geht: Layer-Placement, KV-Quantisierung und
Batch-Größen sind dort nicht erreichbar. LM Studio bietet die beste
Desktop-Oberfläche samt OpenAI-kompatiblem Endpoint inklusive
Headless-Betrieb, JIT-Loading und Auto-Evict. vLLM zielt auf
Multi-User-Serving mit voller VRAM-Bestückung und kontinuierlichem
Batching — für Consumer-Hybrid-Setups ungeeignet. exllamav2 ist die
schnellste Option für Dense-Modelle, die komplett ins VRAM passen
(CUDA-only).

| Tool | Stärke | Schwäche |
|---|---|---|
| llama.cpp | Volle Flag-Kontrolle, jede Hardware | CLI-zentriert, Build nötig |
| Ollama | Zero-Config, Modellverwaltung, Docker | Kaum Tuning möglich |
| LM Studio | GUI, Modell-Browser, lokale API | Weniger Detailkontrolle |
| vLLM | Produktions-Serving, Batching | Braucht viel VRAM, nichts für Hybrid-Setups |
| exllamav2 | Maximaltempo für Dense-Modelle im VRAM | CUDA-only, kein Offload |
| MLX | Apple Silicon, Unified Memory | Nur macOS |

Innerhalb von llama.cpp wählt das Backend die Hardware: CUDA für NVIDIA
(am besten getestet), ROCm/HIP oder Vulkan für AMD, Metal automatisch auf
macOS, SYCL für Intel Arc. Apple Silicon verändert die Größenrechnung
komplett: CPU und GPU teilen sich denselben Speicherpool, ein Mac mit
128 GB RAM hat effektiv 128 GB "VRAM" bei ~400 GB/s Bandbreite (M3 Max).

## Hardware-Basics: Speicher-Hierarchie schlägt alles

Token-Generierung ist bandbreitenlimitiert: Für jeden einzelnen Token
müssen alle aktiven Gewichte durch den Speicher gestreamt werden. Die
Hierarchie entscheidet, wie schnell das geht:

```text
VRAM (GPU)                ~600–1.000 GB/s
Unified Memory (Apple)     ~200–400 GB/s
System-RAM                  ~50–200 GB/s   (Takt + Kanäle!)
NVMe-SSD                      ~5–7 GB/s
SATA-SSD / HDD              ~0,5–3 GB/s
```

Dense-Modelle (Gemma 4, Llama 3, Mistral) lesen pro Token *alle*
Parameter — sie müssen für volles Tempo komplett ins VRAM.
[MoE-Modelle](/glossar/open-source-modell) (Qwen3, DeepSeek, gpt-oss)
aktivieren pro Token nur einen Bruchteil: gpt-oss-120b rechnet mit ~5B von
120B Parametern, Qwen3-Coder-Next mit ~3B von 80B. Deshalb dürfen
Experten-Gewichte in den System-RAM ausweichen — und deshalb wird dessen
Bandbreite zum Flaschenhals.

| VRAM | Dense-Modelle | MoE-Hybrid |
|---|---|---|
| 8 GB | 7B–13B Q4 | 30B–70B mit viel RAM-Offload |
| 12 GB | 13B–20B Q4, 7B Q8 | 70B–120B+ mit CPU-Offload |
| 24 GB | 34B Q4, 13B Q8 | 120B+ mit moderatem Offload |
| 48 GB+ | 70B Q8, 34B FP16 | Meiste MoE (fast) komplett auf GPU |

Zwei Hardware-Tricks kosten nichts: Den Monitor an den
Mainboard-Videoausgang (iGPU) statt an die Grafikkarte hängen — das gibt
500–1.000 MB VRAM frei, die sonst der Desktop frisst. Und bei
Dense-Modellen komplett im VRAM ist die CPU fast arbeitslos; bei
MoE-Hybrid rechnet sie dagegen jeden Token mit.

## Hebel 1 — RAM-Takt: XMP aktivieren bringt bis zu 3× mehr Token

Der fieseste Standardfehler zuerst: Viele BIOS-Setups fahren RAM auf
JEDEC-Basistakt statt auf dem beworbenen Profil. Auf Chauhans Maschine
lief DDR5-6000 ohne XMP auf etwa einem Drittel der TG-Leistung — ein
einziger BIOS-Schalter später war sie wieder normal. Bei MoE-Modellen mit
RAM-Offload gibt es keinen anderen Hebel mit diesem Impact.

```bash
sudo dmidecode -t memory | grep -E "Speed|Configured"
# "Configured Memory Speed" muss dem XMP/EXPO-Profil entsprechen.
# Falls nicht: XMP (Intel) bzw. EXPO (AMD) im BIOS aktivieren.
```

Eine Minute Prüfzeit erspart hier Stunden Tuning an der falschen Stelle —
deshalb steht dieser Check an Position 1.

## Hebel 2 — llama.cpp selbst bauen statt Distro-Paket

Paketquellen liefern veraltete Builds, die nicht für deine GPU kompiliert
sind. Die MoE-Kernel von llama.cpp werden mit praktisch jedem Release
schneller — vor jedem Benchmark lohnt ein `git pull` plus Rebuild. Der
CUDA-Build für eine RTX-40-Karte (Compute Capability 89):

```bash
git clone https://github.com/ggml-org/llama.cpp
cd llama.cpp && mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DGGML_CUDA=ON \
  -DGGML_NATIVE=ON -DGGML_LTO=ON -DGGML_CUDA_GRAPHS=ON \
  -DGGML_CUDA_FA=ON -DGGML_CUDA_FA_ALL_QUANTS=ON \
  -DCMAKE_CUDA_ARCHITECTURES=89
cmake --build . --config Release \
  --target llama-server llama-bench llama-fit-params --parallel
```

Die Architektur-Nummer nicht blind übernehmen: 89 gilt für Ada/RTX 40,
ältere Karten brauchen andere Werte (NVIDIA-Tabelle prüfen); bei
gemischten Karten eine Semikolon-Liste wie `"86;89"` übergeben. AMD-GPUs
bauen mit `-DGGML_HIP=ON` (ROCm) oder `-DGGML_VULKAN=ON`; für portable
Binaries `GGML_NATIVE` abschalten oder mit `-DGGML_BACKEND_DL=ON` Backends
zur Laufzeit laden. Ein Detail für später: `GGML_CUDA_FORCE_CUBLAS`
klingt nach mehr Tempo, ist auf Consumer-Hardware aber langsamer als die
GGML-eigenen MMQ-Kernel — Chauhan maß ~45 Token/s PP-Regression ohne
TG-Gewinn.

## Hebel 3 — Quantisierung: Q5 als Standard, QAT wenn verfügbar

Quantisierung reduziert die Gewichts-Präzision und damit Dateigröße und
Speicherbedarf. Faustregel: die höchste Quantisierung nehmen, die ins
VRAM+RAM-Budget passt. Q8_0 ist praktisch verlustfrei bei 65 % der
FP16-Größe, Q5_K_XL ein starker Default bei ~40 %, Q4_K_M der übliche
Kompromiss bei ~35 % — und Q2_K merklich degradiert.

| Quant | Größe vs. FP16 | Qualität |
|---|---|---|
| Q8_0 | ~65 % | praktisch verlustfrei |
| Q6_K | ~50 % | nahezu verlustfrei |
| Q5_K_M / Q5_K_XL | ~40 % | sehr nah an FP16 — starker Default |
| Q4_K_M / UD-Q4_K_XL | ~35 % | guter Kompromiss |
| IQ3 / IQ4 | ~25–35 % | oft besser als ältere Quants gleicher Größe |
| Q2_K | ~25 % | merklich schlechter |
| MXFP4 (nativ) | ~35 % | besser als Q4_K_M — gpt-oss ist darin trainiert |

Ein Sonderfall verdient Aufmerksamkeit: **QAT** (Quantization-Aware
Training). Dabei lernt das Modell schon im Training mit
Quantisierungsrauschen umzugehen, statt nachträglich gerundet zu werden.
Chauhans Gemma-4-QAT-Tests zeigen 4-Bit-Verhalten nahe Q8-Qualität — und
das 26B-Modell schrumpft von ~18 GB auf ~14,2 GB, wodurch deutlich mehr
Layer direkt ins VRAM passen. **Unsloth-Dynamic-Quants** (UD-Präfix)
verfolgen einen verwandten Ansatz beim Packen: empfindliche Tensoren
behalten mehr Präzision, robuste werden stärker komprimiert. **iMatrix-
und IQ-Quants** kalibrieren den Quantisierer an repräsentativem Text —
wichtig zu wissen: Eine Wiki-Kalibrierung und eine Code/Chat-Kalibrierung
schützen unterschiedliches Verhalten.

## Quant-Qualität messen: Perplexity, KLD und die letzte Instanz

Dateigröße und Token/s sind leicht zu messen, Qualität nicht. Drei
Metriken helfen bei der Vorauswahl, ersetzen aber keinen Praxistest.
**Perplexity (PPL)** taugt als Rauchtest: Fällt ein Quant deutlich hinter
gleich große Alternativen zurück, ist etwas kaputt — PPL kann aber
Antwort-Flips verstecken, weil sich bessere und schlechtere
Token-Wahrscheinlichkeiten ausmitteln. **KLD** (KL-Divergenz) vergleicht
die Ausgabe-Verteilung des Quants mit dem Original und erwischt diesen
Drift zuverlässiger; Unsloth stützt seine Dynamic-GGUF-Analysen darauf.
Und selbst hohe Top-1-Übereinstimmung heißt nur "gleicher nächster Token
wie die Referenz", nicht "faktisch richtig".

| Metrik | Gut für | Blinder Fleck |
|---|---|---|
| Dateigröße / BPW | Passt-es-Planung | Sagt nichts über Qualität |
| PPL | schneller Regressionstest | übersieht Antwort-Flips |
| KLD | Verteilungs-Drift vs. Original | hängt an Kalibrierdaten |
| Task-Evals (Aider, LiveCodeBench) | Aufgaben-Nähe | langsam, Template-fragil |
| Dein Workload | die echte Antwort | musst du selbst fahren |

Die Falle heißt Kalibrierungs-Overfit: Sehen iMatrix und Evaluation beide
nach WikiText aus, glänzt ein Quant auf dem Papier und schwächelt bei
Code, Chat oder Tool-Calls. Deshalb: nach Größe, PPL/KLD und
Maintainer-Vertrauen vorsortieren — die finale Entscheidung fällt bei
deiner Kontextlänge mit deinen Sampling- und KV-Einstellungen.

## Hebel 4 — Layer-Placement: --fit, -ot und die Shared-Expert-Falle

Layer-Placement ist bei MoE-Modellen der größte Software-Hebel: möglichst
viele Blöcke auf die GPU, Experten-Gewichte in den RAM. Drei Werkzeuge mit
steigender Präzision: `-ngl` setzt die Zahl der GPU-Layer (99 = alles,
runter bei OOM), `--n-cpu-moe N` legt die Experten der ersten N Layer auf
die CPU, und `-ot`/`--override-tensor` platziert per Regex einzelne
Tensoren:

```bash
# Alle Experten-Projektionen aller Layer auf die CPU:
--override-tensor ".ffn_(up|down|gate)_(ch|)exps=CPU"
```

Das `(ch|)` im Muster ist kein Tippfehler, sondern die
**Shared-Expert-Falle**: Manche Modelle (Qwen3.5-122B, einige
gpt-oss-Varianten) haben neben den gerouteten Experten (`_exps`) einen
immer aktiven Shared Expert (`_shexp`) pro Layer. Ein Regex, das nur
`_exps` trifft, lässt `_shexp` still im VRAM liegen — und produziert
CUDA-OOM, das niemand versteht. Vorsicht auch bei `--n-cpu-moe`: Bei
einem 60-GB-Modell alle Experten auf die CPU zu legen, versucht 60 GB in
den RAM zu laden und legt einen 64-GB-Rechner hart lahm.

Bequemer ist `--fit on`: misst freies VRAM beim Start und berechnet die
optimale Verteilung inklusive KV-Cache automatisch. `llama-fit-params`
macht dasselbe als Trockenlauf und gibt die fertigen Flags aus — die
hartkodierst du dann im Server-Skript. Faustregel: `--fit on` zum
Experimentieren und nach Hardware-Wechseln, statisches Placement für den
Dauerbetrieb. `--fit-target` nicht unter 512 MiB setzen: Der
CUDA-Speicherpool wächst mit gefülltem Kontext, und zu wenig Reserve
führt zu OOM mitten in der Session statt beim Start.

## Hebel 5 — Kontext und KV-Cache: das VRAM-Budget verteidigen

Der KV-Cache speichert die Attention-Tensoren des bisherigen
[Kontexts](/glossar/context-window), wächst linear mit und liegt im VRAM.
Auf einer 12-GB-Karte frisst 128k-Kontext in f16 ganze 8 GB — es bleiben
4 GB für das Modell. Kontextwahl ist also Placement-Politik:
Coding-Sessions fahren gut mit 64k, RAG braucht eher 128k+.

| Kontext | f16-KV | q8_0-KV |
|---|---|---|
| 8k | ~0,5 GB | ~0,25 GB |
| 32k | ~2 GB | ~1 GB |
| 64k | ~4 GB | ~2 GB |
| 128k | ~8 GB | ~4 GB |

Als konservative Baselines für einen Einzelnutzer-Server haben sich diese
Profile bewährt — Startpunkte, keine Optimallösungen:

| Workload | `--fit-target` | Kontext | KV-Cache | `--parallel` | Batch |
|---|---|---|---|---|---|
| Text, 12 GB VRAM | 512 MiB | 64k | q8_0/q8_0 | 1 | 1024 |
| Text, 24 GB VRAM | 512–768 MiB | 128k | q8_0/q8_0 | 1–2 | 1024 |
| Vision, 12 GB VRAM | 2048 MiB | 64k | q8_0/q8_0 | 1 | 256 |
| MTP-Speculative | 512+ MiB | 64k | pro Modell testen | 1 | 1024 |

Vier Flags entscheiden das Budget. `-ctk q8_0 -ctv q8_0` halbiert den
KV-Cache praktisch verlustfrei — die frei gewordenen 2 GB bei 64k
bedeuteten auf Qwen3-Coder zwei zusätzliche GPU-Layer und ~2 Token/s mehr
TG (q4_0 nur unter extremem Druck: degradiert bei langem Kontext).
`--parallel 1` gilt für Einzelnutzer: Jeder Slot hält einen eigenen
KV-Cache; der Schritt von 4 auf 1 Slot sparte bei gpt-oss-120b ~540 MiB —
genug für einen weiteren GPU-Layer und +1 Token/s. `--flash-attn on`
reduziert den Attention-Speicherverkehr und ist für stabile lange Kontexte
Pflicht (auf CUDA ohne Nachteil; unter Vulkan treiberabhängig). Und
`--ctx-size` ehrlich wählen statt maximal: Jedes ungenutzte
Kontext-Gigabyte ist ein verschenkter GPU-Layer.

## Batch-Größen: --ubatch-size ist kein Naturgesetz

Batch-Parameter steuern die Prefill-Phase. `--batch-size` (logischer
Batch) bestimmt, wie viele Tokens pro Forward-Pass verarbeitet werden:
2048 für maximalen PP-Durchsatz, 1024 als Default, 512 bei knappem VRAM.
`--ubatch-size` (physischer Micro-Batch, ≤ batch-size) legt fest, wie
diese Arbeit gestückelt wird — größer kann PP beschleunigen, erhöht aber
das VRAM-Maximum während des Prefills. Der Wert 512 ist ein sicherer
Default, kein Gesetz:

```bash
for ub in 128 256 512 1024; do
  ./build/bin/llama-bench -m model.gguf \
    -p 2048 -n 128 -b 1024 -ub "$ub" \
    -ngl 99 -ctk q8_0 -ctv q8_0 -fa on
done
```

Die zwei besten Werte danach im echten `llama-server` gegentesten —
Server-Speicherlayout, `--parallel` und Prompt-Cache verschieben das
Ergebnis. Bei CUDA-OOM ausgerechnet während des Prefills zuerst
`--batch-size` senken.

## Sampling-Parameter: Modell-Defaults schlagen Bastelei

Sampling formt die Wahrscheinlichkeitsverteilung bei jedem Decode-Schritt
und beeinflusst primär Qualität, kaum Tempo. Die wichtigste Regel steht in
jeder Model-Card: Nimm die getesteten Defaults des Herstellers, bevor du
experimentierst. [Temperature](/glossar/temperature) 0.0 heißt
deterministisch (gut für reproduzierbare Coding-Agents), 1.0 folgt der
rohen Modellverteilung — darauf sind die meisten modernen Instruct-Modelle
kalibriert. `top-k 100` ist ein sicherer Performance-Deckel ohne messbaren
Qualitätsverlust (auf gpt-oss-120b verifiziert). Und `repeat-penalty`
gehört für Code auf 1.0: Code wiederholt naturgemäß Variablennamen und
Keywords — wer das bestraft, verschlechtert die Ausgabe.

| Modell | temp | top-k | top-p | min-p | repeat-penalty |
|---|---|---|---|---|---|
| Gemma 4 | 1.0 | 64 | 0.95 | 0.0 | 1.0 |
| Qwen3 / Qwen3-Coder | 1.0 | 40 | 0.95 | 0.01 | 1.0 |
| gpt-oss-120b | 1.0 | 100 | 1.0 | 0.0 | 1.0 |

## Hebel 6 — CPU-Kontrolle: P-Cores pinnen, Threads begrenzen

Intel-CPUs ab der 12. Generation mischen P-Cores und E-Cores — und
E-Cores rechnen Matrix-Operationen deutlich langsamer. Landet der
Inferenz-Prozess auf E-Cores, kostet das 20–30 % Token-Generierung bei
MoE-Hybrid-Setups, wo die CPU jeden Token mitrechnet. Die Lösung ist ein
Einzeiler:

```bash
taskset -c 0-11 llama-server ...   # i5-12600K: Kerne 0–11 sind P-Cores
```

Dazu `--threads` auf P-Core-Anzahl minus 1–2 setzen — mehr Threads als
P-Cores verschlechtern das Ergebnis, weil alle um denselben Speicherbus
konkurrieren. Für die Prefill-Phase darf `--threads-batch` dagegen die
volle Thread-Zahl nutzen. Zwei Flags, die du dir sparen kannst: `--poll`
ist bei Hybrid-CPU+GPU-Inferenz komplett wirkungslos (über mehrere Sweeps
bestätigt — GPU-Kernel und PCIe dominieren die Synchronisation), und
`--numa` bringt auf Single-Socket-Systemen nichts bis Gegenteiliges; das
Thema wird erst auf Dual-Socket-Servern (EPYC, Xeon) real.

## Speicher festnageln: --no-mmap und --mlock

Standardmäßig lädt llama.cpp Modelle per Memory-Mapping — elegant, aber
bei MoE-Decode tückisch: Experten-Zugriffe sind nicht sequenziell, kalte
Pages lösen ständig Page-Faults aus, und die TG-Rate zittert.
`--no-mmap` lädt das komplette Modell vor Inferenzbeginn in den RAM;
der Start dauert länger, dafür läuft jeder persistente Server ruhiger.
`--mlock` pinnt die Modell-Pages zusätzlich gegen Swapping — wichtig,
weil viele Distributionen `vm.swappiness` auf 60–150 mit ZRAM setzen. Ohne
`--mlock` kann ein Swap-Ereignis mitten in der Session die Generierung
scheinbar einfrieren. Abgerundet wird das Server-Profil mit `--prio 2`
(höhere Scheduling-Priorität gegen OS-Jitter) und `--no-warmup`
(schnellerer Start; CUDA-Kernel kompilieren beim ersten echten Request).

## Betriebssystem-Tuning: Linux schlägt Windows um 15–20 %

Linux liefert bei CUDA-Inferenz in der Praxis 15–20 % mehr Durchsatz:
schlankerer Treiber-Overhead, besseres Scheduling unter Dauerlast, volle
Kontrolle über CPU-Governor und Speicher. Unter Windows hilft das
Energieprofil "Höchstleistung" plus "Prefer maximum performance" im
NVIDIA-Panel; WSL2 kommt CUDA-seitig nah an nativ heran. Auf Linux lauert
dafür eine besonders fiese Falle: KDE und GNOME installieren
`power-profiles-daemon`, der auf manchen Boots einen gedrosselten
Hardware-P-State setzt — alle sysfs-Checks melden brav "performance",
trotzdem fehlen 20–30 % TG, mal ja, mal nein. Die Drosselung passiert auf
MSR-Ebene, wo Standard-Tools nicht hinschauen. Der Fix:

```bash
sudo apt install tuned          # Ubuntu/Debian; ersetzt power-profiles-daemon
sudo systemctl enable --now tuned
sudo tuned-adm profile throughput-performance
```

Drei weitere Linux-Stellschrauben: Transparent Huge Pages auf `always`
(`echo always | sudo tee /sys/kernel/mm/transparent_hugepage/enabled`),
Headless-Betrieb per `systemctl isolate multi-user.target` (stoppt den
Compositor, gibt 200–400 MB RAM plus Compositor-VRAM frei; `zellij` im
TTY ersetzt die Fenster) — und der iGPU-Trick aus dem Hardware-Kapitel
spart zusätzlich 500–1.000 MB VRAM.

## Hebel 7 — Speculative Decoding: 2,6× schneller mit MTP

Speculative Decoding umgeht das Bandbreiten-Limit der Token-Generierung:
Ein leichtes Draft-Modell rät mehrere Folge-Tokens, das Hauptmodell
verifiziert sie in einem einzigen Forward-Pass. Modelle mit nativen
Multi-Token-Prediction-Köpfen (Gemma 4, Qwen 3.6) bringen ihr Draft-Modell
gleich mit — bei Gemma 4 26B ist es nur ~460 MB groß. Die Zahlen von der
RTX 4070: Gemma 4 26B springt von 38,5 auf 100,6 Token/s (2,6×), das
12B-Modell erreicht 120,8 Token/s (2,0×).

```bash
llama-server -m gemma-4-26B.gguf \
  --spec-draft-model mtp-gemma-4-26B.gguf \
  --spec-type draft-mtp \
  --spec-draft-n-max 2      # 26B: 2; leichtere Modelle (12B): 4
```

Ein Fallstrick: Target- und Draft-KV-Cache sind getrennte Baustellen
(`-ctk/-ctv` vs. `-ctkd/-ctvd`). Bei Gemma 4 drückte ein quantisierter
Target-Cache die Draft-Akzeptanz gegen null — f16 kostete mehr VRAM, hielt
die Akzeptanz aber über 70 % und war unterm Strich klar schneller. Rohe
Token/s reichen als Messwert nicht; Akzeptanzrate immer mitloggen.

Für Coding-Sessions gibt es zusätzlich **draftloses** Speculative
Decoding: N-Gram-Modi suchen wiederkehrende Token-Muster im Kontext —
und Code wiederholt sich nun mal (Imports, Funktionsnamen, Boilerplate).
`--spec-type ngram-mod` mit `--spec-ngram-mod-n-match 24` ist der
interessanteste Startpunkt für persistente Server; `ngram-simple` reicht
für Einzel-Session-Tests. Beide lassen sich mit MTP kombinieren
(`--spec-type draft-mtp,ngram-mod`) — aber nicht blind übernehmen:
Lange Drafts verschwenden Arbeit, wenn die Akzeptanz schlecht ist. Messen,
nicht glauben.

## Coding-Agents lokal: diese Metriken zählen wirklich

Für Coding-Workloads ist TG nur die halbe Wahrheit. Agent-Loops lesen
Dateien, feuern Tool-Calls und schieben immer wieder ähnlichen Kontext
durch den Server — damit rücken TTFT, PP und der Prompt-Cache ins
Zentrum: Startet die Ausgabe nach einem Tool-Call schnell? Verdaut der
Server 8k–64k Code-Kontext ohne Gedenkpause? Greift der Prompt-Cache bei
wiederholtem Agent-Kontext tatsächlich? Bleiben VRAM und RAM nach 30–60
Minuten Session flach? Ein brauchbarer Schnelltest in vier Akten: kalter
Prompt nach Server-Start, gleicher Prompt mit warmem Cache, eine kleine
Inspect-Edit-Explain-Schleife, ein langer Prompt nahe der echten
Kontextgröße. Wer Profile veröffentlicht oder vergleicht, notiert
mindestens: Modell, Quant, llama.cpp-Commit, Kommandozeile, Kontext,
Batch/ubatch, KV-Präzision, PP, TG, TTFT, Draft-Akzeptanz und VRAM nach
langer Session — "fühlt sich schnell an" ist kein Benchmark.

## Vision-Modelle: der Projektor braucht eigenen Platz

Multimodale Modelle laden neben den Gewichten einen Projektor
(`--mmproj`, typisch 1–3 GB VRAM), und genau der produziert die zwei
klassischen Fehlerbilder auf knappen Karten. Fehlerbild eins: Crash beim
Laden, weil ein alter Build oder ein ohne Projektor berechnetes statisches
Placement die mmproj-Allokation nicht einplant — aktuelle llama.cpp-Builds
rechnen sie in `--fit` ein, also Build aktualisieren und `--fit` mit
Projektor laufen lassen. Fehlerbild zwei: Assertion beim ersten Bild, denn
ein Bild tokenisiert zu mehreren hundert Tokens — ist `--ubatch-size`
kleiner als die Bild-Token-Zahl, bricht llama.cpp ab. Deshalb
`--ubatch-size 512` oder höher. Chauhans stabiles 12-GB-Profil:

```bash
llama-server -m model.gguf --mmproj mmproj.gguf \
  --ctx-size 65536 --fit on --fit-ctx 65536 --fit-target 2048 \
  -ctk q8_0 -ctv q8_0 --flash-attn on \
  --batch-size 256 --ubatch-size 512 \
  --no-mmap --mlock --parallel 1
```

Die 2048 MiB Fit-Reserve sind bewusst großzügig; Text- und Vision-Server
auf derselben GPU besser auf getrennten Ports fahren.

## Multi-GPU: layer zuerst, tensor mit Vorsicht

llama.cpp verteilt Modelle mit drei Split-Modi auf mehrere Karten — und
die langweilige Option gewinnt meistens. `--split-mode layer` legt
zusammenhängende Layer-Gruppen auf verschiedene GPUs: kompatibelster
Modus, erster Versuch, bei ungleichen Karten mit `--tensor-split 3,1`
gewichtbar (GPU 0 bekommt 75 %). `row` ist upstream veraltet — für neue
Setups ignorieren. `tensor` (echtes Tensor-Parallel) kann die TG-Latenz
bei Dense-Modellen mit schnellem Interconnect senken, hat aber harte
Auflagen: viele MoE-Architekturen brechen mit "not implemented" ab,
quantisierter KV-Cache wird nicht unterstützt (f16/bf16/f32 Pflicht), und
`--fit` funktioniert nicht — Kontext, Slots und Layer verwaltest du
selbst. `GGML_CUDA_P2P=1` kann Peer-Transfers beschleunigen, auf manchen
Systemen aber crashen oder Ausgaben korrumpieren: erst testen, dann
behalten. Ist Multi-GPU langsamer als eine Karte, ist fast immer der
Interconnect der Flaschenhals.

Am äußersten Rand der Tuning-Skala liegt der **ik_llama.cpp-Fork** von
Ikawrakow: MoE-spezifische Kernel-Optimierungen (u. a. fusionierte
MoE-Kernel) und oft die erste Adresse für neue IQ/K-Quant-Verfahren,
besonders stark bei CPU- und Hybrid-MoE-Läufen. Nichts davon fließt
upstream zurück — der Fork lohnt erst, wenn die Standard-Konfiguration
ausgereizt ist.

## Was tun, wenn es nicht funktioniert?

| Symptom | Ursache | Fix |
|---|---|---|
| TG schwankt 20–30 % zwischen Boots | `power-profiles-daemon` drosselt HWP | `tuned-ppd` + `throughput-performance` |
| TG stabil, aber weit unter Soll | XMP/EXPO aus, RAM auf Basistakt | Speicherprofil im BIOS aktivieren |
| TG niedriger als P-Core-Baseline | E-Cores rechnen mit | `taskset -c` auf P-Cores |
| OOM mitten in der Session | `--fit-target` zu klein | auf ≥ 512 MiB erhöhen |
| Intermittierendes OOM bei langen Prompts | `GGML_CUDA_GRAPH_OPT=1` | auf `0` setzen; nur nach A/B-Test aktivieren |
| TG bricht nach Minuten ein | Modell wird geswappt | `--mlock` setzen, RAM prüfen |
| Vision-Modell crasht beim Laden | mmproj nicht eingeplant | llama.cpp updaten, `--fit` mit mmproj |
| Vision-Assertion beim ersten Bild | `--ubatch-size` < Bild-Tokens | `--ubatch-size 512` oder höher |

Vor jedem Benchmark — und immer, wenn TG unerklärlich niedrig ist — lohnt
die komplette Diagnose-Runde:

```bash
sudo dmidecode -t memory | grep -E "Speed|Configured"   # 1. RAM-Takt
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor        # 2. = performance
cat /sys/devices/system/cpu/cpu0/cpufreq/energy_performance_preference  # 3. = performance
grep "cpu MHz" /proc/cpuinfo | sort -rn | head -6       # 4. P-Cores nahe Max-Boost?
nvidia-smi | grep MiB                                   # 5. VRAM wirklich frei?
cat /sys/class/thermal/thermal_zone*/temp               # 6. Thermik (80000 = 80 °C)
ps aux --sort=-%cpu | head -10                          # 7. CPU-Fresser im Hintergrund
grep -E "pswpin|pswpout" /proc/vmstat                   # 8. Swap-Aktivität wächst?
nvidia-smi -q | grep -A 3 "PCIe Generation"             # 9. PCIe Gen 3/4?
sudo tuned-adm active                                   # 10. throughput-performance?
```

Punkt 3 ist der am häufigsten übersehene: Auf `intel_pstate` reicht der
Governor allein nicht — auch die Energy Performance Preference muss auf
"performance" stehen, nicht auf "balance_performance".

## Sicherheit: llama-server gehört nicht ins offene Internet

Ein lokaler Inferenz-Server ist ein HTTP-Dienst wie jeder andere.
llama-server, LM Studio und vergleichbare Gateways haben ohne
Authentifizierung, Firewall und Rate-Limits nichts am offenen Internet
verloren. Minimalstandard: an localhost binden, für LAN-Zugriff einen
Reverse-Proxy mit Auth davorschalten, und für Remote-Zugriff ein privates
VPN (Tailscale, WireGuard) statt eines offenen Ports. Modell-Dateien
verdienen dieselbe Skepsis wie Software-Dependencies — Quelle, Lizenz und
Datei-Hashes prüfen, bevor ein GGUF aus dritter Hand in den Autostart
wandert. Prompts und Outputs können außerdem in App-Logs, Shell-History
und Proxy-Logs landen; wer lokal aus Datenschutzgründen arbeitet, sollte
diese Nebenkanäle mitdenken. Vertrauenswürdige lokale Agent-Workflows und
alles, was andere Geräte erreichen können, gehören auf getrennte
Endpoints.

## Fazit: Erst messen, dann in dieser Reihenfolge drehen

Die Rangfolge der Hebel ist das eigentliche Ergebnis aus Chauhans
Langzeit-Dokumentation, Stand Juni 2026: XMP/EXPO zuerst (bis 3×), dann
MTP-Speculative-Decoding (2,0–2,6×), QAT-Quants, Linux statt Windows
(15–20 %), frischer llama.cpp-Build, `--fit on`, KV-Cache auf q8_0,
`--parallel 1`, P-Core-Pinning (20–30 %) und Flash Attention. Danach
kommen die Feinheiten: ubatch-Sweeps auf der echten Prompt-Form,
N-Gram-Decoding für repetitive Code-Sessions, `GGML_CUDA_GRAPH_OPT` nur
nach A/B-Test. Wer die Liste von oben abarbeitet, statt an
Sampling-Parametern zu spielen, holt aus einer 500-Euro-GPU mehr heraus
als mancher aus der doppelt so teuren — und behält jeden Prompt im
eigenen Netz. Für die Frage, wann sich das gegenüber Cloud-APIs rechnet,
lohnt der Blick auf unsere [Kosten-Analyse](/guides/claude-code-kosten-2026).

## FAQ

### Reicht Ollama, oder brauche ich wirklich llama.cpp?

Ollama nutzt llama.cpp intern, verdeckt aber fast alle Stellschrauben: Layer-Placement, KV-Cache-Quantisierung, Fit-Parameter und Batch-Größen sind dort nicht zugänglich. Für schnelles Ausprobieren reicht Ollama; wer das Maximum aus 12 GB VRAM holen will, kommt an llama.cpp mit eigenem Build nicht vorbei.

### Warum ist mein MoE-Modell trotz guter GPU langsam?

MoE-Modelle streamen Experten-Gewichte aus dem System-RAM — der RAM-Durchsatz limitiert, nicht die GPU. Häufigste Ursache: XMP/EXPO ist im BIOS deaktiviert und der RAM läuft auf JEDEC-Basistakt. Das kostet bis zu zwei Drittel der Token-Generierung. Danach: E-Cores ausschließen und Layer-Placement mit --fit optimieren.

### Wie viel VRAM brauche ich für ein 70B-Modell?

Dense 70B-Modelle brauchen für volle Geschwindigkeit ~48 GB VRAM (Q4). MoE-Modelle mit 70–120B Gesamtparametern laufen dank CPU-Offload schon auf 12-GB-Karten brauchbar, weil pro Token nur 3–5B aktive Parameter gerechnet werden — der Rest liegt im System-RAM.

### Läuft das auch auf Apple Silicon oder AMD-GPUs?

Ja. Apple Silicon nutzt das Metal-Backend und Unified Memory — ein Mac mit 128 GB RAM hat effektiv 128 GB "VRAM" bei ~400 GB/s Bandbreite (M3 Max); dort lohnt der Vergleich mit dem MLX-Framework. AMD-GPUs laufen über ROCm/HIP oder Vulkan. Die CUDA-spezifischen Flags dieses Guides entfallen, die Konzepte (Quantisierung, KV-Cache, Placement) gelten überall.

### Lohnt sich lokale Inferenz gegenüber Cloud-APIs?

Hosted APIs kosten 1–15 US-Dollar pro Million Token, lokale Inferenz nur Strom plus einmalig 500–3.000 US-Dollar Hardware. Lokal gewinnt bei Datenschutz, Offline-Betrieb und Experimenten; Frontier-Qualität für komplexe Agent-Aufgaben liefern weiterhin die großen API-Modelle. Die meisten Power-User fahren zweigleisig.

## Quellen

- [Local LLM Inference Optimization: The Complete Guide](https://carteakey.dev/blog/local-inference/local-llm-optimization/) — Kartikey Chauhan (carteakey.dev)
- [llama.cpp – LLM inference in C/C++](https://github.com/ggml-org/llama.cpp) — ggml.org / GitHub
- [Unsloth Dynamic 2.0 GGUFs](https://docs.unsloth.ai/basics/unsloth-dynamic-2.0-ggufs) — Unsloth
