Processamento de prompt do llama.cpp 35x mais lento? Corrija o KV cache q5_1
Flash attention mais um KV cache q5_1 podem empurrar a atenção para a CPU. Como confirmar, corrigir com q8_0 e quando uma API é mais simples.

Nesta página
Seu modelo local responde bem, mas agora todo prompt longo fica parado por um minuto e meio enquanto a GPU não faz nada. Se você roda llama.cpp com -fa on e um KV cache q5_1, essa provavelmente é a causa: o build CUDA padrão não tem kernel de flash-attention para esse tipo de cache, então a etapa de atenção roda silenciosamente na CPU. Trocar o cache para q8_0 levou um relator de 38 para 1348 tokens/s no processamento de prompt.
Os números abaixo vêm da issue #28455 do llama.cpp (aberta em 5 de setembro de 2026, build 10791, verificada em 28 de outubro de 2026). Um relator, uma RTX 4080, um modelo 27B, então leia como um exemplo prático, não como uma lei. A análise de causa raiz também é dele: um mantenedor chamou de "problema conhecido" e fechou a issue no dia seguinte.
Como isso aparece na tela#
A configuração era comum. Alguém queria um contexto de 131072 tokens em uma única placa de 16 GB, então reduziu o KV cache para q5_1:
llama-server -m model.gguf -ngl 99 -fa on -c 131072 -np 4 \
--cache-type-k q5_1 --cache-type-v q5_1Depois enviou um prompt de 3,6K tokens. O processamento de prompt rodou a 38,4 tokens/s e a decodificação a 6,5 tokens/s. Faça a divisão: 3.600 ÷ 38,4 = 93,75, ou seja, cerca de 94 segundos antes da primeira palavra. Com q8_0 o mesmo prompt rodou a 1348 tokens/s: 3.600 ÷ 1.348 = 2,67, menos de três segundos.
A pista está no gerenciador de tarefas. Durante as execuções lentas a GPU ficava perto de 0% enquanto a CPU mostrava cerca de 930% (nove ou dez núcleos ocupados). Uma GPU ociosa enquanto você "roda na GPU" é o sintoma a procurar.

