Powrót do bloga

Rozwiązywanie problemówPrzewodnik

Przetwarzanie promptu w llama.cpp 35x wolniejsze? Napraw pamięć KV q5_1

Flash attention plus pamięć KV q5_1 może przenieść uwagę na CPU. Jak to potwierdzić, naprawić przez q8_0 i kiedy API jest prostsze.

Autor: CheapTokens TeamOpublikowano 5 min czytania

Terminal pokazujący GPU na 0 procent i CPU na 930 procent podczas przetwarzania promptu w llama.cpp
Na tej stronie
  1. Jak to wygląda na ekranie
  2. Dlaczego mniejsza pamięć powoduje aż takie spowolnienie
  3. Sprawdź to w dwie minuty
  4. Poprawka 1: użyj q8_0 (albo przebuduj)
  5. Kiedy dostrajanie przestaje się opłacać
  6. Kolejność działań

Twój lokalny model odpowiada poprawnie, ale każdy długi prompt wisi teraz przez półtorej minuty, podczas gdy GPU nic nie robi. Jeśli uruchamiasz llama.cpp z -fa on i pamięcią KV q5_1, to prawdopodobnie przyczyna: domyślna kompilacja CUDA nie ma jądra flash-attention dla tego typu pamięci, więc krok uwagi po cichu wykonuje się na CPU. Przełączenie pamięci na q8_0 podniosło u jednego zgłaszającego przetwarzanie promptu z 38 do 1348 tokenów/s.

Poniższe liczby pochodzą z issue #28455 w llama.cpp (otwarte 5 września 2026, kompilacja 10791, sprawdzone 28 października 2026). Jeden zgłaszający, jedna RTX 4080, jeden model 27B, więc czytaj je jako przykład, nie jako regułę. Ich analiza przyczyny źródłowej też jest ich własna: opiekun nazwał to „znanym problemem” i zamknął issue następnego dnia.

Jak to wygląda na ekranie#

Konfiguracja była zwyczajna. Ktoś chciał kontekst 131072 tokenów na jednej karcie 16 GB, więc zmniejszył pamięć KV do 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

Potem wysłał prompt o 3,6K tokenów. Przetwarzanie promptu działało z prędkością 38,4 tokena/s, a dekodowanie z 6,5 tokena/s. Policz: 3 600 ÷ 38,4 = 93,75, czyli około 94 sekund do pierwszego słowa. Z q8_0 ten sam prompt działał z prędkością 1348 tokenów/s: 3 600 ÷ 1 348 = 2,67, poniżej trzech sekund.

Objaw widać w menedżerze zadań. Podczas wolnych przebiegów GPU było blisko 0%, a CPU pokazywało około 930% (zajęte dziewięć lub dziesięć rdzeni). GPU, które nic nie robi, gdy „działasz na GPU”, to objaw, którego szukasz.

Prędkość przetwarzania promptu z pamięcią KV q5_1 i q8_0
Ewaluacja promptu o 3,6K tokenów, RTX 4080, llama.cpp issue #28455 (5 września 2026)

Dlaczego mniejsza pamięć powoduje aż takie spowolnienie#

Flash attention to zintegrowane jądro GPU. Domyślna kompilacja CUDA dostarcza je tylko dla niektórych par typów pamięci KV. Dla q4_0, q4_1, q5_0 i q5_1 nie ma jądra, więc llama.cpp nie zatrzymuje się z błędem. Przenosi tę operację na CPU i działa dalej. Wszystko nadal działa, tylko około 35 razy wolniej przy przetwarzaniu promptu (1348 ÷ 38,4 = 35,1).

To „po cichu” jest całym problemem. Nic w odpowiedzi ci tego nie mówi. Przetwarzanie promptu spada najbardziej (około 35×), a generowanie też zwalnia: 6,5 tokena/s wobec 30,1 z q8_0 w tym samym issue.

Sprawdź to w dwie minuty#

Uruchom llama-bench z tymi samymi typami pamięci, których używasz w serwerze, raz na wariant, i obserwuj GPU w innym terminalu:

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

Wyniki pp512 zgłaszającego na Qwen 27B Q5_K_XL: 1511,92 tokena/s dla q8_0/q8_0, około 197 dla q5_1/q5_1 w domyślnej kompilacji. Jeśli twoje dwie linie pokazują taką różnicę, a nvidia-smi pokazuje bezczynne GPU podczas drugiej, to właśnie to znalazłeś.

Zanim cokolwiek naprawisz, dopasuj to, co widzisz, do prawdopodobnej przyczyny:

Dopasuj pary

Dopasuj każdy objaw do jego przyczyny

  • GPU na ~0%, CPU na ~930% podczas długiego promptuUwaga działa na CPU
  • Dekodowanie spada do ~6,5 tokena/s wobec 30,1 z q8_0Generowanie też zwalnia, nie tylko przetwarzanie promptu
  • Te same flagi są szybkie z q8_0Ta para typów pamięci nie ma jądra flash-attention na GPU w domyślnej kompilacji

