# 🛠️ Infrastructure & Deployment

Fokus: Die technische Grundlage und Hardware.

# LLM Performance Hub

LLM-Performance ist ein Systemproblem, kein GPU-Einkaufsproblem. Ob man ein einzelnes
Modell auf einer lokalen Workstation betreibt oder einen Multi-Modell-Kubernetes-Cluster
verwaltet — Inferenzgeschwindigkeit, Latenz und Effizienz werden durch das Zusammenspiel
des gesamten Stacks bestimmt:

- Modellarchitektur und Quantisierungsstufe
- VRAM-Kapazität und Speicherbandbreite
- Kontextlänge und KV-Cache-Druck
- Runtime-Scheduling und Request-Batching
- CPU- und Treiber-Overhead
- Systemtopologie — PCIe-Bandbreite, NUMA-Grenzen, Netzwerkfabric

Diese Seite ist meine persönliche Referenz dafür, wie sich LLMs unter realen Workloads
verhalten und wie man sie gezielt optimiert. Der Fokus liegt auf selbst gehosteten und
On-Premise-Deployments — nicht auf verwalteter Cloud-Inferenz.

---

## Was LLM-Performance wirklich bedeutet

Performance ist keine einzelne Zahl. Zwei Systeme können identischen Durchsatz haben und
trotzdem ein völlig unterschiedliches Nutzererlebnis liefern, je nachdem wie die Latenz
verteilt ist.

### Throughput vs. Latenz

- **Throughput:** Aggregierte Tokens pro Sekunde über alle gleichzeitigen Sessions. Relevant
  für Deployments mit mehreren Nutzern.
- **Latenz:** Zeit bis zum ersten Token (TTFT) plus Dekodierzeit pro Token. Das ist das,
  was der Nutzer tatsächlich spürt.

Ein System, das rein auf Durchsatz optimiert ist, kann sich im interaktiven Betrieb träge
anfühlen. Die richtige Balance hängt vom Anwendungsfall ab.

### Wo der Flaschenhals üblicherweise sitzt

Engpässe treten in einer recht vorhersehbaren Reihenfolge auf. Den richtigen Layer zu
identifizieren ist wertvoller als blind Hardware aufzurüsten:

1. **VRAM-Kapazität** — Passt das Modell überhaupt? Wenn nicht, hat man schon verloren.
2. **Speicherbandbreite** — Wie schnell können Gewichte pro Token in die Recheneinheiten
   gelesen werden?
3. **Runtime-Scheduling** — Wie effizient queued und batched der Serving-Layer Requests?
4. **KV-Cache-Druck** — Lange Kontexte füllen den VRAM schnell; Cache-Eviction ist teuer.
5. **CPU/Treiber-Overhead** — Oft übersehen, immer vorhanden sobald Parallelität ins Spiel
   kommt.

---

## Inference-Runtimes und lokales Tooling

Meine Setups unterscheiden sich zwischen Arbeit und Zuhause — Benchmarks und Beobachtungen
sind daher immer einem konkreten Kontext zugeordnet.

### Arbeit — Kubernetes-Cluster (Quadro RTX 6000 Ada, 24 GB VRAM)

Im Arbeitsumfeld laufen llama.cpp-Instanzen in Kubernetes-Pods, ein Modell pro GPU, mit
LiteLLM als einheitlichem API-Proxy und Open WebUI für den Teamzugang. Produktiv im
Einsatz: Gemma 4 26B und Qwen3-Coder 30B.

