Zurück zum Blog

FehlerbehebungAnleitung

llama.cpp Prompt-Verarbeitung 35x langsamer? Behebe den q5_1-KV-Cache

Flash Attention plus ein q5_1-KV-Cache können Attention auf die CPU verlagern. So bestätigst du es, behebst es mit q8_0 und erkennst, wann eine API einfacher ist.

Von CheapTokens TeamVeröffentlicht am 6 Min. Lesezeit

Terminal mit GPU bei 0 Prozent und CPU bei 930 Prozent während der llama.cpp-Prompt-Verarbeitung
Auf dieser Seite
  1. Wie es auf dem Bildschirm aussieht
  2. Warum ein kleinerer Cache es so viel langsamer macht
  3. Prüfe es in zwei Minuten
  4. Fix 1: q8_0 verwenden (oder neu bauen)
  5. Wann Tuning nicht mehr lohnt
  6. Die Reihenfolge, in der du vorgehst

Dein lokales Modell antwortet gut, aber jeder lange Prompt braucht jetzt anderthalb Minuten, während die GPU nichts tut. Wenn du llama.cpp mit -fa on und einem q5_1-KV-Cache betreibst, ist das wahrscheinlich die Ursache: Der Standard-CUDA-Build hat keinen Flash-Attention-Kernel für diesen Cache-Typ, also läuft der Attention-Schritt still auf der CPU. Der Wechsel des Caches auf q8_0 brachte bei einem Melder 1348 statt 38 Tokens/s bei der Prompt-Verarbeitung.

Die Zahlen unten stammen aus llama.cpp Issue #28455 (eröffnet am 5. September 2026, Build 10791, geprüft am 28. Oktober 2026). Ein Melder, eine RTX 4080, ein 27B-Modell – lies sie also als durchgerechnetes Beispiel, nicht als Gesetz. Auch die Root-Cause-Analyse stammt von ihm: Ein Maintainer nannte es „a known issue“ und schloss das Issue am nächsten Tag.

Wie es auf dem Bildschirm aussieht#

Das Setup war gewöhnlich. Jemand wollte einen Kontext von 131072 Tokens auf einer einzelnen 16-GB-Karte, also verkleinerte er den KV-Cache auf q5_1:

bash
llama-server -m model.gguf -ngl 99 -fa on -c 131072 -np 4 \
  --cache-type-k q5_1 --cache-type-v q5_1

Dann schickte er einen Prompt mit 3,6K Tokens. Die Prompt-Verarbeitung lief mit 38,4 Tokens/s und das Decoding mit 6,5 Tokens/s. Rechne nach: 3.600 ÷ 38,4 = 93,75, also etwa 94 Sekunden bis zum ersten Wort. Mit q8_0 lief derselbe Prompt mit 1348 Tokens/s: 3.600 ÷ 1.348 = 2,67, unter drei Sekunden.

Der Hinweis steckt im Task-Manager. Während der langsamen Läufe blieb die GPU bei nahezu 0 %, während die CPU etwa 930 % zeigte (neun oder zehn Kerne beschäftigt). Eine GPU, die im Leerlauf ist, während du „auf der GPU läufst“, ist das Symptom, nach dem du suchen musst.

Prompt-Verarbeitungsgeschwindigkeit mit q5_1- und q8_0-KV-Cache
Prompt-Eval bei einem Prompt mit 3,6K Tokens, RTX 4080, llama.cpp Issue #28455 (5. September 2026)

Warum ein kleinerer Cache es so viel langsamer macht#

Flash Attention ist ein fusionierter GPU-Kernel. Der Standard-CUDA-Build liefert ihn nur für einige KV-Cache-Typ-Paare. Für q4_0, q4_1, q5_0 und q5_1 gibt es keinen Kernel, also bricht llama.cpp nicht mit einem Fehler ab. Es verschiebt diese Operation auf die CPU und macht weiter. Alles funktioniert noch, nur etwa 35-mal langsamer bei der Prompt-Verarbeitung (1348 ÷ 38,4 = 35,1).

