Serving-Ebene wählen, dann Anfragen einplanen
Ollama, llama.cpp und vLLM überschneiden sich; Paketverwaltung und Ausführung sind verschiedene Aufgaben.
KI-gestützte Lernvisualisierung · schematische Erklärung zum Artikel
Ollama ergänzt Modellverwaltung und Runtime-Schnittstelle. llama.cpp ist eine Ausführungsengine mit eigenem Server; Ollama besitzt auch andere Engine-Pfade.
Lokale LLM-Inferenz hat sich auf drei Stacks eingespielt, die ständig verwechselt werden: llama.cpp, Ollama und vLLM. Sie sind keine Konkurrenten auf derselben Ebene – zwei von ihnen umhüllen bzw. ergänzen einander direkt. Dieser Guide legt fest, was jedes Einzelne ist, wo sich Concurrency- und Speichermodelle unterscheiden und was man pro Szenario wählt.
Was jede Schicht wirklich ist
llama.cpp ist die C/C++-Inferenz-Engine: eine GGUF-native Runtime mit Backends für CUDA, Metal, Vulkan, ROCm und reine CPU, plus llama-server, ein eingebauter HTTP-Server mit OpenAI- und Anthropic-kompatiblen Routen, Continuous Batching und parallelem Decoding.1
Ollama ist eine Modell-Distributions- und Runtime-Schicht, keine eigene Engine (jedenfalls überwiegend). Historisch hat es einen gepinnten llama.cpp-Build umhüllt – die Variable LLAMA_CPP_VERSION im Ollama-Repo fixiert die exakte Upstream-Quelle, gepatcht über llama/compat/.2 Über diesen Pin hinaus hat Ollama eigene Engines ergänzt: eine Multimodal-Engine, die Vision-Modelle (Llama 4, Gemma 3, Qwen 2.5 VL) direkt auf der GGML-Tensor-Bibliothek ausführt, statt separaten Text-Decoder- und Vision-Encoder-Prozess zusammenzukleben,3 sowie eine MLX-basierte Engine für Apple Silicon, die Ollama im März 2026 in den Preview gestellt hat und für beschleunigte Modelle den llama.cpp-Metal-Pfad ersetzt.4
vLLM ist eine Python/CUDA-Serving-Engine rund um PagedAttention: KV-Cache-Speicher, OS-artig in Blöcken fester Größe verwaltet mit logisch-zu-physisch Block-Tabellen – dadurch nahezu Null Cache-Verschwendung und 2–4× Throughput gegenüber den Systemen aus dem ursprünglichen Paper.5 Seit der V1-Re-Architektur ist Prefix Caching standardmäßig aktiviert (unter 1% Durchsatzverlust bei 0% Hit-Rate), und V1 erreicht bis zu 1,7× höheren Durchsatz als V0.6
| Layer | llama.cpp | Ollama | vLLM |
|---|---|---|---|
| Was es ist | C/C++-GGUF-Engine + llama-server HTTP | Runtime + Modell-Registry um gepinnte llama.cpp-Version, eigene Multimodal-Engine, MLX-Engine auf Apple Silicon | Python/CUDA-Serving-Engine, PagedAttention-KV-Manager |
| Modellformat | GGUF (nativ) | GGUF (+ MLX-nativ auf Apple Silicon) | HF-Safetensors (GGUF über experimentelles Plugin) |
| Hauptziel | Eine Maschine, jede Hardware inkl. CPU | Ease of use, ollama run | GPU-Server-Durchsatz |
| Concurrency | Parallele Slots; gemeinsamer KV-Pool optional | OLLAMA_NUM_PARALLEL-Slots | Continuous Batching über einen gemeinsam genutzten KV-Pool |
Concurrency-Modelle: Slots und KV-Allokation
Das ist der größte Verhaltensunterschied überhaupt – und die Quelle der übelsten Falle.
llama-server: --parallel N-Slots mit optional gemeinsamem KV-Pool
llama-server -np N erzeugt N Slots. Aktuelle Master-Defaults: -np/--parallel default -1 (auto), und -cb/--cont-batching (Continuous Batching) ist standardmäßig aktiviert; -b/--batch-size hat default 2048, -ub/--ubatch-size 512. --ctx-size (Default 0 = aus dem Modell geladen) bestimmt die gesamte KV-Kapazität. Mit --no-kv-unified wird sie auf Slots aufgeteilt; mit --kv-unified teilen die Slots einen Pool. Bei automatischer Slot-Zahl ist Unified-KV derzeit standardmäßig aktiv.1
Die Falle betrifft den nicht vereinheitlichten Modus: Mit -c 8192 -np 4 --no-kv-unified erhält jeder Slot 8192/4 = 2048 Token KV-Kapazität. Für vier gleichzeitige 8k-Slots in diesem Modus braucht es -c 32768 -np 4 --no-kv-unified. Mit --kv-unified teilen sich die Slots dagegen den 8192-Token-Pool; vier volle 8k-Sequenzen benötigen trotzdem etwa 32k Token Gesamtkapazität. --kv-unified-per-slot kann ein unabhängiges Slot-Limit setzen.7
vLLM: ein gepagter KV-Pool, Continuous Batching
vLLM hält einen paged KV-Pool und alloziert Blöcke nach Bedarf; auch llama-server kann einen gemeinsamen Pool nutzen, verwendet aber einen anderen Allokator und Scheduler. Requests verlassen und ergänzen den Batch bei jedem Decode-Schritt. Höhere Concurrency kostet im Leerlauf nichts, weil kein per-Request-Kontext vorreserviert wird: Der KV-Cache eines Requests wächst Token für Token in physischen Blöcken und wird bei Request-Ende sofort freigegeben.5 --max-num-seqs begrenzt die Batchgröße; die eigentliche Grenze für parallele Requests ist, wie viele Sequenzen mit ihrem angewachsenen KV in den Pool passen.
Ollama: Slots wie llama.cpp, dimensioniert über Defaults
Ollama erbt das Slot-Modell: OLLAMA_NUM_PARALLEL (default 1) ist die Zahl paralleler Requests pro Modell, und der RAM-Bedarf skaliert mit OLLAMA_NUM_PARALLEL * OLLAMA_CONTEXT_LENGTH.8 Beim Default von 1 reihen sich gleichzeitige Requests ein; jede zusätzliche parallele Anfrage kann den KV-Speicherbedarf erhöhen.
GGUF: natives Zuhause vs. experimenteller Gast
GGUF ist llama.cpps natives Format – die Referenzimplementierung mit der kompletten Quant-Familie (Q2_K bis Q8_0, i-Quants, Imatrix-Kalibrierung).9
vLLMs GGUF-Support ist ein anderes Kapitel, in den Worten der eigenen Doku: "GGUF support in vLLM is highly experimental and under-optimized at the moment, it might be incompatible with other features." Das GGUF-Loading ist aus dem Kern in das OOT-Paket vllm-gguf-plugin gewandert (uv pip install vllm-gguf-plugin), und die Doku empfiehlt, den Tokenizer des Basismodells explizit mitzugeben, z. B.10:
vllm serve unsloth/Qwen3-0.6B-GGUF:Q4_K_M --tokenizer Qwen/Qwen3-0.6BPraktische Regel: GGUF ist in vLLM weniger optimiert; die Leistung muss für den konkreten Workload gemessen werden. Für hohen Serving-Durchsatz auch Safetensors mit unterstützter Quantisierung (AWQ, GPTQ, FP8) vergleichen.
Defaults, die beißen
Ollamas Kontext-Default ist VRAM-gestaffelt. Aktuelle Doku: < 24 GiB VRAM → 4k Kontext; 24–48 GiB → 32k; ≥ 48 GiB → 256k, überschreibbar mit OLLAMA_CONTEXT_LENGTH (ältere Releases hatten einen flachen 4096er-Default, und 4096 taucht noch in den Override-Beispielen der FAQ auf).11 Wenn die 24-GB-Karte einen 32k-Default wählt, den man nicht bestellt hat, wächst der KV-Cache entsprechend – ollama ps prüfen (Spalte CONTEXT) und num_ctx pro Request oder die Env-Variable global setzen.
Ollamas KV-Cache-Typ ist default f16. OLLAMA_KV_CACHE_TYPE akzeptiert f16 (default), q8_0 (etwa halber KV-Payload-Speicher) oder q4_0 (etwa ein Viertel des Payloads; bei beiden Qualität am eigenen Workload prüfen) – und wirkt nur, wenn Flash Attention aktiviert ist.8
OLLAMA_NUM_PARALLEL ist default 1 – gleichzeitige Requests laufen nicht parallel, sondern werden gereiht; Erhöhen multipliziert den KV-Speicher mit N.8
vLLMs gpu_memory_utilization ist default 0,92 – vLLM beansprucht beim Start bis zu 92% des Gesamt-Speichers der Karte (pro Instanz, nicht prozess-koordiniert) und zieht danach Gewichte, Aktivierungs-Peak und CUDA-Graph-Pools ab; der KV-Cache ist der Rest. Auf einer Karte mit Display oder weiteren Prozessen kann dadurch zu wenig Speicher frei bleiben. Anteil oder --max-model-len nach gemessenem Bedarf anpassen.12
Durchgerechnet: 14B Q4_K_M, 4 Slots × 8k, auf einer 24-GB-Karte
Nehmen wir Qwen2.5-14B (48 Layer, GQA mit 8 KV-Heads, Hidden Size 5120 über 40 Heads → Head-Dim 128, 14,7 Mrd. Parameter gesamt).13 Wir rechnen das Budget mit der KV-Formel dieser Seite (siehe KV-Cache-Guide und Inferenz-Mathematik) und setzen llama.cpps gemessene Q4_K_M-≈4,85 Bits pro Gewicht für diese Gewichtsklasse ein.9
Gewichte bei 4,85 bpw:
KV-Cache pro Token (f16, 2 Byte/Wert), mit :
Pro Slot bei 8.192 Tokens, und gesamt für 4 Slots:
| Komponente | Größe |
|---|---|
| Gewichte (Q4_K_M, 4,85 bpw) | 8,30 GiB |
| KV-Cache, 4 × 8k Slots, f16 | 6,00 GiB |
| Zwischensumme | 14,30 GiB |
| Puffer auf einer 24-GB-Karte (24 dezimale GB − die 14,30-GiB-Zwischensumme = 15,35 GB) | ~8,65 GB |
Es passt – mit deutlichem Puffer, und genau das ist die Aussage: Auf einer 24-GB-Karte liegen ein 14B-Modell in Q4_K_M und 4 parallele 8k-Konversationen komfortabel im Budget; die ~8,65 GB Puffer — 24 dezimale GB auf dem Aufkleber minus der 14,30-GiB-Zwischensumme (15,35 dezimale GB) — decken Compute-Scratch (abhängig von Batch-Größe und Backend) plus CUDA-Kontext. Zwei Hebel, wenn mehr Slots oder Kontext nötig sind: -ctk q8_0 -ctv q8_0 halbiert den KV-Cache auf 3,0 GiB (llama-server-Flags, f16 default1) – derselbe Trade, den Ollamas OLLAMA_KV_CACHE_TYPE=q8_0 macht. Für den vollständigen Sizing-Workflow siehe VRAM-Rechner erklärt und Quantisierung erklärt; das interaktive Tool ist der LLM-Inferenz-Rechner.
Für vier feste 8k-Slots im nicht vereinheitlichten Modus startet man llama-server -m model-Q4_K_M.gguf -c 32768 -np 4 --no-kv-unified. Ein gemeinsamer Pool kann sie ebenfalls aufnehmen, wenn seine Gesamtkapazität reicht.
Entscheidungstabelle
| Szenario | Wahl | Warum |
|---|---|---|
| Laptop / Desktop, ein Nutzer gleichzeitig | Ollama | Ein Befehl bis zum laufenden Modell; VRAM-gestaffelte Defaults, Modell-Registry, automatisches GPU-Splitting via darunterliegendem llama.cpp |
| Mac mit Apple Silicon, schnellstes Decode | Ollama (MLX-Engine) | Der MLX-Pfad ist für Unified Memory gebaut; Preview erfordert >32 GB Unified Memory und beschleunigt aktuell spezifische Modelle4 |
| Maximale Kontrolle: KV-Quantisierung, Slot-Tuning, exotische Hardware, CPU-Inferenz | llama.cpp (llama-server) | Direkter Zugriff auf jedes Flag (-ctk, -np, -c, --override-tensor), GGUF-nativ, läuft auf CPU – vLLM-GGUF tut das nicht |
| Viele gleichzeitige Nutzer, eine oder viele GPUs, Latenz-SLO | vLLM | Gepagerter KV-Pool + Continuous Batching skalieren mit Last; Prefix Caching standardmäßig an6 |
| Produktions-API mit strukturierten Ausgaben / Tool-Use bei hohem QPS | vLLM | Erstklassige Serving-Features, Tensor-Parallelität über GPUs, FP8/AWQ-Quantisierung |
| Multimodal (Vision) lokal | Ollama oder llama-server | Ollamas Multimodal-Engine macht Vision zur first-class citizen3; llama-servers --mmproj deckt GGUF-Vision-Modelle ab1 |
| Ein HF-only-Modell als GGUF servieren | llama.cpp oder Ollama | vLLMs GGUF-Pfad ist 'highly experimental', Plugin-basiert10 |
Faustregel: llama.cpp, wenn man an die Regler muss oder exotische Hardware bedienen will; Ollama für reibungslose lokale Nutzung; vLLM, wenn andere Menschen oder Services auf den Endpunkt zugreifen und Durchsatz pro GPU zählt.
Footnotes
-
ggml-org/llama.cpp, tools/server/README.md (master): https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md —
-np/--paralleldefault -1 (auto),-cb(Continuous Batching) default aktiviert,-bdefault 2048,-ubdefault 512,-c/--ctx-sizedefault 0 (aus dem Modell geladen). ↩ ↩2 ↩3 ↩4 -
ollama/ollama, llama/README.md:
LLAMA_CPP_VERSIONpinnt Ollamas llama.cpp-Quelle: https://github.com/ollama/ollama/blob/main/llama/README.md ↩ -
Ollama-Blog, „Ollama's new engine for multimodal models" (15. Mai 2025): https://ollama.com/blog/multimodal-models ↩ ↩2
-
Ollama-Blog, „Ollama is now powered by MLX on Apple Silicon in preview" (März 2026): https://ollama.com/blog/mlx ↩ ↩2
-
Kwon et al., „Efficient Memory Management for Large Language Model Serving with PagedAttention", SOSP 2023, arXiv:2309.06180: https://arxiv.org/abs/2309.06180 ↩ ↩2
-
vLLM-Blog, „vLLM V1: A Major Upgrade to vLLM's Core Architecture" (2025-01-27): bis zu 1,7× Throughput vs. V0; Prefix Caching default mit \<1% Durchsatzverlust bei 0% Hit-Rate: https://blog.vllm.ai/2025/01/27/v1-alpha-release.html ↩ ↩2
-
llama.cpp Issue #11681 („--ctx-size is divided by --parallel") und PR #24124 (Commit 1844325) / Release b10662 (
ctx-per-slot,--kv-unified-per-slot): https://github.com/ggml-org/llama.cpp/issues/11681 ↩ -
Ollama-FAQ:
OLLAMA_NUM_PARALLELdefault 1, RAM skaliert mitOLLAMA_NUM_PARALLEL * OLLAMA_CONTEXT_LENGTH;OLLAMA_KV_CACHE_TYPEdefault f16 mit q8_0/q4_0-Optionen: https://docs.ollama.com/faq ↩ ↩2 ↩3 -
ggml-org/llama.cpp, tools/quantize/README.md: Q4_K_M = 4,8944 bpw an Llama-3.1-8B (≈4,85–4,9 bpw Gewichtsklasse): https://github.com/ggml-org/llama.cpp/blob/master/tools/quantize/README.md ↩ ↩2
-
vLLM-Doku, GGUF-Feature-Seite: „highly experimental and under-optimized", Migration zum OOT vllm-gguf-plugin, Basismodell-Tokenizer empfohlen: https://github.com/vllm-project/vllm/blob/main/docs/features/quantization/gguf.md ↩ ↩2
-
Ollama-Doku, Context length: <24 GiB VRAM → 4k, 24–48 GiB → 32k, ≥48 GiB → 256k,
OLLAMA_CONTEXT_LENGTH-Override: https://docs.ollama.com/context-length ; älterer flacher 4096-Default gemäß https://docs.ollama.com/faq ↩ -
vLLM EngineArgs:
gpu_memory_utilizationdefault 0,92, „Fraction of GPU memory to be used for the model executor", pro Instanz: https://docs.vllm.ai/en/latest/api/engine_args.html (vllm/config/cache.py, default=0.92) ↩ -
Qwen2.5-14B-Instruct-Model Card (48 Layer, GQA 40 Q- / 8 KV-Heads, 14,7 Mrd. Parameter) und config.json (hidden_size 5120, num_key_value_heads 8): https://huggingface.co/Qwen/Qwen2.5-14B-Instruct ↩