ManzGPU

Optimizar Llama.CPP

En esta guía verás formas de optimizar llama.cpp para exprimir al máximo y conseguir un mejor rendimiento.

Llama.cpp es un software que se actualiza diariamente, y el que va incorporando multitud de características para obtener mejor rendimiento y conseguir la mayor flexibilidad posible a la hora de cargar modelos locales en nuestro sistema. En la siguiente guía vamos a ir analizando y explicando los diferentes parámetros para que cada uno averigue cuál sería la mejor configuración para utilizar.

Si ya has instalado llama.cpp y lo tienes funcionando, el siguiente paso es optimizarlo para conseguir que aproveche al máximo tu hardware y responda lo más rápido posible. Si aún no lo has hecho, corre al artículo instalación de llama.cpp antes de continuar.

1. Parámetros de llama.cpp

Mi preferido es el modelo MoE de Qwen 3.6 de 35B. Lo he descargado cuantizado a IQ2_XXS y en formato GGUF, por lo que ocupa unos 10GB, suficiente para una tarjeta gráfica de 16GB y margen de 6GB para otras cosas como el contexto:

llama-server -m Qwen3.6-35B-A3B-UD-IQ2_XXS.gguf

A partir de ahora, iremos colocando en cada línea nuevas opciones, que tendrás que modificar según tu hardware o situación. A la misma vez iremos probando con los mismos parámetros el comando llama-bench para hacer un benchmark con dichos parámetros y saber si estamos mejorando o empeorando el rendimiento:

llama-bench -m Qwen3.6-35B-A3B-UD-IQ2_XXS.gguf

| model                     |      size | back |  test |             t/s |
|---------------------------| --------: | ---- | ----: | --------------: |
| qwen35moe 35B.A3B IQ2_XXS | 10.01 GiB | CUDA | pp512 | 2436.40 ± 27.86 |
| qwen35moe 35B.A3B IQ2_XXS | 10.01 GiB | CUDA | tg128 |   116.87 ± 3.31 |

Nos saldrá algo parecido a esto. Lo importante son las dos últimas columnas:

  • pp512 prefill: Es el procesamiento de tokens de entrada (velocidad al entender tu prompt)
  • tg128 decode: Es el procesamiento de tokens de salida (velocidad al responder)

El prefill siempre es muy rápido, mientras que el decode es más lento (y el que más se suele mirar). En este test, observa que nos ha dado 116 tokens/seg. Lo podemos tomar como referencia para ir probando con otros modelos y ver cuales nos rinden mejor en velocidad, y luego probar la calidad de sus respuestas.

En este widget, con la rueda del ratón, puedes variar y ver como es la velocidad en tokens/seg en un chat:

Otra forma para testear la velocidad del modelo, es ejecutar llama-server y abrir el servidor http://localhost:8080 para hacer prompts reales de prueba. Al responder, justo debajo te aparecen las métricas de tokens/segundo.

2. Opciones principales