Dieses „still“ ist das ganze Problem. Nichts in der Antwort sagt es dir. Die Prompt-Verarbeitung fällt am stärksten ab (etwa 35×), und auch die Generierung wird langsamer: 6,5 Tokens/s gegenüber 30,1 mit q8_0 im selben Issue.

Prüfe es in zwei Minuten#

Führe llama-bench mit denselben Cache-Typen aus, die du im Server verwendest, einmal pro Variante, und beobachte die GPU in einem anderen Terminal:

bash
llama-bench -m model.gguf -ngl 99 -fa 1 -ctk q8_0 -ctv q8_0 -p 512 -n 0
llama-bench -m model.gguf -ngl 99 -fa 1 -ctk q5_1 -ctv q5_1 -p 512 -n 0
nvidia-smi -l 1

Die pp512-Ergebnisse des Melders auf einem Qwen 27B Q5_K_XL: 1511,92 Tokens/s für q8_0/q8_0, etwa 197 für q5_1/q5_1 im Standard-Build. Wenn deine beiden Zeilen eine solche Lücke zeigen und nvidia-smi zeigt, dass die GPU während der zweiten im Leerlauf ist, hast du es gefunden.

Bevor du etwas behebst, ordne das, was du siehst, der wahrscheinlichen Ursache zu:

Paare zuordnen

Ordne jedes Symptom seiner Ursache zu

  • GPU bei ~0 %, CPU bei ~930 % während eines langen PromptsAttention läuft auf der CPU
  • Decoding fällt auf ~6,5 Tokens/s gegenüber 30,1 mit q8_0Auch die Generierung wird langsamer, nicht nur die Prompt-Verarbeitung
  • Dieselben Flags sind mit q8_0 schnellDieses Cache-Typ-Paar hat keinen GPU-Flash-Attention-Kernel im Standard-Build

Fix 1: q8_0 verwenden (oder neu bauen)#

Der schnellste Fix ist, zwei Flags zu ändern und alles andere zu behalten:

bash
llama-server -m model.gguf -ngl 99 -fa on -c 131072 -np 4 \
  --cache-type-k q8_0 --cache-type-v q8_0

Im Issue ergab das 1348 Tokens/s bei der Prompt-Verarbeitung und 30,1 Tokens/s beim Decoding (statt 6,5). Der Preis ist Speicher: Ein q8_0-Cache ist größer als q5_1, prüfe also, ob deine Kontextlänge noch in den VRAM passt.

Wenn du q5_1 aus Speichergründen behalten musst, baue neu mit allen Flash-Attention-Cache-Kombinationen einkompiliert:

bash
cmake -B build -DGGML_CUDA=ON -DGGML_CUDA_FA_ALL_QUANTS=ON
cmake --build build --config Release -j

Dieser Build lief mit q5_1 bei 1509,70 Tokens/s auf pp512 und mit 1162 Tokens/s bei dem Prompt mit 3,6K Tokens, mit Decoding bei 38,5 Tokens/s. Ein Kommentator im Issue wies darauf hin, dass das Verschieben der Arbeit zwischen Backends die numerischen Ergebnisse etwas verändern könnte, und schlug einen Perplexity-Vergleich zwischen den Builds vor. Wenn dir exakte Ausgaben wichtig sind, führe einen durch.

Vergleichen

Welcher Fix passt zu deiner Karte?

q8_0-Cache

Ändere --cache-type-k und --cache-type-v auf q8_0. Kein Neubau. Verbraucht mehr VRAM als q5_1, prüfe also die Kontextgröße, die du unterbringen kannst, erneut.

Neu bauen mit FA_ALL_QUANTS

Behalte q5_1 und baue mit -DGGML_CUDA_FA_ALL_QUANTS=ON. Gleicher VRAM wie zuvor, aber du pflegst deinen eigenen Build und die Kompilierung dauert länger.