Por que um cache menor deixa tudo tão mais lento#
Flash attention é um kernel de GPU fundido. O build CUDA padrão o inclui apenas para alguns pares de tipos de KV cache. Para q4_0, q4_1, q5_0 e q5_1 não há kernel, então o llama.cpp não para com erro. Ele move essa operação para a CPU e continua. Tudo ainda funciona, só que cerca de 35 vezes mais lento no processamento de prompt (1348 ÷ 38,4 = 35,1).
Esse "silenciosamente" é o problema todo. Nada na resposta te avisa. O processamento de prompt cai mais (cerca de 35×), e a geração também desacelera: 6,5 tokens/s contra 30,1 com q8_0 na mesma issue.
Verifique em dois minutos#
Rode llama-bench com os mesmos tipos de cache que você usa no servidor, uma vez por variante, e observe a GPU em outro terminal:
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 1Os resultados de pp512 do relator em um Qwen 27B Q5_K_XL: 1511,92 tokens/s para q8_0/q8_0, cerca de 197 para q5_1/q5_1 no build padrão. Se suas duas linhas mostrarem uma diferença dessas e nvidia-smi mostrar a GPU ociosa durante a segunda, você encontrou o problema.
Antes de corrigir qualquer coisa, relacione o que você vê com a causa provável:
Emparelhar os pares
Relacione cada sintoma à sua causa
Toque num item à esquerda, depois no seu par
- GPU a ~0%, CPU a ~930% durante um prompt longoA atenção está rodando na CPU
- Decodificação cai para ~6,5 tokens/s contra 30,1 com
q8_0A geração também desacelera, não só o processamento de prompt - As mesmas flags são rápidas com
q8_0Este par de tipos de cache não tem kernel de flash-attention de GPU no build padrão
Correção 1: use q8_0 (ou recompile)#
A correção mais rápida é mudar duas flags e manter todo o resto:
llama-server -m model.gguf -ngl 99 -fa on -c 131072 -np 4 \
--cache-type-k q8_0 --cache-type-v q8_0Na issue isso deu 1348 tokens/s no processamento de prompt e 30,1 tokens/s na decodificação (acima de 6,5). O preço é memória: um cache q8_0 é maior que q5_1, então verifique se o comprimento de contexto ainda cabe na VRAM.
Se você precisa manter q5_1 por questões de memória, recompile com todas as combinações de cache de flash-attention incluídas:
cmake -B build -DGGML_CUDA=ON -DGGML_CUDA_FA_ALL_QUANTS=ON
cmake --build build --config Release -jEsse build rodou q5_1 a 1509,70 tokens/s em pp512 e 1162 tokens/s no prompt de 3,6K tokens, com decodificação a 38,5 tokens/s. Um comentarista da issue observou que mover o trabalho entre backends pode mudar um pouco os resultados numéricos e sugeriu uma comparação de perplexidade entre builds. Se você se importa com saídas exatas, faça uma.
Comparar
Qual correção se encaixa na sua placa?
Cache q8_0
Mude --cache-type-k e --cache-type-v para q8_0. Sem recompilar. Usa mais VRAM que q5_1, então confira de novo o tamanho de contexto que cabe.
Recompilar com FA_ALL_QUANTS
Mantenha q5_1 e compile com -. Mesma VRAM de antes, mas você mantém seu próprio build e a compilação demora mais.
A resposta de "problema conhecido" do mantenedor não diz se as versões atuais do llama.cpp mudaram isso. A verificação honesta é o par de llama-bench acima: se as duas linhas estiverem próximas, você está bem.
Quando o tuning deixa de valer a pena#
Digamos que você conseguiu a correção e agora está avaliando a próxima rodada: mais flags, uma segunda GPU, um quant menor. Se o trabalho é resumos, revisão de código ou extração em prompts de alguns milhares de tokens, pergunte quanto uma requisição custa em tempo e esforço, não só em watts.
Aqui está uma carga de trabalho declarada para comparar. Digamos que um job de sumarização envia 3.600 tokens de entrada e recebe 500 de volta, 1.000 vezes. Na CheapTokens isso é cerca de $0.104 no DeepSeek-V4-Flash (contexto de 380K, até 32.768 tokens de saída por resposta, um preço a qualquer hora) e cerca de $0.092 no GLM-5.3-Flash (contexto de 390K). A tabela conta entrada e saída juntas, com uma coluna OpenRouter para comparar:
| Modelo | Entrada $/1M | Saída $/1M | Por solicitação | 1.000 solicitações | OpenRouter, 1.000 solicitações |
|---|---|---|---|---|---|
| GLM-5.3-Flash | $0.02 | $0.04 | $0.000092 | $0.092 | $0.187 |
| DeepSeek-V4-Flash | $0.015 | $0.10 | $0.0001 | $0.104 | $0.249 |
| MiniMax-M2.7 | $0.05 | $0.15 | $0.00026 | $0.255 | $1.68 |
3.600 tokens de entrada e 500 tokens de saída por solicitação. Os preços por 1M de tokens são atuais e mudam junto com nossas tarifas; a coluna OpenRouter mostra preços de referência para a mesma carga de trabalho.
A API não se importa com seu tipo de cache, sua VRAM ou suas flags de build; não há nada para cair de volta na CPU. Envie alguns dos seus prompts reais primeiro e julgue as respostas você mesmo. O passo é pequeno: o endpoint fala o formato OpenAI Chat Completions, então a maioria dos clientes locais só precisa de uma nova base URL.
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}'A configuração completa está na documentação da CheapTokens, e os preços atuais por modelo estão na página de preços. Para uma análise mais longa de hardware versus API, veja Rodar DeepSeek localmente ou usar uma API. Se você quer ver como entrada e saída são cobradas separadamente, tokens de entrada vs saída cobre isso.
A ordem para seguir#
Colocar em ordem
Coloque os passos de solução de problemas em ordem
Arraste os itens ou use as setas
- Rode llama-bench para q8_0 e q5_1 e observe nvidia-smi
- Mude os dois tipos de cache para q8_0
- Verifique se o comprimento de contexto ainda cabe na VRAM
- Recompile com GGML_CUDA_FA_ALL_QUANTS=ON só se você precisar de q5_1
- Compare o mesmo prompt em uma API se a configuração local ainda não valer o esforço
Mais um aviso sobre fontes: todo o diagnóstico se apoia em uma issue pública e uma GPU. Trate 1348 e 38,4 como o que aconteceu ali, e meça sua própria placa antes de confiar em qualquer um dos dois.