Largo Corto Descripción Por defecto
1️⃣ --n-gpu-layers -ngl Capas que se cargan en GPU. -1 para el máximo posible. -1
2️⃣ --fit-target -fitt Opuesto al anterior. Indica que use el máximo salvo los MB indicados. -
2️⃣ --fit-ctx -fitc Complemento al anterior. Además, reserva un tamaño de KB para el contexto. -
3️⃣ --fit -fit Con -fit on ajusta automáticamente los parámetros anteriores. on
--flash-attn -fa Activa Flash Attention para reducir uso de VRAM en GPU modernas. on
--no-warmup - Evita el calentamiento inicial del modelo. -
--mlock - Nunca manda el modelo a disco, lo mantiene en RAM. -
--mmap / --no-mmap - Decide si cargar el modelo íntegramente en RAM o no. --mmap
  • --n-gpu-layers o -ngl: Es uno de los parámetros más importantes con el que indicamos las capas que se cargan en GPU. Por defecto, tiene el valor -1, que intenta aprovechar al máximo la GPU. Si tienes una gráfica más pequeña, puedes intentar poner un número concreto de capas, como -ngl 40, para gestionar el número de capas y obligar que el resto se haga en CPU (más lento).

    • --fit-target o -fitt: Alternativa al anterior: En lugar de indicar las capas a usar, indicas que use el máximo posible dejando una cantidad de MB libre reservada.
    • --fit-ctx o -fitc: Complemento al anterior, para reservar espacio para el contexto. Ej: -fitc 16384 reserva también 16K para el contexto.
  • --flash-attn o -fa: Intenta reducir el uso de VRAM y mejora velocidad si usas contextos largos. Si tienes una GPU moderna debería soportarlo y mejora bastante el rendimiento.

  • --no-warmup: Por defecto, llama.cpp hace un test previo antes de comenzar para «calentar» el modelo. No se recomienda desactivar, pero si lo haces puedes reducir la espera inicial si no te importa que inicialmente puedas tener resultados un poco peores.

  • --mlock: Fuerza al sistema a mantener el modelo en RAM en lugar de comprimirlo o pasarlo a disco.

  • --mmap o --no-mmap: Con --mmap (por defecto) no se carga el modelo 100% en RAM, sino sólo las partes que se van usando. Con --no-mmap se carga entero en RAM, y luego se pasa a GPU.

llama-server \
  -m Qwen3.6-35B-A3B-UD-IQ2_XXS.gguf \
  --fit-target 512 \
  --fit-ctx 131072 \
  --fit off \
  --flash-attn on \
  --mlock --mmap

Hemos activado Flash Attention, reservado 128K para el contexto y dejado libre 512MB de margen en la GPU. Además, ajustamos la CPU para que esté muy pendiente de cuando la GPU está libre para mandarle el siguiente lote de datos.

3. Contexto

El contexto es donde se guarda la información de la conversación con nuestros agentes, y es muy importante que tengamos espacio para esta información, ya que de lo contrario, no responderá correctamente. Los parámetros que nos interesan son los siguientes:

Largo Corto Descripción Por defecto
--ctx-size -c Indica el tamaño del contexto en bytes. 0 (max. del modelo)
--cache-type-k -ctk Indica la cuantización de la claves del contexto f16
--cache-type-v -ctv Indica la cuantización de los valores del contexto f16
--cache-reuse - Reutiliza tokens si se repiten fragmentos. Desactivado por defecto. 0

Con --ctx-size establecemos un tamaño particular para el contexto. Cada modelo tiene un tamaño máximo de contexto. Por ejemplo, Qwen 3.6 35B tiene un máximo de 256KB. Si no indicas valor intenta usar el máximo. Luego, con -ctk y -ctv estableces una cuantización para el contexto, con lo que puedes ahorrar algo más de espacio:

llama-server \
  -m Qwen3.6-35B-A3B-UD-IQ2_XXS.gguf \
  --fit-target 512 --fit-ctx 131072 --fit off \
  --flash-attn on --mlock --mmap \
  --ctx-size 131072 -ctk q4_0 -ctv q4_0 --cache-reuse 256

4. Procesamiento

Otro punto fundamental de llama.cpp es como se procesan los tokens y la información, así como se distribuye. Con estos parámetros podemos ajustar su forma de trabajar:

Largo Corto Descripción Por defecto
--cont-batching -cb Optimiza y agrupa datos siempre que sea posible. -cb
--parallel -np Establece un número de slots para tareas paralelas. auto
--batch-size -b Máximo de tokens a procesar en prefill. 2048
--ubatch-size -ub Divide en trozos el anterior para que la GPU procese más fácil. 512
--poll - Con 100 comprueba constantemente si la GPU terminó para enviar más datos. 50
  • -np: Si tienes suficiente VRAM disponible, puedes aumentar a 2 e ir alternando entre slots. Sin embargo, es importante tener en cuenta que cada slot tiene un caché a parte, por lo que el consumo de VRAM se dispara. El parámetro -cb donde es especialmente útil es en valores de -np superiores a 1 (aún así, sigue siendo positivo tenerlo activo).

  • -b y -ub se encargan de determinar los tamaños de los trozos a procesar por llama.cpp.

  • --poll: Con un valor de 100, sirve para que la CPU compruebe constantemente si la GPU ha terminado para mandarle el siguiente lote de tareas y aprovechar lo mejor posible el tiempo. Con valores bajos, no comprueba y puede tardar más en responder, pero hace uso menos intensivo de CPU.