- [llama.cpp RPC Multi-GPU Setup Guide (Windows 11 & Linux Distributed Cluster)](https://wiki.zn80.net/books/ai-llm/page/drei-rechner-ein-modell-llamacpp-rpc-cluster-im-heimnetz)
- [Agentic LLM Inference Tuning Reference für Qwen 3.6 und Gemma 4](https://wiki.zn80.net/books/ai-llm/page/agentic-llm-inference-tuning-reference-for-qwen-36-and-gemma-4)
- *Context-Scheduling und Slot-Management unter Parallellast* — in Vorbereitung

### Zuhause — Eigene Workstation (RTX 5070, 12 GB VRAM)

Zu Hause ist der Toolstack experimenteller: llama.cpp für die rohe Inferenz, Jan.ai und
LM Studio als lokale Frontends, OpenCode für KI-gestützte Entwicklungsworkflows. Die
12-GB-Grenze ist real — Quantisierungsentscheidungen wiegen hier deutlich schwerer als
auf der Arbeit.

- [OpenCode LLM Benchmarks: IndexNow & Migration Mapping](https://wiki.zn80.net/books/ai-llm/page/opencode-llm-benchmarks-indexnow-migration-mapping)
- [The AI Coding Loop: Verification-Driven Development with AI Agents](https://wiki.zn80.net/books/ai-llm/page/the-ai-coding-loop-verification-driven-development-with-ai-agents)
- *Jan.ai vs. LM Studio: Frontend-Verhalten und Parameter-Zugang im Vergleich* — in Vorbereitung
- *12 GB VRAM: Modellauswahl — was läuft, was nicht* — in Vorbereitung

---

## Hardware-Grenzen, die wirklich zählen

Rohe GPU-Rechenleistung ist selten der limitierende Faktor. Systemarchitektur —
PCIe-Bandbreite, VRAM-Kapazität, Speicherbandbreite — bestimmt, was überhaupt möglich
ist, bevor man auch nur eine Modelldatei anfasst. Die beiden Setups, mit denen ich täglich
arbeite, repräsentieren zwei sehr unterschiedliche Constraint-Profile: 24 GB auf der Arbeit
(Server-GPU, ECC, gute Bandbreite) und 12 GB zu Hause (Consumer-GPU, schneller pro Core,
engeres VRAM-Budget).

- *PCIe-Bandbreite und Multi-GPU-Durchsatz in der Praxis* — in Vorbereitung
- *24 GB VRAM: praktische Modellfit- und KV-Cache-Grenzen für große Modelle* — in Vorbereitung
- *12 GB VRAM: Quantisierungsentscheidungen und ihre Konsequenzen* — in Vorbereitung

---

## Benchmarks & Modellvergleiche

Benchmarks sind nur dann nützlich, wenn sie eine konkrete Frage beantworten. Leaderboard-
Scores ohne Workload-Kontext sind Rauschen.

### Arbeit — Quadro RTX 6000 Ada (24 GB VRAM)

Der Arbeitscluster betreibt Gemma 4 26B und Qwen3-Coder 30B produktiv. Bei 24 GB geht es
nicht nur darum, ob das Modell passt — sondern wie viel Kontext-Headroom nach dem Laden
der Gewichte noch übrig bleibt und wie sich das Modell unter realer gleichzeitiger
Teamnutzung schlägt.

- [Agentic LLM Inference Tuning Reference für Qwen 3.6 und Gemma 4](https://wiki.zn80.net/books/ai-llm/page/agentic-llm-inference-tuning-reference-for-qwen-36-and-gemma-4)
- *Gemma 4 26B und Qwen3-Coder 30B unter realistischer Parallellast* — in Vorbereitung
- *Quadro RTX 6000 Ada: Durchsatz unter Multi-Modell-Kubernetes-Last* — in Vorbereitung

### Zuhause — RTX 5070 (12 GB VRAM)

12 GB sind eine echte Einschränkung. Die meisten interessanten Modelle brauchen aggressive
Quantisierung, und das KV-Cache-Budget schrumpft bei längeren Kontexten schnell. Der
Vorteil: Die RTX 5070 hat für ihre Klasse eine hervorragende Speicherbandbreite, und die
interaktive Single-User-Latenz ist sehr gut.

- [Qwen 3.6 27B und 35B MTP vs. Standard auf 16-GB-GPU](https://wiki.zn80.net/books/ai-llm/page/qwen-36-27b-and-35b-mtp-vs-standard-on-16gb-gpu) — Speculative Decoding: Geschwindigkeit vs. Kontextkosten
- *RTX 5070 12 GB: Welche Modelle laufen wirklich gut?* — in Vorbereitung
- *Quantisierungsstufen: Auswirkung auf Qualität und Geschwindigkeit bei 12 GB VRAM* — in Vorbereitung

### Modellgeschwindigkeit & Qualität

- [OpenCode LLM Benchmarks: IndexNow & Migration Mapping](https://wiki.zn80.net/books/ai-llm/page/opencode-llm-benchmarks-indexnow-migration-mapping)
- *Qwen3-Coder 30B vs. andere Coding-Modelle auf realen Aufgaben* — in Vorbereitung
- *Modellvergleich: Gemma 4 vs. Qwen3 für agentische Workflows* — in Vorbereitung

### Spezialisierte Tests

- **Coding:** [The AI Coding Loop: Verification-Driven Development with AI Agents](https://wiki.zn80.net/books/ai-llm/page/the-ai-coding-loop-verification-driven-development-with-ai-agents)
- **Strukturierter Output:** *Zuverlässigkeit von JSON-/Structured-Output über Modellfamilien hinweg* — in Vorbereitung
- **Zusammenfassung:** *Zusammenfassungsqualität bei variierenden Kontextlängen* — in Vorbereitung

---

## Inferenz-Optimierung

Techniken, die Latenz reduzieren oder den Durchsatz verbessern, ohne die Ausgabequalität
zu beeinträchtigen.

- [Qwen 3.6 MTP vs. Standard: Speculative Decoding in der Praxis](https://wiki.zn80.net/books/ai-llm/page/qwen-36-27b-and-35b-mtp-vs-standard-on-16gb-gpu) — Bringt MTP wirklich etwas?
- [Agentic Inference Parameter Tuning für Qwen und Gemma](https://wiki.zn80.net/books/ai-llm/page/agentic-llm-inference-tuning-reference-for-qwen-36-and-gemma-4) — Praxistaugliche Einstellungen für agentische Produktiv-Workflows
- *Speculative Decoding in llama.cpp: reale Gewinne auf Ada- vs. Consumer-GPUs* — in Vorbereitung

---

## Optimierungs-Playbook

Tuning funktioniert am besten als inkrementeller Prozess. Jeder Schritt sollte validiert
werden, bevor man zum nächsten übergeht.

**Schritt 1: Modell zum Laufen bringen**

- Die richtige Quantisierungsstufe wählen — Q4_K_M, Q6_K, Q8_0 stehen jeweils für einen
  anderen Qualitäts-/Geschwindigkeits-Kompromiss.
- Das Kontextfenster auf das tatsächlich Notwendige reduzieren.
- CPU-Offloading ist das letzte Mittel; es zerstört den Durchsatz.

**Schritt 2: Latenz stabilisieren**

- Prefill-Kosten reduzieren — kürzere System-Prompts wirken sich stärker aus als erwartet.
- Structured-Output-Schemas früh validieren, um teure Wiederholungsgenerierungen zu
  vermeiden.
- TTFT separat von der Gesamtgenerierungszeit messen; sie haben unterschiedliche Ursachen.

**Schritt 3: Durchsatz steigern**

- Den parallelen Slot-Count in llama.cpp auf das eigene Request-Muster abstimmen.
- LiteLLMs Load-Balancing nutzen, um Requests auf mehrere Modellinstanzen zu verteilen.
- vLLM oder SGLang in Betracht ziehen, wenn llama.cpp-Scheduling zum Engpass wird.

*Für Hosting-Strategie und Infrastrukturentscheidungen:
[LLM Hosting in 2026: Local, Self-Hosted and Cloud Infrastructure Compared](https://wiki.zn80.net/books/ai-llm/page/llm-hosting-in-2026-local-self-hosted-und-cloud-infrastruktur-vergleich).*

---

## Häufige Fragen

**Warum ist mein LLM langsam, obwohl ich eine leistungsstarke GPU habe?**
Meistens liegt es an der Speicherbandbreite. LLM-Dekodierung ist speicherbegrenzt — die
GPU wartet öfter auf ankommende Gewichte als dass sie wirklich rechnet. Quantisierung hilft,
weil sie die Datenmenge reduziert, die pro Token bewegt werden muss.

**Was ist wichtiger — VRAM-Größe oder GPU-Modell?**
VRAM-Kapazität kommt zuerst. Wenn Modell oder KV-Cache nicht in den VRAM passen, bricht
die Performance in dem Moment zusammen, in dem der Runtime anfängt auf System-RAM
auszulagern. Jenseits des reinen Fits ist dann die Speicherbandbreite entscheidend.

**Warum verschlechtert sich die Performance, wenn mehr Nutzer gleichzeitig arbeiten?**
Request-Queuing, KV-Cache-Contention und Scheduler-Sättigung verstärken sich gegenseitig.
Jeder zusätzliche parallele Request verbraucht VRAM und Speicherbandbreite, auf die alle
anderen Sessions ebenfalls angewiesen sind. Die Degradationskurve ist selten linear.

---

## Fazit

LLM-Performance-Optimierung folgt vorhersehbaren Prinzipien, sobald man die
Engpass-Hierarchie verstanden hat. Die Hardware spielt eine weit kleinere Rolle als das
korrekte Identifizieren des tatsächlich limitierenden Layers.

**Erst messen → Engpass identifizieren → diesen Layer beheben → wiederholen.**

# LLM Hosting in 2026: Local, Self-Hosted und Cloud-Infrastruktur Vergleich

# LLM Hosting — Übersicht und Entscheidungshilfe

Large Language Models laufen längst nicht mehr nur in der Cloud. 2026 ist die Frage nicht
mehr "Kann ich ein LLM selbst betreiben?" — sondern:

> Welche Hosting-Strategie passt zu meinem Workload, meinem Budget und meinen
> Anforderungen an Kontrolle und Datenschutz?

Diese Seite ist meine persönliche Referenz. Ich dokumentiere hier, was ich tatsächlich
betreibe und getestet habe — keine vollständige Marktübersicht, sondern ehrliche
Erfahrungswerte aus zwei verschiedenen Kontexten: dem Arbeitsumfeld (Kubernetes-Cluster,
Team-Betrieb) und dem Home-Lab (Workstation, Einzelnutzer).

---

## Was LLM Hosting eigentlich bedeutet

LLM Hosting beschreibt, wie und wo Modelle für Inferenz betrieben werden. Diese
Entscheidung hat direkte Auswirkungen auf:

- Latenz und Time-to-First-Token
- Durchsatz und Parallelität
- Kosten pro Request
- Datenschutz und Datenhoheit
- Infrastrukturkomplexität
- Operativen Aufwand

LLM Hosting ist keine reine Installationsaufgabe — es ist eine Infrastrukturentscheidung.

---

## Entscheidungsmatrix

| Ansatz | Geeignet für | Hardware | Produktionstauglich | Kontrolle |
|---|---|---|---|---|
| llama.cpp | GGUF-Modelle, CLI + Server, Offline | CPU / GPU | Ja (llama-server) | Sehr hoch |
| vLLM | Hochdurchsatz-Produktion | Dedizierter GPU-Server | Ja | Hoch |
| Jan.ai | Lokale Experimente, Einzelnutzer | Consumer GPU / CPU | Begrenzt | Hoch |
| LM Studio | Lokale Experimente, Parameter-Tuning | Consumer GPU / CPU | Begrenzt | Hoch |
| LiteLLM | Proxy-Layer, Multi-Backend, API-Unified | Keiner (nur Proxy) | Ja | Hoch |
| Open WebUI | Team-Frontend für lokale Modelle | Keiner (nur Frontend) | Ja | Hoch |

### Nur noch selten in Benutzung

| Ansatz | Geeignet für | Hardware | Produktionstauglich | Kontrolle |
|---|---|---|---|---|
| Ollama | Schneller Einstieg, minimale Konfiguration | Consumer GPU / CPU | Eingeschränkt | Hoch |
| Cloud-Anbieter | Zero-Ops, Skalierung ohne Hardware | Keiner (remote) | Ja | Gering |

---

## Lokales LLM Hosting

Lokales Hosting bringt:

- Vollständige Kontrolle über Modelle und Parameter
- Keine tokenbasierte Abrechnung
- Vorhersehbare Latenz
- Datenschutz ohne Kompromisse

Die Kehrseite: Hardware-Grenzen, Wartungsaufwand und manuelle Skalierung.

---

### llama.cpp

llama.cpp ist mein primäres Inference-Backend — sowohl auf der Arbeit als auch zu Hause.
Es ist eine schlanke C/C++-Engine für GGUF-Modelle mit sehr feingranularer Kontrolle über
Speicher, Threads, Kontextgröße und Quantisierung.

Ich nutze llama.cpp wenn:

- Ich maximale Kontrolle über Inference-Parameter brauche
- Das Deployment offline oder ohne Python-Stack laufen muss
- `llama-server` als OpenAI-kompatibler Endpunkt gefragt ist
- Ich GGUF-Modelle direkt aus dem Hub laden will

**Arbeit:** llama.cpp-Instanzen laufen als Kubernetes-Pods, je ein Modell pro
Quadro-RTX-6000-Ada-GPU (24 GB VRAM), hinter LiteLLM als einheitlichem API-Proxy.

**Zuhause:** llama.cpp direkt auf der RTX 5070 (12 GB VRAM), meistens als Backend für
Jan.ai oder OpenCode.

- [llama.cpp RPC Multi-GPU Setup Guide (Windows 11 & Linux Distributed Cluster)](https://wiki.zn80.net/books/ai-llm/page/drei-rechner-ein-modell-llamacpp-rpc-cluster-im-heimnetz)
- [Agentic LLM Inference Tuning Reference für Qwen 3.6 und Gemma 4](https://wiki.zn80.net/books/ai-llm/page/agentic-llm-inference-tuning-reference-for-qwen-36-and-gemma-4)
- *llama-server Konfiguration und Slot-Management* — in Vorbereitung
- *llama.cpp unter Kubernetes: Deployment-Muster und Fallstricke* — in Vorbereitung

---

### LiteLLM

LiteLLM ist kein Inference-Backend — sondern der Proxy-Layer davor. Ein einheitlicher
OpenAI-kompatibler Endpunkt, der Requests an verschiedene Backends weiterleitet:
llama.cpp-Instanzen, vLLM, externe Cloud-APIs. LiteLLM habe ich hauptsächlich im Arbeitsumfeld im Einsatz. Private nur eine Instanz für Tests und Updates.

Ich nutze LiteLLM wenn:

- Mehrere Modelle und Backends hinter einer einzigen API-URL liegen sollen
- Load-Balancing zwischen mehreren llama.cpp-Instanzen gefragt ist
- Nutzungsstatistiken und API-Key-Management zentral verwaltet werden sollen
- Clients (Open WebUI, Coding-Tools, Skripte) nichts vom Backend-Wechsel mitbekommen sollen
- *LiteLLM als Proxy vor llama.cpp: Setup und Konfiguration* — in Vorbereitung
- *API-Usage-Tracking mit LiteLLM und Open WebUI* — in Vorbereitung

---

### vLLM

vLLM ist auf Hochdurchsatz-Inferenz ausgelegt — PagedAttention, kontinuierliches Batching,
tensor-paralleles Sharding. Ich habe vLLM installiert und getestet, betreibe es aber nicht
produktiv, weil llama.cpp + LiteLLM für mein Workload-Profil ausreichend ist.

Interessant wird vLLM wenn:

- Viele parallele Requests gleichzeitig bedient werden müssen
- Durchsatz wichtiger ist als einfache Konfiguration
- Hugging-Face-Modelle (Safetensors) direkt geladen werden sollen
- [Lokale Installation und Betrieb von LLMs mit vLLM](https://wiki.zn80.net/books/ai-llm/page/lokale-installation-und-betrieb-von-llms-mit-vllm)
- [llama.cpp — Installation, Betrieb und Konfiguration](https://wiki.zn80.net/books/ai-llm/page/llamacpp-installation-betrieb-und-konfiguration)
- *vLLM vs. llama.cpp: Wann lohnt sich der Wechsel?* — in Vorbereitung

---

### Jan.ai

Jan.ai ist mein primäres lokales Frontend zu Hause — eine plattformübergreifende App mit
eingebautem llama.cpp-Backend, experimenteller MLX-Unterstütung, 
übersichtlicher Modellverwaltung mit Zugriff auf Huggingface und direktem Zugang zu
Inference-Parametern. Gut geeignet für Experimente, lokale Assistenten mit MCP-Server Unterstützung,
Rollenspiel-Prompts (nicht so gut wie SillyTavern) und Modellvergleiche im interaktiven Betrieb.

Ich nutze Jan.ai wenn:

- Ich schnell verschiedene Modelle ausprobieren will ohne CLI
- Parameter wie Temperature, Top-P oder Repeat-Penalty direkt anpassen will
- Eine lokale GUI ohne Cloud-Abhängigkeit gefragt ist

- *Jan.ai: Setup, Modellverwaltung und Parameter-Tuning* — in Vorbereitung
- *Jan.ai vs. LM Studio: Vergleich aus der Praxis* — in Vorbereitung

---

### LM Studio

LM Studio ist eine Alternative zu Jan.ai mit ähnlichem Ansatz: lokale GUI,
eingebettetes llama.cpp-Backend, OpenAI-kompatibler lokaler Server. Etwas stärker auf
Entwickler-Workflows ausgerichtet, mit besserem Prompt-Template-Editor.

Ich nutze LM Studio wenn:

- Der eingebaute lokale Server als API-Endpunkt für andere Tools gefragt ist
- Ich Prompt-Templates für verschiedene Modellformate pflegen will
- Ich Modelle aus Hugging Face direkt in der App suchen und laden will

Weiterführende Links

- *LM Studio als lokaler API-Server für OpenCode und andere Clients* — in Vorbereitung

---

### Open WebUI

Open WebUI ist das Team-Frontend im Arbeitsumfeld — eine ChatGPT-ähnliche
Web-Oberfläche, die hinter LiteLLM auf die llama.cpp-Instanzen zugreift. Kollegen
brauchen nichts zu installieren; sie öffnen den Browser.

Ich nutze Open WebUI wenn:

- Mehrere Nutzer Zugang zu den lokalen Modellen brauchen
- Ein benutzerfreundliches Frontend ohne technische Hürden gefragt ist
- RAG, Bildupload und Gesprächsverwaltung zentral verwaltet werden sollen

Weiterführende Links

- [Open WebUI — Übersicht und Setup](https://wiki.zn80.net/books/self-hosted-projects/page/open-webui)

---

### OpenCode

OpenCode ist mein KI-gestütztes Coding-Werkzeug — ein CLI-Agent, der llama.cpp als
Backend nutzt und direkt in den Entwicklungsworkflow integriert ist. Kein Frontend,
kein Chat — sondern Codeanalyse, Refactoring und Aufgabenausführung im Terminal.

- [The AI Coding Loop: Verification-Driven Development with AI Agents](https://wiki.zn80.net/books/ai-llm/page/the-ai-coding-loop-verification-driven-development-with-ai-agents)
- [OpenCode LLM Benchmarks: IndexNow & Migration Mapping](https://wiki.zn80.net/books/ai-llm/page/opencode-llm-benchmarks-indexnow-migration-mapping)
- *OpenCode mit lokalem llama.cpp-Backend: Konfiguration und Modellwahl* — in Vorbereitung

---

### Ollama

Ollama habe ich getestet, betreibe ich aber nicht aktiv. Es ist der einfachste Einstieg
in lokale LLMs — gute CLI, automatisches Modell-Pulling, minimale Konfiguration. Die
Einschränkungen beim Scheduling und die begrenzte Kontrolle über Inference-Parameter
haben mich zu llama.cpp geführt.

Ollama macht Sinn wenn:

- Der schnellste Weg zu einem laufenden Modell gefragt ist
- Kein Interesse an Parameter-Tuning besteht
- Ein einzelner Nutzer lokal experimentiert

Weiterführende Links

- *Warum ich von Ollama zu llama.cpp gewechselt habe* — in Vorbereitung

---

## Cloud LLM Hosting

Cloud-Anbieter abstrahieren die Hardware vollständig. Ich nutze Cloud-APIs punktuell —
vor allem für Modelle, die lokal nicht sinnvoll betreibbar sind (frontier-Modelle wie
Claude oder GPT-4-class).

Vorteile:

- Sofortige Skalierbarkeit
- Kein Hardware-Investment
- Keine Wartung

Nachteile:

- Laufende Kosten pro Token
- Daten verlassen die eigene Infrastruktur
- Vendor-Abhängigkeit

Weiterführende Links

- *Cloud-APIs sinnvoll einsetzen: wann lokales Hosting nicht reicht* — in Vorbereitung

---

## Frontends & Oberflächen

Das Hosting-Backend ist nur ein Teil des Systems. Welches Frontend Nutzer sehen,
beeinflusst die Akzeptanz erheblich.

| Frontend | Kontext | Typ |
|---|---|---|
| Open WebUI | Arbeit, Team | Web-App |
| Jan.ai | Zuhause, Einzelnutzer | Desktop-App |
| LM Studio | Zuhause, Entwicklung | Desktop-App |
| OpenCode | Zuhause, Terminal | CLI-Agent |

---

## Kosten und Kontrollvergleich

| Faktor | Lokal | Cloud |
|---|---|---|
| Anschaffungskosten | Hardware | Keine |
| Laufende Kosten | Strom | Token-Abrechnung |
| Datenschutz | Vollständig | Eingeschränkt |
| Skalierung | Manuell | Automatisch |
| Wartung | Selbst | Anbieter |
| Modellkontrolle | Vollständig | Eingeschränkt |

---

## Wann welcher Ansatz?

**llama.cpp** wenn maximale Kontrolle und GGUF-Modelle gefragt sind — sowohl für
Einzelnutzer als auch im Kubernetes-Cluster.

**LiteLLM** sobald mehrere Backends oder mehrere Nutzer hinter einer einheitlichen API
zusammengefasst werden sollen.

**vLLM** wenn llama.cpp unter Parallellast zum Engpass wird und Durchsatz Priorität hat.

**Jan.ai oder LM Studio** für lokale Experimente mit GUI, ohne CLI-Aufwand.

**OpenCode** wenn KI direkt in den Coding-Workflow integriert werden soll.

**Open WebUI** wenn Kollegen ohne technisches Setup Zugang zu lokalen Modellen brauchen.

**Cloud** wenn frontier-Modelle gefragt sind oder lokale Hardware nicht ausreicht.

---

## Häufige Fragen

**Was ist der einfachste Einstieg in lokale LLMs?**
Ollama — minimale Konfiguration, sofort lauffähig. Wer mehr Kontrolle braucht, wechselt
zu llama.cpp.

**Ist Self-Hosting günstiger als Cloud-APIs?**
Bei hohem, gleichmäßigem Volumen oft ja — sobald die Hardware amortisiert ist. Bei
sporadischer Nutzung rechnet sich Cloud meistens besser.

**Kann man LLMs ohne GPU betreiben?**
Ja, aber die Inferenzgeschwindigkeit ist erheblich eingeschränkt. Für produktiven Betrieb
ist eine dedizierte GPU praktisch Pflicht.

**Welches Frontend empfehle ich für ein Team?**
Open WebUI — es braucht keine lokale Installation auf den Client-Rechnern und lässt sich
gut hinter einen Reverse-Proxy stellen.

---

*Zur Performance und Optimierung der Inference-Backends: [LLM Performance Hub](https://wiki.zn80.net/books/ai-llm/page/llm-performance-hub)*

# Drei Rechner, ein Modell — llama.cpp RPC Cluster im Heimnetz

Ich habe drei Rechner zu Hause, die sonst meist im Leerlauf laufen. Die Idee: alle drei
per llama.cpp RPC zu einem gemeinsamen VRAM-Pool zusammenschalten und damit Modelle
betreiben, die auf einer einzelnen Karte nicht mehr passen. Dieses Dokument beschreibt,
wie ich das umgesetzt habe — inklusive der Stellen, an denen es hakelig wurde.

---

## Hardware-Übersicht

**Master Node — Windows 11**

- AMD Ryzen 7800 X3D, 32 GB RAM
- MSI GeForce RTX 5070 Ventus X2 OC, 12 GB VRAM

**Worker Node 1 & 2 — Linux (Debian)**

- Intel Core i5, 11. Generation, 16 GB RAM
- NVIDIA RTX 2070, 8 GB VRAM

**Gepoolter VRAM: 12 + 8 + 8 = 28 GB**

---

## Was 28 GB VRAM wirklich bedeuten

Bevor man anfängt, lohnt sich ein ehrlicher Blick auf die Zahlen. Ein 70B-Modell in
Q4_K_M braucht allein für die Gewichte rund 43 GB. Das übersteigt den Pool deutlich.

| Komponente | Bedarf (70B Q4_K_M) | Gepoolter VRAM | Differenz |
|---|---|---|---|
| Modellgewichte | ~43 GB | 28 GB | −15 GB |
| KV-Cache (8K Kontext) | ~5 GB | 0 GB | −5 GB |
| KV-Cache (32K Kontext) | ~25 GB | 0 GB | −25 GB |

Die fehlenden 15 GB Gewichte landen im System-RAM des Master-Nodes. Der KV-Cache
ebenfalls. Das hat Konsequenzen: Die Inferenzgeschwindigkeit liegt realistisch bei
**8–12 Tokens pro Sekunde** — nicht mehr. Wer schnelle Antworten erwartet, wird
enttäuscht sein. Für experimentelle Zwecke und zum Verstehen der Architektur ist es
trotzdem interessant.

Wer in diesem Setup produktiv mit großen Kontexten arbeiten will, kommt an RAG nicht
vorbei — kleines Kontextfenster (z.B. 8K) halten, relevante Passagen per Retrieval
einbinden, VRAM für die Gewichte freihalten.

---

## OS-Wahl für die Worker Nodes

Ich habe Debian auf beiden Intel-Maschinen installiert. Gründe:

- Sehr stabile NVIDIA-Treiberunterstützung
- Gut dokumentierte CUDA-Einrichtung
- Kein Overhead durch Desktop-Umgebung nötig

Ubuntu funktioniert genauso — der Installationsweg ist nahezu identisch.

---

## Linux Worker Nodes einrichten

### Pakete und Build-Toolchain

```bash
sudo apt install build-essential g++ cmake git curl libcurl4-openssl-dev pciutils
```

### NVIDIA-Treiber installieren

APT-Quellen um non-free erweitern:

```bash
sudo sed -i 's/main/main non-free contrib/g' /etc/apt/sources.list
sudo apt update
```

Kernel-Header, DKMS und nvidia-detect installieren:

```bash
sudo apt install linux-headers-$(uname -r) build-essential dkms nvidia-detect
```

Prüfen ob die Karte erkannt wird:

```bash
nvidia-detect
```

Wenn ja, Treiber installieren:

```bash
sudo apt install nvidia-driver nvidia-kernel-dkms
sudo reboot
```

Nach dem Neustart verifizieren:

```bash
nvidia-smi
```

### CUDA Toolkit

```bash
sudo apt install nvidia-cuda-toolkit
```

Compute Capability der GPU ermitteln — das braucht man beim Build:

```bash
nvidia-smi --query-gpu=compute_cap --format=csv
```

---

## llama.cpp auf den Linux Nodes bauen

Ich kompiliere llama.cpp selbst — einerseits für maximale Kompatibilität, andererseits
weil ich wissen will, was da läuft. Auf dem i5 mit acht parallelen Prozessen dauert der
Build ca. 6 Minuten.

### Schritt 1: Normaler CUDA-Build

```bash
git clone https://github.com/ggml-org/llama.cpp
cd llama.cpp
cmake -B build -DGGML_CUDA=ON
cmake --build build --config Release -j 8
```

Den `-j 8`-Parameter an die eigene Kernzahl anpassen.

### Schritt 2: RPC-fähigen Build erstellen

Jetzt nochmal kompilieren, diesmal mit RPC-Support. Das ist ein separater Build-Ordner:

```bash
mkdir build-rpc-cuda
cd build-rpc-cuda
cmake .. -DGGML_CUDA=ON -DGGML_RPC=ON
cmake --build . --config Release
```

Das erzeugt das `rpc-server`-Binary, das auf den Worker Nodes laufen muss.

---

## llama.cpp auf Windows installieren

Ich habe winget verwendet — unkompliziert und ausreichend für den Master-Node:

```powershell
winget install llama.cpp
```

**Wichtig:** Master und Worker müssen denselben llama.cpp-Stand (Git-Commit) verwenden.
Das RPC-Protokoll ist noch in aktiver Entwicklung; Versionsunterschiede führen zu
Abstürzen beim Tensor-Laden. Bei winget immer prüfen, welcher Stand installiert wird,
und die Linux-Worker ggf. auf denselben Commit zurücksetzen.

---

## Netzwerk

Kein WLAN. Verteilte Inferenz reagiert sehr empfindlich auf Latenz und Jitter — WLAN
macht das Ergebnis unbrauchbar. Gigabit-Ethernet per Kabel ist das absolute Minimum.

Das RPC-Protokoll überträgt Modell-Tensoren und Hidden States **unverschlüsselt**. Die
Ports (Standard: 50052, ich nutze 21000) dürfen ausschließlich im lokalen Netz
erreichbar sein. Niemals nach außen öffnen.

Firewall auf den Linux-Nodes: den gewählten Port für die IP des Master-Nodes freigeben,
alles andere sperren.

---

## Worker Nodes starten

Auf beiden Linux-Maschinen ins Build-Verzeichnis wechseln und den RPC-Server starten:

```bash
./rpc-server --host 0.0.0.0 --port 21000
```

`--host 0.0.0.0` lässt den Server auf allen Interfaces lauschen. Das ist nur dann
vertretbar, wenn die Firewall den Zugriff auf die IP des Masters beschränkt.

---

## Master Node: Inferenz starten

Der Master orchestriert das Sharding — die Remote-Worker erscheinen als zusätzliche
CUDA-Devices.

Meine Worker laufen auf `192.168.0.91` und `192.168.0.92`:

```bash
./llama-cli.exe -m llama-3-70b-q4_k_m.gguf \
  --rpc 192.168.0.91:21000,192.168.0.92:21000 \
  --n-gpu-layers 100 \
  --ctx-size 8192
```

- `--rpc`: Adressen der Worker-Nodes, kommagetrennt
- `--n-gpu-layers 100`: So viele Layer wie möglich in den gepoolten VRAM; der Rest
  landet im System-RAM des Masters
- `--ctx-size 8192`: Bei 28 GB VRAM vernünftiger Ausgangswert; größere Kontexte
  kosten schnell alles was noch übrig ist

---

## Performance-Flags

Diese Flags bringen messbare Verbesserungen:

- **`--flash-attn`** — Reduziert Speicherbedarf und Rechenaufwand des
  Attention-Mechanismus. Immer einschalten.
- **`--mlock`** — Verhindert, dass das OS Modellgewichte auf die Auslagerungsdatei
  schreibt. Ohne dieses Flag gibt es Stottern bei längerem Betrieb.
- **`--no-mmap`** — Auf den Worker-Nodes empfehlenswert wenn schnelle NVMe vorhanden
  ist: erzwingt vollständiges Laden des Shards in RAM beim Start.
- **`--threads`** — Für die CPU-Fallback-Verarbeitung auf dem Master: 4–8 Threads
  sind optimal, unabhängig von der Gesamtkernzahl. Mehr Threads erzeugen
  Kontextwechsel-Overhead der die Performance verschlechtert.

---

## Fehlerbehebung

### "RPC Failed to Connect" oder Worker meldet "0 MiB free"

Verbindung klappt, aber der Worker meldet keinen freien VRAM:

1. CUDA-Backend auf dem Worker ist nicht korrekt initialisiert — `nvidia-smi` prüfen
2. Falsches `CUDA_DOCKER_ARCH` beim Build gesetzt
3. `nvidia-cuda-toolkit` unvollständig installiert

### Absturz beim Tensor-Laden

Fast immer ein Versions-Mismatch. llama.cpp-Version auf Master und Worker angleichen —
identischer Git-Commit, nicht nur dieselbe Release-Nummer.

---

## Screenshots

Hier ein paar Aufnahmen aus dem laufenden Betrieb — NVTOP und NVITOP zeigen schön,
wie die VRAM-Last auf die Worker verteilt wird.

*(Screenshots aus dem Wiki-Upload — siehe Originalartikel)*

---

## Fazit

Das Setup läuft. 70B-Modelle sind auf 28 GB VRAM machbar, aber man muss die
Erwartungen kalibrieren: 8–12 TPS, kein großes Kontextfenster, der Master-RAM ist
der eigentliche Flaschenhals. Für das Experimentieren mit Modellen, die sonst gar
nicht laufen würden, ist es trotzdem ein sinnvolles Setup.

Wer ernsthaft mit großen Kontexten und diesem VRAM-Budget arbeiten will, sollte RAG
in Betracht ziehen — kleines Fenster halten, Retrieval macht den Rest.

# Lokale Installation und Betrieb von LLMs mit vLLM

vLLM ist ein hochdurchsatzorientiertes Inference-Framework für Hugging-Face-Modelle.
Im Vergleich zu llama.cpp liegt der Fokus auf kontinuierlichem Batching und
PagedAttention — das macht vLLM besonders interessant wenn mehrere Requests
gleichzeitig bedient werden sollen. Für Einzelnutzer im Homelab ist llama.cpp oft
die einfachere Wahl; vLLM lohnt sich wenn der Throughput wichtiger ist als
unkomplizierte Konfiguration.

---

## Voraussetzungen

- NVIDIA GPU mit CUDA-Support (Ampere oder neuer empfohlen)
- Mindestens 8 GB VRAM für kleinere Modelle; für 7B-Klasse realistisch 10–12 GB
- Python 3.10–3.12
- CUDA 12.1 oder neuer

CUDA und Treiber prüfen:

```bash
nvcc --version
nvidia-smi
```

---

## System vorbereiten und uv installieren

`uv` ist ein moderner Python-Paketmanager von [Astral](https://astral.sh/) — deutlich
schneller als pip, zuverlässigere Dependency-Resolution, empfehlenswert für alle
Python-basierten AI-Projekte.

**Linux:**

```bash
sudo apt update && sudo apt upgrade -y
sudo apt install curl
curl -LsSf https://astral.sh/uv/install.sh | sh
```

Shell neu laden damit `uv` im PATH liegt:

```bash
source ~/.bashrc
# oder
source ~/.zshrc
```

**Windows:**

```powershell
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
```

---

## vLLM installieren

Eine virtuelle Umgebung anlegen und vLLM darin installieren:

```bash
uv venv vllm-env --python 3.12
source vllm-env/bin/activate
uv pip install vllm
```

Auf Windows:

```powershell
uv venv vllm-env --python 3.12
vllm-env\Scripts\activate
uv pip install vllm
```

Die Installation zieht PyTorch mit CUDA-Support automatisch — das sind mehrere GB,
also etwas Geduld einplanen.

Installation verifizieren:

```bash
python -c "import vllm; print(vllm.__version__)"
```

---

## Erstes Modell starten

vLLM lädt Modelle direkt von Hugging Face. Beim ersten Start wird das Modell
heruntergeladen und im Cache gespeichert (`~/.cache/huggingface`).

Beispiel mit Qwen3 4B (passt gut auf 12 GB VRAM):

```bash
vllm serve Qwen/Qwen3-4B-Instruct \
  --host 0.0.0.0 \
  --port 8000
```

Beispiel mit Gemma 3 12B auf 24 GB VRAM (Arbeitsumgebung):

```bash
vllm serve google/gemma-3-12b-it \
  --host 0.0.0.0 \
  --port 8000 \
  --dtype bfloat16
```

Wenn der Server läuft, ist die API unter `http://localhost:8000` erreichbar und
OpenAI-kompatibel — LiteLLM, Open WebUI und andere Clients können direkt damit
arbeiten.

---

## API testen

Verfügbare Modelle anzeigen:

```bash
curl http://localhost:8000/v1/models
```

Chat-Request absetzen:

```bash
curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen3-4B-Instruct",
    "messages": [
      {"role": "user", "content": "Was ist der Unterschied zwischen vLLM und llama.cpp?"}
    ]
  }'
```

---

## Wichtige Start-Parameter

| Parameter | Beschreibung | Beispiel |
|---|---|---|
| `--host` | Bind-Adresse | `0.0.0.0` für Netzwerkzugriff |
| `--port` | Port | `8000` |
| `--max-model-len` | Maximale Kontextlänge | `8192` |
| `--gpu-memory-utilization` | VRAM-Auslastung (0–1) | `0.85` |
| `--dtype` | Datentyp | `bfloat16` oder `float16` |
| `--quantization` | Quantisierungsmethode | `awq`, `gptq` |
| `--tensor-parallel-size` | Multi-GPU-Parallelität | `2` für zwei GPUs |

**`--gpu-memory-utilization`** ist praktisch wenn vLLM zu viel VRAM belegt und OOM
wirft. Default ist 0.9 — auf 0.8 oder 0.85 reduzieren wenn andere Prozesse auch
VRAM brauchen.

**`--max-model-len`** begrenzt den KV-Cache. Bei 12 GB VRAM macht es Sinn, diesen
Wert explizit zu setzen:

```bash
vllm serve Qwen/Qwen3-4B-Instruct \
  --host 0.0.0.0 \
  --port 8000 \
  --max-model-len 8192 \
  --gpu-memory-utilization 0.85
```

---

## Quantisierte Modelle verwenden

Wer auf VRAM-Budget achten muss, nutzt AWQ- oder GPTQ-quantisierte Varianten —
die meisten großen Modellreihen haben diese direkt auf Hugging Face:

```bash
vllm serve Qwen/Qwen3-7B-Instruct-AWQ \
  --quantization awq \
  --host 0.0.0.0 \
  --port 8000
```

---

## Als systemd-Service betreiben

Für dauerhaften Betrieb auf einem Linux-Server:

```ini
[Unit]
Description=vLLM Inference Server
After=network.target

[Service]
Type=simple
User=DEIN_USER
WorkingDirectory=/home/DEIN_USER
ExecStart=/home/DEIN_USER/vllm-env/bin/vllm serve Qwen/Qwen3-4B-Instruct \
  --host 0.0.0.0 \
  --port 8000 \
  --max-model-len 8192
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target
```

Speichern als `/etc/systemd/system/vllm.service`, dann:

```bash
sudo systemctl daemon-reload
sudo systemctl enable vllm
sudo systemctl start vllm
sudo systemctl status vllm
```

---

## Fehlerbehebung

**CUDA out of memory beim Start**
`--gpu-memory-utilization` reduzieren oder `--max-model-len` kleiner setzen. vLLM
reserviert beim Start den gesamten kalkulierten KV-Cache — das ist kein Bug,
sondern das Design.

**Modell lädt aber Requests schlagen fehl**
Prüfen ob der `--max-model-len` mit der Kontextlänge des Modells kompatibel ist.
Manche Modelle haben eine maximale Länge die vLLM nicht automatisch erkennt.

**Langsame erste Anfrage**
Normal — vLLM kompiliert beim ersten Request CUDA-Kernel. Ab der zweiten Anfrage
läuft es mit voller Geschwindigkeit.

---

## vLLM vs. llama.cpp — wann was?

| | vLLM | llama.cpp |
|---|---|---|
| Modellformat | Safetensors (HF) | GGUF |
| Stärke | Hoher Durchsatz, Parallelität | Feingranulare Kontrolle, Offline |
| VRAM-Overhead | Höher | Niedriger |
| Konfiguration | Einfacher für HF-Modelle | Flexibler für GGUF-Ökosystem |
| Produktionstauglich | Ja | Ja (llama-server) |

Für meinen Arbeitscluster bleibt llama.cpp die erste Wahl — das GGUF-Ökosystem,
die LiteLLM-Integration und der niedrigere VRAM-Overhead passen besser. vLLM kommt
ins Spiel wenn ein Modell nur als Safetensors verfügbar ist oder wenn ich unter
echter Parallellast testen will.

# llama.cpp — Installation, Betrieb und Konfiguration

llama.cpp ist mein primäres Inference-Backend — sowohl im Arbeitscluster als auch zu
Hause. Es ist eine schlanke C/C++-Engine für GGUF-Modelle mit sehr direktem Zugang zu
allen relevanten Parametern: Kontextgröße, GPU-Layer-Verteilung, Quantisierung,
Threading. Kein Python-Stack, kein Framework-Overhead.

Der Einstieg ist etwas steiler als bei Ollama oder Jan.ai, aber die Kontrolle ist es
wert sobald man weiß was man tut.

---

## Wann llama.cpp, wann etwas anderes?

| Situation | Empfehlung |
|---|---|
| GGUF-Modell, maximale Kontrolle | llama.cpp |
| Schneller Einstieg ohne CLI | Jan.ai oder LM Studio |
| Hugging-Face-Modell (Safetensors) | vLLM |
| Hoher Durchsatz, viele parallele Nutzer | vLLM |
| Team-Frontend ohne lokale Installation | Open WebUI + LiteLLM |

---

## Modelle beschaffen

llama.cpp arbeitet ausschließlich mit GGUF-Dateien. Die beste Anlaufstelle ist
Hugging Face — dort gibt es für fast jedes bekannte Modell fertige GGUF-Versionen,
meistens von [bartowski](https://huggingface.co/bartowski) oder direkt vom
Modellhersteller.

**Quantisierungsstufen im Überblick:**

| Quantisierung | VRAM-Bedarf (7B) | Qualität | Empfehlung |
|---|---|---|---|
| Q8_0 | ~8 GB | Sehr gut | Wenn VRAM reicht |
| Q6_K | ~6 GB | Gut | Guter Kompromiss |
| Q4_K_M | ~4.5 GB | Akzeptabel | Standard für knappes VRAM |
| Q4_K_S | ~4 GB | Etwas schlechter | Nur wenn nötig |
| Q3_K_M | ~3.5 GB | Spürbare Verluste | Notlösung |

Für die RTX 5070 (12 GB) passen 7B-Modelle in Q8_0 bequem, 13B-Modelle in Q4_K_M
noch gut. Für die Quadro RTX 6000 Ada (24 GB) sind 30B-Modelle in Q4_K_M oder
kleinere Modelle in höherer Quantisierung realistisch.

Modell direkt von Hugging Face laden:

```bash
# Mit huggingface-cli (pip install huggingface_hub)
huggingface-cli download bartowski/Qwen3-8B-GGUF \
  Qwen3-8B-Q6_K.gguf \
  --local-dir ./models
```

---

## Installation

### Linux — aus dem Quellcode bauen

Empfohlen für maximale Kompatibilität und aktuelle Features. Auf einem i5 mit
8 parallelen Jobs ca. 6 Minuten Buildzeit.

Abhängigkeiten:

```bash
sudo apt install build-essential cmake git curl libcurl4-openssl-dev
```

Bauen mit CUDA-Support:

```bash
git clone https://github.com/ggml-org/llama.cpp
cd llama.cpp
cmake -B build -DGGML_CUDA=ON
cmake --build build --config Release -j 8
```

Die fertigen Binaries liegen in `build/bin/`.

### Windows — winget

Der einfachste Weg für den Windows-Master-Node:

```powershell
winget install llama.cpp
```

Wer eine spezifische Version oder CUDA-optimierte Builds braucht, findet diese als
fertige Releases auf der [llama.cpp GitHub-Seite](https://github.com/ggml-org/llama.cpp/releases).

---

## llama-cli — Interaktiver Betrieb

`llama-cli` ist das Kommandozeilen-Interface für direkte Interaktion mit einem Modell.
Gut für schnelle Tests, Prompt-Experimente und das Debuggen von Parametern.

Basis-Aufruf:

```bash
./build/bin/llama-cli \
  -m ./models/Qwen3-8B-Q6_K.gguf \
  --interactive \
  -ngl 99 \
  --ctx-size 8192
```

Mit System-Prompt:

```bash
./build/bin/llama-cli \
  -m ./models/Qwen3-8B-Q6_K.gguf \
  --interactive \
  -ngl 99 \
  --ctx-size 8192 \
  --system-prompt "Du bist ein hilfreicher Assistent."
```

Einzelne Ausgabe ohne interaktiven Modus (gut für Scripting):

```bash
./build/bin/llama-cli \
  -m ./models/Qwen3-8B-Q6_K.gguf \
  -ngl 99 \
  --ctx-size 4096 \
  -p "Erkläre den Unterschied zwischen TCP und UDP in drei Sätzen."
```

---

## llama-server — OpenAI-kompatibler API-Endpunkt

`llama-server` ist das produktive Backend — startet einen HTTP-Server mit
OpenAI-kompatibler API. Damit lassen sich LiteLLM, Open WebUI, OpenCode, Jan.ai und
alle anderen OpenAI-kompatiblen Clients direkt anbinden.

Starten:

```bash
./build/bin/llama-server \
  -m ./models/Qwen3-8B-Q6_K.gguf \
  --host 0.0.0.0 \
  --port 8080 \
  -ngl 99 \
  --ctx-size 8192
```

API testen:

```bash
# Verfügbare Modelle
curl http://localhost:8080/v1/models

# Chat-Request
curl http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3-8b",
    "messages": [
      {"role": "user", "content": "Was ist llama.cpp?"}
    ]
  }'
```

---

## Wichtige Parameter

### GPU und Speicher

| Parameter | Beschreibung | Empfehlung |
|---|---|---|
| `-ngl` / `--n-gpu-layers` | Layer auf der GPU | `99` — alles auf GPU |
| `--ctx-size` | Kontextfenstergröße | 8192 als Ausgangswert |
| `--flash-attn` | Flash Attention aktivieren | Immer |
| `--mlock` | Modell im RAM fixieren | Empfohlen |

### Threading und Parallelität (llama-server)

| Parameter | Beschreibung | Empfehlung |
|---|---|---|
| `--parallel` | Parallele Request-Slots | 2–4 für Einzelnutzer |
| `--threads` | CPU-Threads für Prefill | Physische Kerne |
| `--threads-batch` | Threads für Batch-Verarbeitung | Wie `--threads` |

### Ausgabesteuerung

| Parameter | Beschreibung |
|---|---|
| `--temp` | Temperature (0 = deterministisch) |
| `--top-p` | Nucleus Sampling |
| `--repeat-penalty` | Wiederholungsstrafe |
| `--seed` | Reproduzierbare Ausgaben |

Ein typischer Produktions-Start für den Arbeitscluster (Quadro RTX 6000 Ada, 24 GB):

```bash
./build/bin/llama-server \
  -m ./models/Qwen3-Coder-30B-Q4_K_M.gguf \
  --host 0.0.0.0 \
  --port 8080 \
  -ngl 99 \
  --ctx-size 16384 \
  --flash-attn \
  --mlock \
  --parallel 4 \
  --threads 8
```

Für die RTX 5070 zu Hause (12 GB) mit einem 8B-Modell:

```bash
./build/bin/llama-server \
  -m ./models/Qwen3-8B-Q6_K.gguf \
  --host 127.0.0.1 \
  --port 8080 \
  -ngl 99 \
  --ctx-size 8192 \
  --flash-attn \
  --mlock \
  --parallel 2
```

---

## Als systemd-Service betreiben

Für dauerhaften Betrieb auf einem Linux-Server:

```ini
[Unit]
Description=llama.cpp Inference Server
After=network.target

[Service]
Type=simple
User=DEIN_USER
WorkingDirectory=/home/DEIN_USER/llama.cpp
ExecStart=/home/DEIN_USER/llama.cpp/build/bin/llama-server \
  -m /home/DEIN_USER/models/Qwen3-8B-Q6_K.gguf \
  --host 0.0.0.0 \
  --port 8080 \
  -ngl 99 \
  --ctx-size 8192 \
  --flash-attn \
  --mlock \
  --parallel 4
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target
```

```bash
sudo systemctl daemon-reload
sudo systemctl enable llamacpp
sudo systemctl start llamacpp
sudo systemctl status llamacpp
```

---

## Integration mit LiteLLM

Im Arbeitscluster läuft llama-server hinter LiteLLM als einheitlichem API-Proxy.
LiteLLM-Konfiguration für einen llama.cpp-Endpunkt:

```yaml
model_list:
  - model_name: qwen3-coder-30b
    litellm_params:
      model: openai/qwen3-coder-30b
      api_base: http://localhost:8080
      api_key: none
```

Damit ist das Modell für alle LiteLLM-Clients unter `qwen3-coder-30b` erreichbar,
ohne dass sie direkt mit llama-server kommunizieren müssen.

---

## Fehlerbehebung

**Modell startet, aber Inferenz ist sehr langsam**
Prüfen ob `-ngl 99` gesetzt ist und ob `nvidia-smi` während der Inferenz VRAM-Auslastung
zeigt. Wenn der VRAM bei 0 bleibt, wurde llama.cpp ohne CUDA gebaut.

**CUDA-Build schlägt fehl**
`nvcc --version` prüfen — wenn kein NVCC gefunden wird, fehlt das CUDA Toolkit:
```bash
sudo apt install nvidia-cuda-toolkit
```

**Out of Memory beim Start**
Entweder `--ctx-size` reduzieren oder ein stärker quantisiertes Modell verwenden.
Mit `--verbose` starten um die genaue VRAM-Kalkulation zu sehen.

**Langsamer Prefill, schneller Decode**
Normales Verhalten — Prefill ist compute-bound, Decode ist memory-bound. Flash Attention
(`--flash-attn`) verbessert den Prefill messbar.

---

## Weiterführend

- [llama.cpp RPC Cluster — verteilte Inferenz im Heimnetz](https://wiki.zn80.net/books/ai-llm/page/llamacpp-rpc-multi-gpu-setup-guide-windows-11-linux-distributed-cluster)
- [Agentic LLM Inference Tuning für Qwen 3.6 und Gemma 4](https://wiki.zn80.net/books/ai-llm/page/agentic-llm-inference-tuning-reference-for-qwen-36-and-gemma-4)
- [LLM Performance Hub](https://wiki.zn80.net/books/ai-llm/page/llm-performance-hub)