Poprawka 1: użyj q8_0 (albo przebuduj)#

Najszybsza poprawka to zmiana dwóch flag i zachowanie całej reszty:

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

W issue dało to 1348 tokenów/s przy przetwarzaniu promptu i 30,1 tokena/s przy dekodowaniu (wzrost z 6,5). Ceną jest pamięć: pamięć q8_0 jest większa niż q5_1, więc sprawdź, czy twoja długość kontekstu nadal mieści się w VRAM.

Jeśli musisz zachować q5_1 ze względu na pamięć, przebuduj z wszystkimi kombinacjami pamięci flash-attention wkompilowanymi:

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

Ta kompilacja uruchomiła q5_1 z prędkością 1509,70 tokena/s na pp512 i 1162 tokenów/s na prompcie o 3,6K tokenów, z dekodowaniem na poziomie 38,5 tokena/s. Komentujący w issue zauważył, że przenoszenie pracy między backendami może nieco zmienić wyniki numeryczne, i zasugerował porównanie perplexity między kompilacjami. Jeśli zależy ci na dokładnych wynikach, zrób takie porównanie.

Porównaj

Która poprawka pasuje do twojej karty?

Pamięć q8_0

Zmień --cache-type-k i --cache-type-v na q8_0. Bez przebudowy. Zużywa więcej VRAM niż q5_1, więc ponownie sprawdź, jaki rozmiar kontekstu się zmieści.

Przebudowa z FA_ALL_QUANTS

Zachowaj q5_1 i zbuduj z -DGGML_CUDA_FA_ALL_QUANTS=ON. Tyle samo VRAM co wcześniej, ale utrzymujesz własną kompilację i kompilacja trwa dłużej.

Odpowiedź opiekuna „znany problem” nie mówi, czy obecne wersje llama.cpp to zmieniły. Uczciwym sprawdzeniem jest para llama-bench powyżej: jeśli obie linie są blisko siebie, wszystko jest w porządku.

Kiedy dostrajanie przestaje się opłacać#

Powiedzmy, że poprawka zadziałała i teraz rozważasz kolejną rundę: więcej flag, druga GPU, mniejsza kwantyzacja. Jeśli zadanie to streszczenia, przegląd kodu lub ekstrakcja na promptach o kilku tysiącach tokenów, zapytaj, ile żądanie kosztuje cię czasu i wysiłku, a nie tylko watów.

Oto podane obciążenie do porównania. Powiedzmy, że zadanie streszczania wysyła 3600 tokenów wejściowych i dostaje 500 z powrotem, 1000 razy. W CheapTokens to około $0.104 na DeepSeek-V4-Flash (kontekst 380K, do 32 768 tokenów wyjściowych na odpowiedź, jedna cena o każdej porze) i około $0.092 na GLM-5.3-Flash (kontekst 390K). Tabela liczy wejście i wyjście razem, z kolumną OpenRouter do porównania:

Model Za żądanie 1000 żądań OpenRouter, 1000 żądań
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

3600 tokenów wejściowych i 500 tokenów wyjściowych na żądanie. Ceny za 1 mln tokenów są aktualne i zmieniają się wraz z naszymi taryfami; kolumna OpenRouter pokazuje ceny referencyjne dla tego samego obciążenia.

API nie obchodzi twój typ pamięci, twoja VRAM ani flagi kompilacji; nie ma czego przenosić na CPU. Najpierw wyślij kilka swoich prawdziwych promptów i sam oceń odpowiedzi. Krok jest mały: endpoint mówi w formacie OpenAI Chat Completions, więc większość lokalnych klientów potrzebuje tylko nowego bazowego 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}'

Pełna konfiguracja jest w dokumentacji CheapTokens, a aktualne ceny poszczególnych modeli na stronie z cenami. Szersze spojrzenie na sprzęt kontra API znajdziesz w Run DeepSeek locally or use an API. Jeśli chcesz zobaczyć, jak wejście i wyjście są rozliczane osobno, input vs output tokens to omawia.

Kolejność działań#

Ustaw w kolejności

Ułóż kroki rozwiązywania problemów w kolejności

  1. Uruchom llama-bench dla q8_0 i q5_1 i obserwuj nvidia-smi
  2. Przełącz oba typy pamięci na q8_0
  3. Sprawdź, czy długość kontekstu nadal mieści się w VRAM
  4. Przebuduj z GGML_CUDA_FA_ALL_QUANTS=ON tylko jeśli potrzebujesz q5_1
  5. Porównaj ten sam prompt na API, jeśli lokalna konfiguracja nadal nie jest warta wysiłku

Jeszcze jedno ostrzeżenie o źródłach: cała diagnoza opiera się na jednym publicznym issue i jednej GPU. Traktuj 1348 i 38,4 jako to, co wydarzyło się tam, i zmierz własną kartę, zanim zaufasz któremukolwiek z nich.