llama-server \
  -m Qwen3.6-35B-A3B-UD-IQ2_XXS.gguf \
  --fit-target 512 --fit-ctx 131072 --fit off \
  --flash-attn on --mlock --mmap \
  --ctx-size 131072 -ctk q4_0 -ctv q4_0 --cache-reuse 256 \
  -b 4096 -ub 1024 --poll 100

5. Razonamiento

Algunos modelos LLM tienen un comportamiento de Thinking o Reasoning. Antes de responderte, activan un proceso de razonamiento donde exploran caminos antes de darte una respuesta. Tenemos algunos parámetros relevantes para ello:

Largo Corto Descripción Por defecto
--reasoning -rea Activa on o desactiva off el razonamiento. auto
--reasoning-budget Limita el máximo de tokens de razonamiento. -1 sin límite. -1

El razonamiento está activo por defecto, ya que suele mejorar las respuestas y ofrece datos relevantes de forma anticipada. Aún así, con -rea off se puede desactivar. Lo más relevante es --reasoning-budget, un parámetro con el que podemos limitar el razonamiento a un número de tokens específico.

Así pues, con --reasoning-budget 1024 indicaremos que el modelo no puede usar más de 1024 tokens para pensar (puede terminar antes), pero como máximo establece ese límite. Si lo excede, el pensamiento termina y el modelo te da la respuesta con lo razonado hasta el momento. Valores menores de 512 ofrecen respuestas rápidas, 512-1024 equilibradas, alrededor de 4096 ofrecen razonamiento profundo y -1 sin límite, el modelo decide.

llama-server \
  -m Qwen3.6-35B-A3B-UD-IQ2_XXS.gguf \
  --fit-target 512 --fit-ctx 131072 --fit off \
  --flash-attn on --mlock --mmap \
  --ctx-size 131072 -ctk q4_0 -ctv q4_0 --cache-reuse 256 \
  -b 4096 -ub 1024 --poll 100 \
  --reasoning-budget 2048

6. Temperatura

Los denominados parámetros del modelo son ciertos detalles que permiten personalizar el comportamiento que produce el modelo. El más popular es la temperatura: valores muy bajos hacen que el modelo devuelva respuestas deterministas y conservadoras (siempre iguales o muy parecidas), mientras que valores muy altos devuelven respuestas más aleatorias y creativas.

Los más interesantes de estos parámetros son los siguientes:

Largo Descripción Default Disabled Coding Reasoning
--temp Temperatura: Aleatoriedad, más bajo = más determinista 0.80 - 0.6 1
--top-k Filtra tokens muy improbables (solo 20 más probables) 40 0 20 20
--top-p Considera tokens por encima de 95% de probabilidad. 0.95 1 0.95 0.95
--min-p Tercer filtro. 0.05 0 0 0
--repeat-penalty Penaliza tokens que ya aparecieron 1 1 1 1
--presence-penalty Igual al anterior, pero compatible con OpenAI. 0 0 0 1.5
--frequency-penalty Penaliza tokens (penaliza más cuanto más aparece) 0 0 0 0

En la web de los modelos que utilizas, suelen venir una serie de indicaciones para modificar estos parámetros según tu objetivo: tareas generales, coding, tareas de razonamiento profundo, etc. Con estos parámetros, los modelos funcionan mejor para esos propósitos.