Die „known issue“-Antwort des Maintainers sagt nicht, ob aktuelle llama.cpp-Versionen das geändert haben. Die ehrliche Prüfung ist das llama-bench-Paar oben: Wenn beide Zeilen nah beieinander liegen, bist du fein raus.

Wann Tuning nicht mehr lohnt#

Angenommen, du hast den Fix zum Laufen gebracht und wägst jetzt die nächste Runde ab: mehr Flags, eine zweite GPU, ein kleineres Quant. Wenn die Aufgabe Zusammenfassungen, Code-Review oder Extraktion bei Prompts von einigen tausend Tokens ist, frag, was eine Anfrage dich an Zeit und Aufwand kostet, nicht nur an Watt.

Hier ist eine angegebene Workload zum Vergleichen. Angenommen, ein Zusammenfassungs-Job sendet 3.600 Input-Tokens und bekommt 500 zurück, 1.000-mal. Auf CheapTokens sind das etwa $0.104 bei DeepSeek-V4-Flash (380K Kontext, bis zu 32.768 Output-Tokens pro Antwort, ein Preis zu jeder Stunde) und etwa $0.092 bei GLM-5.3-Flash (390K Kontext). Die Tabelle zählt Input und Output zusammen, mit einer OpenRouter-Spalte zum Vergleich:

Modell Pro Anfrage 1.000 Anfragen OpenRouter, 1.000 Anfragen
GLM-5.3-Flash $0.000092 $0.092 $0.187
DeepSeek-V4-Flash $0.0001 $0.104 $0.249
MiniMax-M2.7 $0.00026 $0.255 $1.68

3.600 Input- und 500 Output-Tokens pro Anfrage. Die Preise pro 1 Mio. Tokens sind aktuell und ändern sich zusammen mit unseren Tarifen; die OpenRouter-Spalte zeigt Referenzpreise für dieselbe Arbeitslast.

Die API kümmert sich nicht um deinen Cache-Typ, deinen VRAM oder deine Build-Flags; es gibt nichts, was auf die CPU zurückfallen kann. Schick zuerst ein paar deiner echten Prompts und beurteile die Antworten selbst. Der Schritt ist klein: Der Endpoint spricht das OpenAI-Chat-Completions-Format, die meisten lokalen Clients brauchen also nur eine neue Base-URL.

bash
curl https://api.cheaptokens.dev/v1/chat/completions \
  -H "Authorization: Bearer $CHEAPTOKENS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "deepseek-ai/DeepSeek-V4-Flash-0731", "messages": [{"role": "user", "content": "Summarize the text below in 5 bullets: ..."}], "max_tokens": 500}'

Das vollständige Setup steht in der CheapTokens-Doku, und die aktuellen Preise pro Modell findest du auf der Preisseite. Für einen längeren Blick auf Hardware versus API siehe DeepSeek lokal ausführen oder eine API nutzen. Wenn du sehen willst, wie Input und Output getrennt abgerechnet werden, deckt Input- vs. Output-Tokens das ab.

Die Reihenfolge, in der du vorgehst#

In die richtige Reihenfolge bringen

Bringe die Troubleshooting-Schritte in die richtige Reihenfolge

  1. Führe llama-bench für q8_0 und q5_1 aus und beobachte nvidia-smi
  2. Stelle beide Cache-Typen auf q8_0 um
  3. Prüfe, ob die Kontextlänge noch in den VRAM passt
  4. Baue nur dann mit GGML_CUDA_FA_ALL_QUANTS=ON neu, wenn du q5_1 brauchst
  5. Vergleiche denselben Prompt mit einer API, wenn das lokale Setup den Aufwand immer noch nicht wert ist

Noch eine Vorsicht zu den Quellen: Die ganze Diagnose stützt sich auf ein öffentliches Issue und eine GPU. Behandle 1348 und 38,4 als das, was dort passiert ist, und miss deine eigene Karte, bevor du einem von beiden vertraust.