La caché KV en GPUs de 16 GB: cómo hacer que los contextos largos quepan realmente
Por qué el contexto de 128K se bloquea con 16 GB
Un modelo puede publicitar una ventana de contexto de 128K y seguir fallando a los 40K tokens en una GPU de 16 GB. El límite de la arquitectura nunca prometió que los pesos, la caché KV, los buffers de cálculo y el compositor del escritorio cabrían en tu tarjeta al mismo tiempo.
La caché KV suele ser donde los planes de contexto largo se topan con ese límite físico. Crece con cada token y secuencia activos, por lo que una configuración que parece cómoda al inicio puede ralentizarse bruscamente, desbordarse a la memoria del sistema o fallar durante un prefill grande.

Esta guía convierte el problema en un presupuesto de VRAM. Cubre la fórmula de la caché, tablas reproductibles de tamaños de 32K a 128K y configuraciones funcionales para llama.cpp --cache-type-k y --cache-type-v, vLLM con caché paginada y de prefijo, y controles de contexto de Ollama — además de las bifurcaciones experimentales de caché adaptativa que merecen atención pero no confianza ciega. Para el contexto más amplio de rendimiento, latencia y benchmarks detrás de estas cifras, comienza con el Centro de rendimiento LLM.
La Respuesta Corta para una GPU de 16 GB
Comienza con una secuencia, un contexto máximo realista, Flash Attention y una caché KV de 8 bits. Mide esa configuración antes de intentar caché de 4 bits, offload a CPU, múltiples slots paralelos o una bifurcación experimental.
| Objetivo | Primer intento sensato en 16 GB | Riesgo principal |
|---|---|---|
| 32K | Pesos Q4 o Q5, KV Q8, una secuencia | Los pesos del modelo dejan demasiado poco espacio para buffers |
| 64K | Modelo más pequeño o cuantización agresiva de pesos, KV Q8 | Latencia de prefill y ancho de banda de caché |
| 128K | Modelo GQA pequeño, KV Q8 o Q4 probado, una secuencia | La sola caché puede consumir la mayor parte de la VRAM |
| Dos sesiones simultáneas de 64K | Tratarlo como un presupuesto de caché de aproximadamente 128K | La capacidad paralela se confunde con rendimiento gratuito |
Mi opinión es simple: una configuración estable de 64K suele ser más útil que una configuración nominal de 128K que se ejecuta al borde de una falla por falta de memoria. La capacidad de contexto no es un trofeo; es una decisión de latencia, calidad y concurrencia.
Qué Almacena la Caché KV
Durante la generación autoregresiva, cada capa de atención produce tensores de claves (keys) y valores para cada token procesado. El runtime retiene esos tensores para que el siguiente token pueda prestar atención a tokens anteriores sin recalcular todo el prefijo.
La caché ahorra un cálculo enorme, pero consume memoria en proporción al número de tokens retenidos. Para un transformador convencional con atención de consulta agrupada (grouped-query attention), una línea base útil es:
Bytes KV = secuencias * tokens * capas * 2 * cabeceras KV * dimensión de cabecera * bytes por valor
El factor de dos representa claves y valores. La atención multi-cabecera (multi-head attention) utiliza tantas cabeceras KV como cabeceras de consulta, la atención de consulta agrupada utiliza menos cabeceras KV, y la atención latente multi-cabecera (multi-head latent attention) o las arquitecturas recurrentes híbridas requieren cálculos diferentes.
Por Qué la Cantidad de Parámetros No Suficiente
Dos modelos de 8B pueden tener costos de caché KV muy diferentes. Uno puede utilizar 32 capas y ocho cabeceras KV, mientras que otro puede utilizar menos cabeceras KV, capas KV compartidas, atención de ventana deslizante o estados latentes comprimidos.
La cantidad de parámetros predice principalmente la memoria de pesos. La geometría KV proviene de la arquitectura de atención, por lo que lee los metadatos del modelo en lugar de adivinar a partir de 8B, 27B o el tamaño del archivo GGUF. La ilustración más clara es cuán lejos ha avanzado el diseño de atención más allá de la atención multi-cabecera simple (MHA):
- Atención de Consulta Única (MQA) comparte una única cabecera K/V entre todas las cabeceras de consulta — ahorros máximos de caché, pero es el compromiso de calidad más agresivo y rara vez se usa solo en los modelos de frontera actuales.
- Atención de Consulta Agrupada (GQA) agrupa las cabeceras de consulta en clústeres que cada uno comparte una cabecera K/V — el compromiso predominante utilizado por la mayoría de los modelos densos abiertos, y la geometría que la fórmula anterior asume.
- Atención Latente Multi-Cabecera (MLA), introducida en DeepSeek-V2 y llevada a DeepSeek-V3 y Kimi K2, toma un enfoque completamente diferente: en lugar de compartir K/V entre cabeceras, proyecta claves y valores en un vector latente de rango comprimido y reconstruye el K/V a resolución completa bajo demanda en el momento de la atención. DeepSeek reportó aproximadamente una reducción del 93% de la caché KV frente a un modelo denso MHA de tamaño equivalente, manteniendo la calidad competitiva con — a veces por delante de — GQA con el mismo presupuesto de memoria.
La consecuencia práctica es que un “modelo GQA de 27B” y un “modelo MLA de 27B” pueden tener huellas de caché KV que difieren en un orden de magnitud para la misma longitud de contexto. No asumas que la fórmula anterior se aplica a un modelo que se documenta a sí mismo como usando atención latente, estado estilo DeltaNet o capas de ventana deslizante — verifica la sección de arquitectura de la tarjeta del modelo primero.
Con Ollama, ollama show MODEL --verbose expone metadatos del modelo incluyendo cantidad de capas, cabeceras de atención, cabeceras KV y longitud de contexto donde el formato los proporciona. Con llama.cpp, la salida del cargador de modelo impresa al inicio generalmente incluye metadatos GGUF equivalentes y la asignación real de caché del runtime.
Límite del Modelo, Contexto Asignado y Contexto Utilizado
Estos son tres números separados. El límite del modelo es el máximo soportado por su entrenamiento y codificación posicional, el contexto asignado es lo que el runtime reserva o permite, y el contexto utilizado son los tokens actualmente retenidos para una secuencia.
Elevar una bandera del motor no puede extender con seguridad un modelo más allá de su esquema de posición soportado. El escalado RoPE puede extender algunas arquitecturas, pero es un experimento de calidad del modelo, no una optimización de memoria KV.
Tabla de Tamaño de Caché KV: Presupuestos de Contexto 32K, 64K y 128K
Considere un modelo GQA representativo con 32 capas, ocho cabeceras KV y una dimensión de cabecera de 128. Estas dimensiones producen 65.536 elementos de clave y valor por token antes de multiplicar por el tamaño de almacenamiento de cada elemento.
La tabla usa GiB binarios y los tamaños de bloques físicos comúnmente asociados con llama.cpp f16, q8_0 y q4_0. Es un cálculo de línea base, no una promesa sobre la memoria total del proceso; la alineación, metadatos, capas híbridas y espacios de trabajo del backend añaden sobrecarga.
| Tipo de caché | Bytes aprox. por valor almacenado | Contexto 32K | Contexto 64K | Contexto 128K |
|---|---|---|---|---|
| F16 | 2,0000 | 4,00 GiB | 8,00 GiB | 16,00 GiB |
| Q8_0 | 1,0625 | 2,13 GiB | 4,25 GiB | 8,50 GiB |
| Q4_0 | 0,5625 | 1,13 GiB | 2,25 GiB | 4,50 GiB |
| Q8_0 K y Q4_0 V | Mixto | 1,63 GiB | 3,25 GiB | 6,50 GiB |
Ahora duplique la cantidad de capas a 64 dejando las demás dimensiones sin cambios. La caché FP16 se vuelve de 8 GiB a 32K, 16 GiB a 64K y 32 GiB a 128K, lo cual demuestra por qué una sola recomendación de contexto no puede cubrir todos los modelos.
La Ecuación Real de 16 GB
Un presupuesto práctico es más amplio que la fórmula KV:
VRAM utilizable = VRAM total - reserva del escritorio y driver
Presupuesto KV = VRAM utilizable
- pesos del modelo residentes en GPU
- buffers de grafo y activaciones
- espacio de trabajo del runtime
- estado de decodificación especulativa
- margen de seguridad
En una tarjeta de 16 GB conectada a un display, no planifiques asumiendo que todos los 16 GiB estén disponibles. Reserva al menos varios cientos de MiB para el escritorio y el driver, y luego deja otro margen para buffers dependientes de la carga de trabajo; 1,0 a 1,5 GiB de margen total de maniobra es una suposición inicial razonable, pero tus registros son la autoridad.
Supongamos que un modelo GGUF ocupa 10,8 GiB en la GPU y la sobrecarga del runtime pico cerca de 1,2 GiB. Después de un margen de seguridad de 1 GiB, solo quedan aproximadamente 3 GiB para KV, por lo que el modelo representativo encaja aproximadamente 45K tokens con Q8_0 o 87K con Q4_0, antes de la sobrecarga específica del motor.
Eso no hace automáticamente de Q4_0 la elección correcta. Si la precisión del contexto largo disminuye en tu carga de trabajo, un modelo más pequeño o más agresivamente cuantizado con una caché Q8_0 puede ser mejor que pesos más grandes emparejados con una caché frágil. Las anclas medidas para exactamente esta aritmética están en las tablas de benchmark llama.cpp para 16 GB de VRAM, donde la VRAM por modelo se registra a 19K, 32K y 64K de contexto. Para una encuesta más amplia de qué tamaños de modelo y niveles de cuantización se comportan bien bajo Ollama en la misma clase de tarjeta, vea Comparando el rendimiento de LLMs en Ollama en GPU de 16GB VRAM.
Calcule el Presupuesto de Caché KV para su Modelo
El siguiente fragmento en Python estima una caché GQA de atención completa convencional. Reemplace la geometría con valores de la configuración del modelo o metadatos GGUF.
def kv_gib(tokens, layers, kv_heads, head_dim, bytes_per_value, sequences=1):
total = (
sequences
* tokens
* layers
* 2
* kv_heads
* head_dim
* bytes_per_value
)
return total / (1024 ** 3)
model = {
"layers": 32,
"kv_heads": 8,
"head_dim": 128,
}
types = {
"f16": 2.0,
"q8_0": 34 / 32,
"q4_0": 18 / 32,
}
for tokens in (32768, 65536, 131072):
row = {
name: round(kv_gib(tokens=tokens, bytes_per_value=size, **model), 2)
for name, size in types.items()
}
print(tokens, row)
Las proporciones de Q8_0 y Q4_0 incluyen metadatos de bloque simples, por lo que son ligeramente más grandes que exactamente un byte y medio byte por valor. El informe de inicio del runtime sigue siendo más preciso porque conoce las disposiciones de caché específicas del modelo.
Cuándo Esta Fórmula Está Mal: Arquitecturas Híbridas y de Ventana Deslizante
No fuerce arquitecturas híbridas en la ecuación GQA convencional. Las capas de ventana deslizante retienen solo una ventana reciente, las capas KV compartidas reducen la duplicación, las capas recurrentes pueden llevar estado de tamaño fijo, y la atención latente multi-cabecera almacena una representación comprimida en lugar de tensores K/V por cabecera — el caso MLA anterior siendo el ejemplo más dramático.
Los motores modernos gestionan cada vez más explícitamente estas disposiciones mixtas. Use la fórmula para explicar los términos dominantes, y luego confirme la asignación reportada por la versión exacta del motor y el backend que planea desplegar.
llama.cpp: Control Directo de la Precisión de K y V
llama.cpp expone opciones separadas --cache-type-k y --cache-type-v en su analizador de argumentos actual. Esta es la interfaz de inferencia local más útil cuando necesitas intercambiar precisión de caché contra capacidad de contexto en lugar de aceptar una preconfiguración global. Si necesitas primero la configuración de instalación y servicio circundante, la guía de llama.cpp cubre llama-cli, llama-server y las principales banderas de VRAM.
Una configuración conservadora de 64K para un solo usuario se ve así:
./llama-server \
--model /models/model.gguf \
--n-gpu-layers 999 \
--ctx-size 65536 \
--parallel 1 \
--flash-attn on \
--cache-type-k q8_0 \
--cache-type-v q8_0 \
--batch-size 1024 \
--ubatch-size 256
La sintaxis de banderas y el soporte del backend cambian rápidamente, por lo que ejecute llama-server --help para la instalación. Más importante aún, inspeccione el registro de inicio: debe mostrar el contexto previsto, los tipos de caché, el offload a GPU y los buffers K y V asignados.
Qué Tipos de Caché de llama.cpp Probar
Comienza con Q8_0 para K y V. Aproximadamente reduce la memoria KV a la mitad en relación con F16, y pruebas independientes de perplexidad en modelos de 20B o más (Qwen3.6-27B, Nemotron-30B) muestran que la diferencia de calidad agregada desde F16 está dentro del ruido de medición — una apuesta mucho menos dramática que pasar directamente a Q4_0, que las mismas pruebas mostraron que colapsa la velocidad de decodificación y precisión a largo contexto en modelos más pequeños.
Si Q8_0 no cabe, prueba claves Q8_0 con valores Q4_0 antes de cuantizar ambos lados a Q4_0. Este ordenamiento tiene respaldo de investigación, no solo folclore: estudios controlados de asignación de bits en puntos de control de Llama, Phi-4, Qwen3 y Mistral encontraron que los tensores de clave son consistentemente dos a diez veces más sensibles al error de cuantización que los tensores de valor, y que dar a las claves un presupuesto de bits mayor (por ejemplo, claves de 4 bits con valores de 2 bits) recupera hasta el 94–98% de la precisión de precisión completa — mientras que la división invertida (claves de 2 bits, valores de 4 bits) puede perder 30 puntos porcentuales en tareas como GSM8K. Las claves determinan qué tokens anteriores la atención realmente coincide, por lo que protegerlas primero es la elección arquitectónicamente sólida, no solo la que suena más segura.
| Configuración | Memoria | Riesgo de calidad | Recomendación |
|---|---|---|---|
| K y V F16 | Mayor | Menor | Línea base cuando cabe |
| K y V Q8_0 | Aproximadamente la mitad de F16 | Bajo pero no cero | Punto de partida 16 GB por defecto |
| K Q8_0, V Q4_0 | Entre Q8 y Q4 | Moderado | Segundo paso útil |
| K y V Q4_0 | Aproximadamente un cuarto de F16 | Mayor | Validar en la profundidad objetivo |
Una advertencia que vale la pena internalizar: “riesgo de calidad bajo” en benchmarks agregados no significa cero riesgo a nivel de token. Una prueba controlada que mantuvo Flash Attention constante y solo cambió la precisión KV bajo decodificación greedy (determinística) encontró que la caché Q8_0 cambió el texto generado exacto en la gran mayoría de los prompts, y Q4_0 lo cambió en prácticamente todos — una vez que un token cambia, el resto de la continuación puede divergir. Las puntuaciones de perplexidad y tareas de aval pueden parecer bien en promedio mientras las salidas individuales aún difieren de la línea base F16. Si tu aplicación necesita reproducibilidad byte por byte (pruebas de regresión, respuestas en caché, agentes deterministas), trata cualquier cuantización KV como un cambio de comportamiento, no solo una optimización de memoria, y valida contra tu propio conjunto fijo de prompts.
La caché V cuantizada puede requerir Flash Attention o una ruta de backend compatible. Un servidor que cae silenciosamente a otro tipo invalida el experimento, por lo que los registros de inicio importan más que las líneas de comando copiadas.
Contexto, Slots Paralelos y Caché Unificada
--ctx-size describe una capacidad del motor, no una garantía de que cada slot paralelo reciba independientemente tantos tokens. La gestión de caché ha evolucionado en llama.cpp, incluyendo el comportamiento de caché unificada, por lo que prueba la versión exacta en lugar de confiar en una regla más antigua que simplemente divide el contexto por la cantidad de slots.
La ecuación de capacidad aún sobrevive a los cambios de implementación: los tokens únicos simultáneos necesitan almacenamiento en algún lugar. Si dos sesiones de agente pueden alcanzar 48K cada una, haz presupuesto para cerca de 96K tokens vivos a menos que la carga de trabajo comparta prefijos o tolere la expulsión y recálculo.
El Tamaño de Lote No Reduce la KV Almacenada
--batch-size y --ubatch-size afectan el procesamiento del prompt y la memoria temporal. Reducirlos puede rescatar un prefill grande de un pico de memoria de activación, pero no cambia los bytes persistentes requeridos para cada token retenido.
Esta distinción explica un patrón de fallo común: el modelo inicia y una solicitud vacía funciona, pero un prompt de 60K falla durante la ingesta. Reduce el micro-lote para diagnosticar el pico transitorio; reduce el contexto, la precisión de la caché, el paralelismo o la residencia de pesos para cambiar la capacidad persistente.
vLLM: La Capacidad Paginada Sigue Siendo Capacidad
vLLM aborda el problema como un motor de servicio. Perfiliza la memoria disponible, reserva un pool de caché KV y asigna caché en bloques para que las secuencias simultáneas no requieran cada una una región contigua grande. Si estás decidiendo si moverte a vLLM en primer lugar, la guía de migración de Ollama a vLLM cubre las señales de carga de trabajo; aquí la pregunta es puramente cuánta caché puede contener el pool, y la guía de inicio rápido de vLLM cubre la instalación y banderas generales de servicio más allá de las palancas de capacidad a continuación.
PagedAttention reduce la fragmentación y el desperdicio alrededor de longitudes de secuencia variables — la asignación paginada elimina la fragmentación, no el costo de almacenamiento por token, por lo que una solicitud única de 128K aún necesita suficientes bloques para su estado KV.
La guía oficial de conservación de memoria de vLLM recomienda limitar max_model_len y max_num_seqs cuando la memoria es ajustada, y señala que las graficas CUDA consumen memoria GPU adicional. En una tarjeta de 16 GB, ambas configuraciones deben ser intencionales en lugar de heredadas de la configuración máxima del modelo.
Un servidor de secuencia única enfocado podría comenzar aquí:
vllm serve MODEL_ID \
--max-model-len 65536 \
--max-num-seqs 1 \
--gpu-memory-utilization 0.90 \
--kv-cache-dtype fp8 \
--enable-prefix-caching
No todas las GPUs de 16 GB, modelos, métodos de cuantización o backends de atención admiten esa combinación exacta. Trátalo como una forma de configuración: restringe la longitud y la concurrencia, reserva margen, selecciona un tipo de caché admitido y valida el informe de inicialización.
Caché KV FP8 en vLLM
La documentación actual de caché KV cuantizada de vLLM soporta formatos de caché FP8 en rutas CUDA y ROCm compatibles. FP8 aproximadamente reduce el almacenamiento bruto de caché a la mitad en relación con BF16 o FP16 y por lo tanto puede aumentar la capacidad de tokens o la concurrencia.
La escalada importa. La documentación distingue entre escalas por defecto, cálculo de calentamiento y calibración de conjunto de datos, y recomienda la calibración basada en conjunto de datos para la máxima precisión; simplemente establecer FP8 con escala 1.0 es conveniente pero no automáticamente la elección de calidad más confiable.
La Caché de Prefijo Es una Optimización de Reutilización
La caché de prefijo automática permite a una nueva solicitud reutilizar bloques KV para un prefijo idéntico en caché. Es excelente para consultas repetidas sobre el mismo documento largo, prompts de sistema compartidos y conversaciones de múltiples rondas porque evita recalcular el prefill coincidente.
No hace que una solicitud larga única sea más pequeña, y no acelera la generación de tokens nuevos. La documentación de caché de prefijo de vLLM limita explícitamente el beneficio al trabajo de prefill de prefijo compartido.
La Utilización de Memoria GPU No Es Memoria Gratuita
Elevar --gpu-memory-utilization le da a vLLM un objetivo de reserva más grande, pero no crea VRAM. Empujarlo demasiado cerca de 1.0 puede dejar espacio insuficiente para el display, otro proceso, picos de activación cambiantes o asignaciones no PyTorch.
Comienza alrededor de 0.88 a 0.92 en una GPU de 16 GB dedicada, inspecciona el perfil y aumenta solo si la carga de trabajo permanece estable. Si la inicialización tiene éxito pero los prompts reales fallan, reduce los tokens por lote, la concurrencia de secuencias, la captura de graficas CUDA o el contexto máximo antes de asumir que el asignador está roto.
Ollama: Controles Más Fáciles, Diagnóstico Menos Granular
Ollama proporciona deliberadamente una superficie operativa más pequeña. Su documentación actual de longitud de contexto establece por defecto 4K de contexto para GPUs menores de 24 GiB, recomienda al menos 64K para cargas de trabajo de agentes y codificación, y advierte que un contexto más grande consume más memoria.
Establece el valor predeterminado del servidor y confirma el modelo cargado así:
OLLAMA_CONTEXT_LENGTH=65536 ollama serve
ollama ps
También puedes establecer num_ctx por solicitud o modelo. ollama ps es importante porque sus columnas PROCESSOR y CONTEXT revelan si el modelo permaneció completamente en la GPU y si el contexto solicitado fue realmente asignado. Ten en cuenta que el comportamiento de programación detrás de esos números cambió entre versiones de Ollama; mi comparación de la asignación de memoria de Ollama v0.12.1 muestra que el nuevo programador empuja algunos modelos más lejos a la CPU en una tarjeta de 16 GB, por lo que fija la versión que midiste.
Caché KV Cuantizada en Ollama
Ollama expone OLLAMA_KV_CACHE_TYPE con opciones f16, q8_0 y q4_0 en su FAQ actual. La caché KV cuantizada requiere Flash Attention, que Ollama usa automáticamente en backends compatibles o puede solicitarse con OLLAMA_FLASH_ATTENTION=1.
Un servicio de contexto largo de 16 GB puede iniciarse por lo tanto como:
OLLAMA_CONTEXT_LENGTH=65536 \
OLLAMA_FLASH_ATTENTION=1 \
OLLAMA_KV_CACHE_TYPE=q8_0 \
OLLAMA_NUM_PARALLEL=1 \
ollama serve
Q8_0 es la alternativa recomendada de Ollama a F16. La FAQ advierte que Q4_0 puede producir una pérdida de calidad más notable, especialmente a mayor contexto, por lo que debe ser un respaldo medido en lugar de una preconfiguración automática de 16 GB.
El Paralelismo de Ollama Multiplica el Presupuesto de Contexto
Ollama documenta una regla particularmente clara: la memoria requerida escala con OLLAMA_NUM_PARALLEL * OLLAMA_CONTEXT_LENGTH. Cuatro solicitudes paralelas a una configuración de 32K pueden implicar una asignación de contexto agregada de 128K para ese modelo.
Para un agente personal en 16 GB, mantén OLLAMA_NUM_PARALLEL=1 hasta que una sesión larga sea estable. Encolar una segunda solicitud suele ser preferible a empujar el primer modelo parcialmente a la CPU y hacer que ambas solicitudes sean lentas. Los mecanismos de encolado, 503 y descarga de modelos detrás de esa elección están documentados en cómo Ollama maneja solicitudes paralelas.
Offload a CPU: Una Salida Válida con un Precio
Mover algunas capas del modelo o estado KV a la RAM del sistema puede convertir un fallo de asignación en un proceso funcional. También coloca el ancho de banda PCIe y la latencia de la memoria del anfitrión en la ruta de decodificación, donde cada token generado puede pagar el costo. El carril y la evidencia de generación para cuándo PCIe realmente muerde están en Rendimiento LLM y Carriles PCIe.
El offload puede ser sensato para trabajo por lotes ocasional, pero rara vez es el valor predeterminado mejor para un agente de codificación interactivo. Primero compara una cuantización de pesos más pequeña, KV Q8, concurrencia reducida y un límite de contexto realista; usa offload cuando la capacidad importa más que la latencia.
Vigila el precipicio en lugar del promedio. Un servidor puede decodificar rápidamente a 8K, luego ralentizarse severamente después de que parte del conjunto de trabajo se desborde, por lo que haz benchmark a 32K, 64K y el máximo previsto en lugar de reportar solo una tasa de tokens de contexto vacío.
Cachés KV de Ventana Deslizante y Adaptativas
La atención de ventana deslizante cambia el presupuesto reteniendo solo una ventana reciente para capas seleccionadas. Los modelos híbridos pueden combinar esas capas con atención global ocasional o estado recurrente, haciendo que un cálculo plano de contexto completo sobreestime o mal coloque la memoria sustancialmente.
La optimización es parte de la arquitectura del modelo, no un interruptor genérico que se puede aplicar sin consecuencias. Un motor debe entender el patrón de capas, las reglas de expulsión, las posiciones y cualquier token global correctamente.
Qué Intenta Mejorar la KV Adaptativa
Las bifurcaciones experimentales van más allá eligiendo la precisión o disposición de la caché por capa y profundidad de contexto. El objetivo es atractivo: preservar una mayor precisión donde importa, comprimir capas menos sensibles y cambiar la mezcla antes de que la presión de VRAM cause un desbordamiento duro — el mismo hallazgo de sensibilidad de claves sobre sensibilidad de valores descrito arriba es exactamente el tipo de señal que un asignador adaptativo querría explotar automáticamente en lugar de dejarlo al ajuste manual de --cache-type-k/--cache-type-v.
Un proyecto descendiente de agosto de 2026, llama.cpp-adaptive-turboquant, reporta un selector automático para varios modos adaptativos por capa y publica pruebas de profundidad larga en una RTX 5080 16 GB. Esas cifras son resultados reportados por el autor de una bifurcación especializada, no evidencia de que llama.cpp upstream se comporte de la misma manera.
Por Qué Aún Es Experimental
La bifurcación combina tipos de caché personalizados, núcleos CUDA, rutas específicas del modelo y restricciones de cadena de herramientas. Eso es mucho más código que confiar que cambiar el almacenamiento de caché upstream de F16 a Q8_0.
Usa una bifurcación tal solo cuando upstream no puede cumplir un requisito real y puedes reproducir calidad, estabilidad y velocidad en tu modelo. Registra el commit y la versión de CUDA, porque un resultado adjunto solo a un nombre de proyecto no es reproducible.
Una Prueba Justa de Caché Adaptativa
Compara la bifurcación contra una línea base Q8_0 upstream con el mismo GGUF, prompt, muestreador, profundidad de contexto y longitud de salida. Mide la VRAM de inicio, la VRAM pico de prefill, la velocidad de procesamiento del prompt, la velocidad de decodificación y una tarea de calidad que realmente requiera evidencia de la parte más antigua del contexto.
No aceptes una asignación exitosa como un resultado completo. Una caché puede caber 128K y aún perder hechos iniciales, corromper la salida tarde en la secuencia o decodificar demasiado lento para ser útil.
Un Procedimiento de Ajuste de 16 GB Paso a Paso: Una Variable a la Vez
La ruta más rápida a una configuración estable es cambiar una dimensión de memoria a la vez. Alterar aleatoriamente el tipo de caché, el tamaño de lote, el offload de capas, el paralelismo y el contexto juntos produce un comando funcional sin explicación.
Paso 1: Establecer la Línea Base de Pesos
Carga el modelo a 8K de contexto, una secuencia y el offload a GPU previsto. Registra la VRAM del proceso después del calentamiento y verifica que ninguna capa se haya movido inesperadamente a la CPU.
Si los pesos y el runtime ya consumen más de aproximadamente 14,5 a 15 GiB, el contexto largo no tiene margen saludable. Elige una cuantización de pesos o un modelo más pequeño antes de ajustar la caché.
Paso 2: Medir KV F16 o BF16 como Línea Base de Calidad
Ejecuta el contexto más pequeño que soporte tu prueba y retenga la caché de alta precisión predeterminada. Guarda las salidas de tareas de recuperación, edición de código, selección de herramientas e instrucciones largas.
Esta línea base te dice si los errores posteriores provienen de la cuantización de la caché. Sin ella, un problema de plantilla de chat o un modelo débil puede ser fácilmente culpad a la KV Q4.
Paso 3: Pasar a Q8 o FP8
Habilita Flash Attention donde sea requerido, selecciona Q8_0 en llama.cpp o Ollama, o un modo FP8 compatible en vLLM. Repite los mismos prompts a las mismas profundidades de tokens y confirma que el registro muestre el tipo de caché previsto.
Para muchas implementaciones de 16 GB, este es el punto de parada útil. Aproximadamente duplica la capacidad bruta KV sin hacer que la compresión de la caché sea la cuantización más agresiva de la pila.
Paso 4: Elevar el Contexto por Etapas
Prueba 32K, 64K, 96K y 128K en lugar de saltar directamente al máximo publicitado. En cada etapa, registra tokens por segundo de procesamiento de prompt, tokens por segundo de decodificación, VRAM pico y si la evidencia cerca del inicio aún puede recuperarse.
La decodificación de contexto largo a menudo se ralentiza incluso después de que la memoria cabe porque la atención lee más estado en caché. La capacidad y el rendimiento son ejes separados.
Paso 5: Ajustar la Memoria Transitoria
Si el fallo ocurre durante el prefill en lugar de la inicialización, reduce el micro-lote o los tokens de lote máximos. Si el fallo ocurre solo con solicitudes simultáneas, reduce la concurrencia de secuencias o los slots paralelos.
Solo después de que esos controles sean comprendidos debes intentar caché mixta Q8/Q4, caché Q4 completa, offload a CPU o una bifurcación adaptativa. Mantén la ejecución Q8 upstream como la línea base de comparación. Si más tarde añades decodificación especulativa o MTP, recuerda que sus buffers de borrador son otra línea en la ecuación del presupuesto, no velocidad gratuita — la guía de decodificación especulativa cubre los mecanismos y su costo de VRAM, y mi benchmark de Qwen 3.6 27B y 35B MTP vs Estándar muestra exactamente cuánto contexto puede costar el estado extra de una cabeza MTP en una tarjeta de 16 GB.
Qué Registrar en un Benchmark de Contexto Largo
Una sola cifra de tokens/s oculta el problema exacto que este artículo intenta resolver. Las pruebas de contexto largo deberían preservar suficiente detalle para que otro operador pueda reproducir el límite de memoria.
| Campo | Por qué importa |
|---|---|
| GPU y VRAM utilizable | El uso de display y otros procesos cambian el presupuesto |
| Versión o commit del motor | El comportamiento de la caché y las banderas evolucionan rápidamente |
| Versión del driver, CUDA, ROCm o Vulkan | Determina el comportamiento del backend y núcleos |
| Modelo exacto y cuantización de pesos | Define la residencia de pesos y la arquitectura |
| Tipos de caché K y V | Define el tamaño de caché persistente y el riesgo de calidad |
| Capacidad de contexto y profundidad del prompt | La asignación no es lo mismo que la profundidad real |
| Secuencias paralelas | Multiplica o comparte la demanda de caché |
| Lote y micro-lote | Afecta picos de prefill y velocidad |
| Velocidad de procesamiento del prompt | Expone la usabilidad de prefill largo |
| Velocidad de decodificación a cada profundidad | Expone el ralentizamiento por ancho de banda de caché |
| VRAM pico y offload a CPU | Distingue encaje de desbordamiento |
| Resultado de calidad de contexto largo | Detecta fallos de compresión o posición |
Use muestreo de nvidia-smi o el tooling de vendedor equivalente durante tanto el prefill como la decodificación. El informe de asignación del motor es necesario, pero la memoria de dispositivo pico durante un prompt real es el número que decide la estabilidad.
Errores Comunes de Caché KV en GPUs de 16 GB
Tratar el Soporte de 128K como una Promesa de Hardware
El campo de contexto en una configuración de modelo es un límite arquitectónico. No dice nada sobre la memoria restante después de cargar una cuantización particular en un motor particular.
Calcule la caché y verifique el runtime. Un contexto de tamaño de marketing sin un presupuesto de VRAM es simplemente un OOM retrasado hasta el primer prompt serio.
Cuantizar Pesos pero Olvidar la KV
Un GGUF de 4 bits reduce los pesos del modelo, no una caché KV F16. A largo contexto, la caché puede borrar todo el ahorro y eventualmente superar la huella de los pesos.
Reporta ambas cuantizaciones. Modelo Q4_K_M, KV Q8_0 es significativo; Modelo de 4 bits está incompleto.
Asumir que la Atención Paginada Comprime Tokens
La paginación mejora el comportamiento de asignación y compartición. No cambia la precisión del tensor ni elimina el estado KV requerido por una secuencia única.
Use la asignación paginada para servir cargas de trabajo variables eficientemente. Use la precisión de la caché, la arquitectura del modelo, los límites de contexto y los límites de concurrencia para controlar la capacidad.
Asumir que la Caché de Prefijo Ayuda a Cada Prompt Largo
La caché de prefijo ahorra el cálculo de prefill repetido cuando las solicitudes comparten un prefijo exacto. Un volcado de repositorio único de 100K no recibe un descuento de memoria mágico solo porque la caché de prefijo esté habilitada.
Es una optimización de carga de trabajo, no un reemplazo de la ecuación del presupuesto. Mide la tasa de acierto y la presión de caché retenida en el servicio multiusuario.
Usar KV Q4 Sin una Prueba de Calidad
La caché de bits bajos puede fallar sutilmente. El modelo aún escribe texto fluido, pero la atención sobre evidencia distante, nombres exactos, argumentos de herramientas o dependencias de código pueden degradarse — y como la investigación de divergencia de tokens arriba muestra, incluso la configuración “segura” Q8_0 no está garantizada para reproducir la salida F16 exacta bajo decodificación determinista, solo para preservar la precisión en agregado.
Prueba la tarea objetivo a la profundidad objetivo. Los benchmarks de chat cortos son casi inútiles para validar una caché de contexto largo.
Dejar el Paralelismo en Automático
Un motor puede elegir una concurrencia que es sensata para el rendimiento pero imposible para tu objetivo de contexto largo. En 16 GB, una secuencia profunda y varias secuencias cortas son cargas de trabajo fundamentalmente diferentes.
Establece el límite explícitamente, luego elévalo con tráfico medido. De lo contrario, una segunda solicitud puede convertir una configuración estable de 64K en una sorpresa de asignación o latencia.
Perfiles Recomendados de 16 GB
Estos perfiles son posiciones de inicio, no preconfiguraciones universales. Un modelo con geometría KV inusual — un diseño MLA o híbrido de ventana deslizante en particular — puede ser mucho más barato o más caro que el ejemplo GQA convencional.
Agente de Codificación Interactivo
Usa una secuencia, contexto de 48K a 64K, caché Q8, Flash Attention y residencia completa de pesos en GPU si es posible. Este perfil favorece la latencia predecible y buena precisión de caché sobre un máximo impresionante pero raramente útil.
Habilita la reutilización de prefijo cuando el motor lo soporte porque los giros de codificación a menudo comparten un repositorio o prefijo de conversación grande. Aún así, comprime la salida de herramientas y transcripciones antiguas; la ingeniería de caché no hace que los tokens irrelevantes sean valiosos.
Análisis de Documentos Largos
Usa un modelo más pequeño con capacidad de 64K a 128K, caché Q8 o FP8 calibrado, y caché de prefijo repetido cuando múltiples preguntas apuntan al mismo documento. Mide el tiempo hasta el primer token porque el prefill puede dominar incluso cuando la decodificación permanece aceptable.
Si solo se hará una pregunta, la recuperación o el resumen fragmentado puede ser más rápido y más confiable que forzar todo el corpus a través de una tarjeta de 16 GB. El contexto largo es una herramienta, no un reemplazo de la arquitectura de información.
Servidor Multiusuario Pequeño
Limita el contexto por solicitud y las secuencias activas totales en lugar de publicitar el máximo del modelo a cada cliente. La asignación paginada de vLLM es útil aquí, mientras que Ollama y llama.cpp también requieren atención explícita a los tokens vivos agregados.
Preferencia por el encolado sobre el desbordamiento sin control. Una política de admisión más lenta es menos dañina que cada solicitud cruzando PCIe de repente durante la decodificación.
Recomendación Final para Contexto Largo en 16 GB
Para contexto largo en 16 GB, la KV Q8 y una secuencia activa son la línea base correcta. Exponen el límite real sin hacer que la calidad de la caché de bits bajos, la asignación paralela y la latencia de offload fallen a la vez.
Calcula desde la geometría de atención, resta los pesos y la sobrecarga del runtime, y luego confirma el resultado en los registros del motor y las mediciones de memoria pico. Si 128K aún no cabe, un modelo más pequeño a menudo es la optimización más limpia; si cabe pero se arrastra, reducir el contexto a menudo es la honesta.
La atención paginada, la caché de prefijo, las ventanas deslizantes y la precisión adaptativa resuelven problemas útiles pero diferentes. La configuración ganadora es la que permanece en la GPU, recupera la evidencia antigua correctamente y sostiene una velocidad de decodificación aceptable a la profundidad de contexto que realmente usas.
Referencias
- vLLM: conservando memoria GPU
- vLLM: caché KV cuantizada (FP8)
- vLLM: caché de prefijo automática
- Ollama: documentación de longitud de contexto
- Ollama FAQ:
OLLAMA_KV_CACHE_TYPEy Flash Attention - llama.cpp-adaptive-turboquant — bifurcación experimental de caché adaptativa por capa (resultados reportados por el autor)
- Raschka, S. “Multi-Head Latent Attention (MLA).” LLM Architecture Gallery. https://sebastianraschka.com/llm-architecture-gallery/mla/
- “Decoding Multi-Head Latent Attention: The KV Cache Memory Bottleneck, Solved.” Vizuara. https://vizuara.substack.com/p/decoding-multi-head-latent-attention
- “Quantize What Counts: Bit Allocation Insights Informed by Spectral Gaps in Keys and Values.” arXiv:2502.15075. https://ar5iv.labs.arxiv.org/html/2502.15075
- v-code01. “kvdivergence — does KV cache quantization change the generated text under greedy decoding?” GitHub. https://github.com/v-code01/kvdivergence
- Comparando el rendimiento de LLMs en Ollama en GPU de 16GB VRAM
- Qwen 3.6 27B y 35B MTP vs Estándar en GPU de 16GB