llama-server \
  -m Qwen3.6-35B-A3B-UD-IQ2_XXS.gguf \
  --fit-target 512 --fit-ctx 131072 --fit off \
  --flash-attn on --mlock --mmap \
  --ctx-size 131072 -ctk q4_0 -ctv q4_0 --cache-reuse 256 \
  -b 4096 -ub 1024 --poll 100 \
  --reasoning-budget 2048 \
  --temp 0.6 --top-k 20 --top-p 0.95 --min-p 0

7. Speculative Decoding

Esta técnica permite acelerar la generación de texto sin modificar la calidad del resultado. Se basa en utilizar un draft (un modelo pequeño y rápido) para proponer varios tokens de golpe. Luego, el modelo grande verifica los tokens en paralelo, en un solo paso. Si el draft es capaz de acertar con las predicciones, acelera mucho la generación de texto.

Los primeros no requieren drafts pequeños:

Largo Requiere draft Descripción
--spec-type none No usa speculative decoding (comportamiento por defecto).
--spec-type ngram-simple Busca secuencias repetidas en el contexto y las propone.
--spec-type ngram-map-k Igual, pero con tabla hash.
--spec-type ngram-map-k4v Igual, pero optimizada para contextos muy largos.
--spec-type ngram-mod Ngram con longitud de lookup variable. Más preciso.
--spec-type ngram-cache Usa archivo de caché externo con ngrams precalculados.
--spec-type draft-simple Draft propone tokens, grande verifica varios a la vez.
--spec-type draft-eagle3 Variante con arquitectura EAGLE3. Más eficiente.
--spec-type draft-mtp MTP Multi-Token prediction. Predice varios tokens.
--spec-draft-n-min - Mínimo de tokens draft. Con ngram-* valores de 8. En MTP valores de 2.
--spec-draft-n-max - Máximo de tokens draft. Con ngram-* valores de 16. En MTP valores de 3.

Los 3 últimos, requieren un modelo pequeño, mientras que MTP incluye el draft en el propio modelo principal, por lo que el coste del draft es casi nulo.

llama-server \
  -m Qwen3.6-35B-A3B-UD-IQ2_XXS-MTP.gguf \
  --fit-target 512 --fit-ctx 131072 --fit off \
  --flash-attn on --mlock --mmap \
  --ctx-size 131072 -ctk q4_0 -ctv q4_0 --cache-reuse 256 \
  -b 4096 -ub 1024 --poll 100 \
  --reasoning-budget 2048 \
  --temp 0.6 --top-k 20 --top-p 0.95 --min-p 0 \
  --spec-type draft-mtp --spec-draft-n-min 1 --spec-draft-n-max 3

Donde más notorio es el speculative decoding es en los modelos densos, aunque en los MoE también ofrece pequeñas mejoras.

8. Otros

Algunos otros parámetros interesantes son los siguientes:

Largo Descripción
--port Puerto donde está escuchando en el servidor. Por defecto, 8080.
--host IP donde está escuchando el servidor. Por defecto, 127.0.0.1.

Si tienes el puerto 8080 ocupado, puedes modificarlo mediante --port. Además, recuerda que si estás usando llama.cpp como servidor y quieres usarlo desde otro equipo en la misma red, tienes que exponerlo escuchando en el puerto 0.0.0.0 con --host:

llama-server \
  -m Qwen3.6-35B-A3B-UD-IQ2_XXS-MTP.gguf \
  --fit-target 512 --fit-ctx 131072 --fit off \
  --flash-attn on --mlock --mmap \
  --ctx-size 131072 -ctk q4_0 -ctv q4_0 --cache-reuse 256 \
  -b 4096 -ub 1024 --poll 100 \
  --reasoning-budget 2048 \
  --temp 0.6 --top-k 20 --top-p 0.95 --min-p 0 \
  --spec-type draft-mtp --spec-draft-n-min 1 --spec-draft-n-max 3 \
  --port 8999 --host 0.0.0.0