Los controles del motor que importan
La mayoría de los valores por omisión de los motores son sanos para una
demo y equivocados para el uso real. Tres o cuatro controles cambian
resultados: longitud de contexto, descarga a GPU, tipo de caché KV y
flash attention. Todo lo demás es afinar al margen. Esta página usa
nombres de flags de llama.cpp, con los equivalentes de Ollama al final —
los conceptos se transfieren a todo motor.
Longitud de contexto: la trampa del valor silencioso
Los motores traen valores por omisión conservadores: llama.cpp
históricamente 512 y luego 4096, Ollama 2048–4096 según versión (a fecha
de redacción OLLAMA_CONTEXT_LENGTH cae alrededor de 4k). Mientras
tanto tu modelo puede soportar nativamente 32k–128k. Pega un documento de
20k tokens en un contexto de 4k y ocurre una de dos cosas, ambas malas:
un error duro («la petición excede el contexto disponible») o truncado
silencioso de los mensajes más antiguos. Ninguno de los dos mensajes de
error se explica solo ante un principiante.
Ejemplo resuelto: cargas un contrato de ~12k tokens más una pregunta, en
una ventana de 4096 por omisión. El motor conserva el material más
reciente, tira el principio del documento, y el modelo responde con
confianza preguntas sobre la mitad equivocada del archivo. Esto parece un
modelo estúpido; es un prompt truncado.
El arreglo es mecánico: pasa el tamaño de contexto explícito en cada
arranque, dimensionado a tus prompts reales más la salida esperada, y
verifica que el registro de arranque muestre n_ctx = 16384 (o lo que
elijas). Nota sobre el coreano: el texto coreano a menudo se tokeniza con
menos densidad que el inglés en el mismo tokenizador — una página en
coreano puede costar más tokens que una página en inglés (véase
tokens) — así que la presión de contexto llega antes de
lo que esperas.
# la trampa: los valores por omisión difieren por motor y por versión
llama-server -m model.gguf # arranca con n_ctx = 4096 aprox
# el arreglo: explícito y verificado en el registro de arranque
llama-server -m model.gguf -c 16384 # el registro imprime: n_ctx = 16384
Descarga a GPU: n_gpu_layers
-ngl / --n-gpu-layers fija cuántas capas del transformer viven en la
GPU; usa un número grande como 99 (o -1 donde se soporte) para decir
«todas». El síntoma de la descarga parcial es inconfundible: 3–10 tok/s
en una máquina con una GPU decente. Verifícalo con la línea de registro
de carga, p. ej. offloaded 33/33 layers to GPU. Si la VRAM no puede
con el modelo más la caché KV, las opciones honestas son una cuantización
menor, una caché KV cuantizada o menos capas descargadas — pero sabe que
cada capa dejada en CPU arrastra todo el bucle al ritmo de la CPU (véase
velocidad). Descargar a medias un modelo que casi cabe
suele ser peor que bajar un paso de cuantización.
Comprueba también en la otra dirección: -ngl 0 fuerza CPU pura, y si
eso corre a la misma velocidad que tu configuración «GPU», la GPU no
estaba haciendo nada.
Hilos (solo modo CPU)
En modo CPU fija -t al número de núcleos físicos, no de hilos SMT: en
un chip de 8 núcleos/16 hilos, usa 8. Más hilos que núcleos físicos causa
contención y frena la decodificación. El procesamiento de prompts tiene
su propio control (--threads-batch); aplica la misma regla.
Memoria: mmap y --mlock
llama.cpp mapea en memoria el archivo del modelo por omisión: el arranque
es rápido y las capas intactas no cuestan RAM. La contrapartida es que el
sistema puede desalojar páginas bajo presión de memoria, causando pausas
misteriosas horas dentro de una sesión. --mlock clava el modelo para
que no pueda desalojarse — útil en máquinas ocupadas, al coste de
encerrar gigabytes lejos de todo lo demás. Ollama maneja esto internamente;
los usuarios de llama.cpp puro en máquinas compartidas deberían saber que
el flag existe.
Flash attention
-fa / --flash-attn reduce el tráfico de memoria en el paso de
atención y viene activado (o automático) por omisión en las versiones
recientes de llama.cpp. Importa más con contexto largo, y cuantizar la
caché V lo requiere en las versiones actuales. Si una versión fresca se
comporta mal en tu backend de GPU, este es el primer flag que hay que
conmutar — y en cualquier versión reciente, lo primero que hay que
comprobar es que no se haya desactivado solo.
Cuantización de la caché KV
--cache-type-k q8_0 --cache-type-v q5_0 almacena la caché KV en
8 bits/5 bits en vez de floats de 16, cortando la memoria KV más o menos
a la mitad o más con un coste de calidad menor — lo que significa más
contexto en la misma VRAM. Qué es la caché KV y la matemática exacta de
tamaño: caché KV.
Ganancia típica: q8_0 para K más q5_0 para V parte el tamaño KV casi a la
mitad con un cambio apenas visible en tareas de chat — verifica en tus
propias cargas antes de confiar.
Tamaño de lote del prompt
-b / --batch-size es el tamaño de trozo del prefill (procesamiento
del prompt). Lotes más grandes significan menos tiempo al primer token
en prompts largos, al coste de un poco de VRAM pico. Si los pegados
largos tardan en empezar, súbelo antes de culpar al modelo.
Estirar el contexto: rope scaling y YaRN
--rope-scaling yarn --rope-factor 2.0 estira un modelo nativo de 32k
hacia 64k reescalando frecuencias posicionales. Funciona, con pendiente
de calidad: la degradación es pequeña cerca de la ventana nativa y crece
al estirarla más allá. Para lo importante, prefiere un modelo cuyo
contexto nativo ya cubra tu necesidad antes que estirar una ventana menor
(véase elección de modelo).
A fecha de redacción Ollama no expone el rope scaling en su Modelfile;
los experimentos de contexto estirado significan lanzar llama.cpp
directamente.
Una línea de arranque anotada
llama-server -m qwen3-8b-q4_k_m.gguf --host 127.0.0.1 --port 8080 -c 16384 -ngl 99 -fa on -b 2048 --cache-type-k q8_0 --cache-type-v q5_0
| Flag | Qué hace | Cuidado con |
|---|---|---|
-c 16384 |
Ventana de contexto (prompt + salida la comparten) | Nunca confíes en el valor por omisión; ponlo explícito |
-ngl 99 |
Capas descargadas a GPU (99 = todas) | Comprueba la línea de registro offloaded N/N |
-fa on |
Flash attention | Auto por omisión en versiones recientes; necesario para cuantizar la caché V |
-b 2048 |
Lote de procesamiento de prompts | Sube un poco la VRAM pico; ayuda al TTFT |
--cache-type-k/-v |
dtype de la caché KV | La cuantización de V requiere flash attention |
--host 127.0.0.1 |
Vincular solo al loopback | Reglas de exposición en servicio |
Equivalentes en Ollama
# por modelo, en un Modelfile:
PARAMETER num_ctx 16384
PARAMETER num_gpu 99
# o global, antes de que arranque el servicio:
export OLLAMA_CONTEXT_LENGTH=16384
export OLLAMA_FLASH_ATTENTION=1
export OLLAMA_KV_CACHE_TYPE=q8_0
Ollama registra una advertencia cuando una petición excede num_ctx — lee
el registro una vez tras cambiar cualquiera de esto. Los cambios por
variables de entorno exigen reiniciar el servicio.
Para ver qué aplicó Ollama en realidad: ollama show model --modelfile
imprime los parámetros resueltos, y OLLAMA_DEBUG=1 hace que el
servicio registre el contexto y los recuentos de descarga reales.
Los samplers no son controles del motor
Temperatura, top-p, penalización de repetición — esos moldean qué token
se elige, no qué tan rápido ni cuánto cabe en memoria. Viven en
muestreo. Si la salida es rara pero la velocidad y la
memoria están bien, quieres esa página, no esta.
La regla
Fija el contexto explícitamente. Verifica con una línea de registro —n_ctx = ... y offloaded N/N layers — cada vez que cambies una
configuración de arranque. Los valores por omisión están afinados para
que arranque la primera demo, no para que se sirva tu carga de trabajo.
llm_load_tensors: offloaded 33/33 layers to GPU
n_ctx = 16384
Ambas líneas se imprimen a los pocos segundos del arranque. Búscalas una
vez y la configuración deja de ser folclore.
Relacionados: Velocidad · Caché KV · Muestreo · Servir un endpoint