KV Cache en GPUs de 16 GB: Cómo hacer que el contexto largo realmente quepa
Por qué el contexto de 128K falla con 16 GB
Un modelo puede publicitar una ventana de contexto de 128K y aun así fallar en 40K tokens en una GPU de 16 GB. El límite de la arquitectura nunca prometió que los pesos, la caché KV, los búferes 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 chocan con ese límite físico. Crece con cada token y secuencia activa, 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 de tamaño reproducibles de 32K a 128K, y configuraciones funcionales para llama.cpp --cache-type-k y --cache-type-v, caché paginada y de prefijo de vLLM, y controles de contexto de Ollama, además de las forks experimentales de caché adaptativa que merecen interés pero no confianza ciega. Para el contexto más amplio sobre rendimiento, latencia y benchmarks detrás de estos números, comienza con el centro de rendimiento de 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 la caché de 4 bits, la descarga a CPU, múltiples ranuras paralelas o una fork experimental.
| Objetivo | Primer intento razonable en 16 GB | Riesgo principal |
|---|---|---|
| 32K | Pesos Q4 o Q5, KV Q8, una secuencia | Los pesos del modelo dejan demasiado poco espacio de búfer |
| 64K | Modelo más pequeño o cuantización agresiva de pesos, KV Q8 | Latencia de prefill y ancho de banda de la caché |
| 128K | Modelo GQA pequeño, KV Q8 o Q4 probado, una secuencia | La caché por sí sola puede consumir la mayor parte de la VRAM |
| Dos sesiones simultáneas de 64K | Trátalo como un presupuesto de caché de aproximadamente 128K | La capacidad paralela se confunde con throughput 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 opera al borde de un fallo de memoria insuficiente. 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 autorregresiva, cada capa de atención produce tensores clave y valor para cada token procesado. El runtime retiene esos tensores para que el siguiente token pueda atender a tokens anteriores sin recomputar todo el prefijo.
La caché ahorra un enorme cálculo, 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:
KV bytes = secuencias * tokens * capas * 2 * cabecas KV * dimensión de cabeza * bytes por valor
El factor de dos representa claves y valores. La atención multi-cabeza usa tantas cabecas KV como cabecas de consulta, la atención de consulta agrupada usa menos cabecas KV, y la atención latente multi-cabeza o las arquitecturas recurrentes híbridas requieren cálculos diferentes.
Por qué el número de parámetros no es suficiente
Dos modelos de 8B pueden tener costos de caché KV muy diferentes. Uno puede usar 32 capas y ocho cabecas KV, mientras que otro puede usar menos cabecas KV, capas KV compartidas, atención de ventana deslizante o estados latentes comprimidos.
El número de parámetros predice principalmente la memoria de pesos. La geometría de la KV proviene de la arquitectura de atención, por lo que lee los metadatos del modelo en lugar de adivinar desde 8B, 27B o el tamaño del archivo GGUF. La ilustración más clara es cuán lejos se ha movido el diseño de atención más allá de la atención multi-cabeza simple (MHA):
- Atención de Consulta Única (MQA) comparte una única cabeza K/V en todas las cabezas de consulta, maximizando los ahorros 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 cabezas de consulta en clústeres que comparten cada uno una cabeza K/V, el compromiso mainstream utilizado por la mayoría de los modelos densos abiertos, y la geometría que asume la fórmula anterior.
- Atención Latente Multi-Cabeza (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 cabezas, proyecta claves y valores en un vector latente de bajo rango comprimido y reconstruye el K/V a resolución completa bajo demanda en el momento de la atención. DeepSeek reportó una reducción de la caché KV de aproximadamente 93% frente a un modelo denso MHA de tamaño equivalente, mientras mantenía la calidad competitiva con, a veces por delante de, la 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 que usa atención latente, estado estilo DeltaNet o capas de ventana deslizante; primero revisa la sección de arquitectura de la tarjeta del modelo.
Con Ollama, ollama show MODEL --verbose expone metadatos del modelo, incluyendo el número de capas, cabezas de atención, cabezas KV y longitud de contexto donde el formato los proporciona. Con llama.cpp, la salida del cargador de modelo impresa al inicio suele incluir metadatos GGUF equivalentes y la asignación de caché real del runtime.
Límite del Modelo, Contexto Asignado y Contexto Usado
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 usado son los tokens actualmente retenidos para una secuencia.
Elevar una bandera de motor no puede extender con seguridad un modelo más allá de su esquema posicional soportado. El escalado de 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 la Caché KV: Presupuestos de Contexto de 32K, 64K y 128K
Consideremos un modelo GQA representativo con 32 capas, ocho cabecas KV y una dimensión de cabeza de 128. Estas dimensiones producen 65,536 elementos 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 bloque físico comúnmente asociados con f16, q8_0 y q4_0 de llama.cpp. Es un cálculo de línea base, no una promesa sobre la memoria total del proceso; la alineación, los metadatos, las capas híbridas y los espacios de trabajo del backend agregan sobrecarga.
| Tipo de caché | Aprox. bytes 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 |
| K Q8_0 y V Q4_0 | Mixto | 1.63 GiB | 3.25 GiB | 6.50 GiB |
Ahora duplica el número de capas a 64, dejando las otras dimensiones sin cambios. La caché FP16 se convierte en 8 GiB en 32K, 16 GiB en 64K y 32 GiB en 128K, lo que demuestra por qué una única recomendación de contexto no puede cubrir cada modelo.
La Ecuación Real de 16 GB
Un presupuesto práctico es más amplio que la fórmula de KV:
VRAM disponible = VRAM total - reserva de escritorio y controlador
Presupuesto KV = VRAM disponible
- pesos del modelo residentes en GPU
- búferes de grafo y activación
- espacio de trabajo del runtime
- estado de descodificación especulativa
- margen de seguridad
En una tarjeta de 16 GB conectada a una pantalla, no planifiques asumiendo que todo el espacio de 16 GiB esté disponible. Reserva al menos varios cientos de MiB para el escritorio y el controlador, y deja otro margen para búferes dependientes de la carga de trabajo; 1.0 a 1.5 GiB de margen total es un supuesto 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 alcanza un pico cercano a 1.2 GiB. Después de un margen de seguridad de 1 GiB, solo quedan aproximadamente 3 GiB para la KV, por lo que el modelo representativo encaja aproximadamente 45K tokens con Q8_0 u 87K con Q4_0, antes de la sobrecarga específica del motor.
Esto no hace automáticamente que Q4_0 sea la elección correcta. Si la precisión de contexto largo disminuye en tu carga de trabajo, un modelo más pequeño o más agresivamente cuantizado con una caché Q8_0 podría ser mejor que pesos más grandes combinados con una caché frágil. Las anclas medidas para exactamente esta aritmética se encuentran en las tablas de benchmark de llama.cpp para VRAM de 16 GB, donde la VRAM por modelo se registra en contextos de 19K, 32K y 64K. Para una encuesta más amplia de qué tamaños de modelos y niveles de cuantización se comportan bien bajo Ollama en la misma clase de tarjeta, ve Comparando el rendimiento de LLMs en Ollama en una GPU de 16GB VRAM.
Calcula el Presupuesto de Caché KV para Tu Modelo
El siguiente fragmento de Python estima una caché GQA de atención completa convencional. Reemplaza la geometría con valores de la configuración del modelo o los metadatos GGUF.
def kv_gib(tokens, capas, cabecas_kv, dim_cabeza, bytes_por_valor, secuencias=1):
total = (
secuencias
* tokens
* capas
* 2
* cabecas_kv
* dim_cabeza
* bytes_por_valor
)
return total / (1024 ** 3)
modelo = {
"capas": 32,
"cabecas_kv": 8,
"dim_cabeza": 128,
}
tipos = {
"f16": 2.0,
"q8_0": 34 / 32,
"q4_0": 18 / 32,
}
for tokens in (32768, 65536, 131072):
fila = {
nombre: round(kv_gib(tokens=tokens, bytes_por_valor=tamano, **modelo), 2)
for nombre, tamano in tipos.items()
}
print(tokens, fila)
Las proporciones de Q8_0 y Q4_0 incluyen metadatos de bloque simples, por lo que son ligeramente mayores 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 es Incorrecta: Arquitecturas Híbridas y de Ventana Deslizante
No fuerces las 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-cabeza almacena una representación comprimida en lugar de tensores K/V por cabeza, siendo el caso de MLA arriba el ejemplo más dramático.
Los motores modernos gestionan cada vez más estas disposiciones mixtas explícitamente. Usa la fórmula para explicar los términos dominantes, y luego confirma la asignación reportada por la compilación exacta del motor y el backend que planeas 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 parser de argumentos actual. Esta es la interfaz de inferencia local más útil cuando necesitas intercambiar la precisión de la caché por la capacidad de contexto en lugar de aceptar una predefinición global. Si primero necesitas la configuración de instalación y servicio circundante, la guía de llama.cpp cubre llama-cli, llama-server y las banderas clave 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 las banderas y el soporte del backend cambian rápidamente, por lo que ejecuta llama-server --help para la compilación instalada. Más importante aún, inspecciona el registro de inicio: debe mostrar el contexto previsto, los tipos de caché, la descarga a GPU y los búferes asignados K y V.
Qué Tipos de Caché de llama.cpp Probar
Comienza con Q8_0 para ambos K y V. Reduce aproximadamente a la mitad la memoria KV 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 agregada de calidad frente a 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 colapsando la velocidad de decodificación y la precisión en contexto largo en modelos más pequeños.
Si Q8_0 no encaja, 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 checkpoints de Llama, Phi-4, Qwen3 y Mistral encontraron que los tensores clave son consistentemente de 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 un 94-98% de la precisión a 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 a 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 encaja |
| K y V Q8_0 | Mitad de F16 | Bajo pero no cero | Punto de inicio por defecto para 16 GB |
| K Q8_0, V Q4_0 | Entre Q8 y Q4 | Moderado | Segundo paso útil |
| K y V Q4_0 | Un cuarto de F16 | Mayor | Validar en profundidad objetivo |
Una advertencia que vale la pena interiorizar: “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 codicia (determinista) 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 esencialmente todos — una vez que un token cambia, el resto de la continuación puede divergir. Las puntuaciones de perplexidad y tareas descendientes 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 a byte (pruebas de regresión, respuestas en caché, agentes deterministas), trata cualquier cuantización de KV como un cambio de comportamiento, no solo como una optimización de memoria, y valida contra tu propio conjunto de prompts fijos.
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 eso los registros de inicio importan más que las líneas de comando copiadas.
Contexto, Ranuras Paralelas y Caché Unificada
--ctx-size describe una capacidad del motor, no una garantía de que cada ranura paralela reciba ese número de tokens de forma independiente. La gestión de la caché ha evolucionado en llama.cpp, incluyendo el comportamiento de caché unificada, por lo que prueba la compilación exacta en lugar de confiar en una regla más antigua que simplemente divide el contexto por el número de ranuras.
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 cada una 48K, presupuesta cerca de 96K tokens vivos a menos que la carga de trabajo comparta prefijos o tolere la expulsión y recomputación.
El Tamaño del 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 microlote para diagnosticar el pico transitorio; reduce el contexto, la precisión de la caché, la 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. Perfila la memoria disponible, reserva un pool de caché KV y asigna la caché en bloques para que las secuencias concurrentes no requieran cada una una gran región contigua. Si estás decidiendo si migrar 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 las 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 los grafos CUDA consumen memoria de 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 enfocado en secuencia única 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 GPU de 16 GB, modelos, métodos de cuantización o backends de atención soportan 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é soportado 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 reduce aproximadamente a la mitad el almacenamiento crudo de caché 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 escalas por defecto, cálculo de calentamiento y calibración de datos, y recomienda la calibración basada en datos para la mayor precisión; simplemente configurar FP8 con escala 1.0 es conveniente pero no es automáticamente la elección de calidad más fiable.
La Caché de Prefijo es una Optimización de Reutilización
La caché automática de prefijo permite que una solicitud nueva reutilice bloques KV para un prefijo en caché idéntico. Es excelente para consultas repetidas sobre el mismo documento largo, prompts de sistema compartidos y conversaciones de múltiples rondas porque evita recomputar 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 de GPU No es Memoria Gratis
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 la pantalla, 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 grafos 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 pone por defecto a las GPUs menores de 24 GiB a contexto de 4K, 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.
Configura el valor predeterminado a nivel de servidor y confirma el modelo cargado de esta manera:
OLLAMA_CONTEXT_LENGTH=65536 ollama serve
ollama ps
También puedes configurar num_ctx por solicitud o por 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 en Ollama v0.12.1 muestra cómo el nuevo programador empuja algunos modelos más hacia la CPU en una tarjeta de 16 GB, por lo que fija la versión que mediste.
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 ser solicitado con OLLAMA_FLASH_ATTENTION=1.
Un servicio de contexto largo de 16 GB puede, por lo tanto, iniciarse 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 por Ollama a F16. El FAQ advierte que Q4_0 puede producir una pérdida de calidad más notable, especialmente en contexto más alto, por lo que debe ser un refugio medido en lugar de una predefinición automática de 16 GB.
La Paralelización 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 en 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 que empujar el primer modelo parcialmente a la CPU y hacer que ambas solicitudes sean lentas. La mecánica de encolado, 503 y descargado de modelos detrás de esa elección está documentada en cómo Ollama maneja solicitudes paralelas.
Descarga a CPU: Una Válvula de Escape Válida con un Precio
Mover algunas capas del modelo o el 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 de PCIe y la latencia de la memoria del anfitrión en la ruta de decodificación, donde cada token generado puede pagar el costo. La evidencia del carril y generación de cuándo PCIe realmente afecta está en Rendimiento de LLM y Carriles PCIe.
La descarga puede ser razonable 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 la descarga cuando la capacidad importa más que la latencia.
Observa el acantilado en lugar del promedio. Un servidor puede decodificar rápidamente en 8K, y luego ralentizarse severamente después de que parte del conjunto de trabajo desborde, por lo que haz benchmark en 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 coloque incorrectamente la memoria.
La optimización es parte de la arquitectura del modelo, no un interruptor genérico que puede aplicarse 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 forks experimentales van más allá eligiendo la precisión de la caché o la disposición por capa y profundidad de contexto. El objetivo es atractivo: preservar una precisión más alta 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. Esos números son resultados reportados por el autor de una fork especializada, no evidencia de que el llama.cpp upstream se comporte de la misma manera.
Por Qué Aún es Experimental
La fork combina tipos de caché personalizados, kernels de CUDA, rutas específicas del modelo y restricciones de cadena de herramientas. Es mucho más código del que cabe en confianza que cambiar el almacenamiento de caché de upstream de F16 a Q8_0.
Usa tal fork solo cuando upstream no pueda cumplir un requisito real y puedas 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 fork contra una línea base Q8_0 de upstream con el mismo GGUF, prompt, muestreador, profundidad de contexto y longitud de salida. Mide la VRAM de inicio, la VRAM máxima 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 encajar 128K y aún perder hechos iniciales, dañar la salida tarde en la secuencia o decodificar demasiado lento para ser útil.
Un Proceso de Ajuste de 16 GB Ejemplo: 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 del lote, la descarga de capas, la paralelización y el contexto juntos produce un comando funcional sin explicación.
Paso 1: Establecer el Piso de Pesos
Carga el modelo en contexto 8K, una secuencia y la descarga a GPU prevista. Registra la VRAM del proceso después del calentamiento y verifica que ninguna capa se moviera 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 por defecto. Guarda 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 culpado de KV Q4.
Paso 3: Pasar a Q8 o FP8
Habilita Flash Attention donde se requiera, selecciona Q8_0 en llama.cpp u Ollama, o un modo FP8 soportado en vLLM. Repite los mismos prompts en las mismas profundidades de tokens y confirma que el registro muestra el tipo de caché previsto.
Para muchos despliegues de 16 GB, este es el punto de parada útil. Aproximadamente duplica la capacidad bruta de KV sin hacer que la compresión de la caché sea la cuantización más agresiva en el stack.
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 los tokens por segundo de procesamiento de prompt, tokens por segundo de decodificación, VRAM máxima 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 encaja 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 microlote o los tokens por lote máximos. Si el fallo ocurre solo con solicitudes simultáneas, reduce la concurrencia de secuencias o las ranuras paralelas.
Solo después de que esos controles sean entendidos, intenta la caché mixta Q8/Q4, la caché Q4 completa, la descarga a CPU o una fork adaptativa. Mantén la ejecución Q8 de upstream como la línea base de comparación. Si más adelante agregas decodificación especulativa o MTP, recuerda que sus búferes de borrador son otra línea en la ecuación de presupuesto, no velocidad gratuita — la guía de decodificación especulativa cubre la mecánica 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 adicional 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 deben preservar suficiente detalle para que otro operador pueda reproducir el límite de memoria.
| Campo | Por qué importa |
|---|---|
| GPU y VRAM disponible | El uso de la pantalla 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 controlador, CUDA, ROCm o Vulkan | Determina el comportamiento del backend y el kernel |
| 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 la 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 microlote | Afecta los picos de prefill y la velocidad |
| Velocidad de procesamiento de prompt | Expone la usabilidad de prefill largo |
| Velocidad de decodificación en cada profundidad | Expone el ralentización por ancho de banda de caché |
| VRAM máxima y descarga a CPU | Distingue el encaje del desbordamiento |
| Resultado de calidad de contexto largo | Detecta fallos de compresión o posición |
Usa muestreo de nvidia-smi o la herramienta de proveedor equivalente durante tanto el prefill como la decodificación. El informe de asignación del motor es necesario, pero la memoria máxima del dispositivo 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.
Calcula la caché y verifica 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. En contexto largo, la caché puede borrar todo el ahorro y finalmente exceder la huella de los pesos.
Reporta ambas cuantizaciones. Modelo Q4_K_M, KV Q8_0 es significativo; Modelo de 4 bits es 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.
Usa la asignación paginada para servir cargas de trabajo variables de manera eficiente. Usa 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 de 100K de una sola vez no recibe ningún descuento mágico de memoria simplemente porque la caché de prefijo esté habilitada.
Es una optimización de carga de trabajo, no un sustituto de la ecuación de presupuesto. Mide la tasa de acierto y la presión de caché retenida en servicio de múltiples usuarios.
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 puede degradarse — y como la investigación de divergencia de tokens arriba muestra, incluso la configuración “segura” de Q8_0 no está garantizada para reproducir la salida exacta F16 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 la Paralelización en Automático
Un motor puede elegir una concurrencia que es razonable para el throughput pero imposible para tu objetivo de contexto largo. En 16 GB, una secuencia profunda y varias secuencias cortas son cargas de trabajo fundamentalmente diferentes.
Configura el límite explícitamente, y 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 puntos de partida, no predefiniciones 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 costoso 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 la buena precisión de la caché sobre un máximo impresionante pero raramente útil.
Habilita la reutilización de prefijo cuando el motor la soporte, porque los turnos de codificación a menudo comparten un repositorio o prefijo de conversación grande. Aún así, compacta la salida de herramientas y las 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 varias preguntas apuntan al mismo documento. Mide el tiempo al primer token porque el prefill puede dominar incluso cuando la decodificación permanece aceptable.
Si solo se hará una pregunta, la recuperación o la resumición por fragmentos puede ser más rápida y fiable que forzar todo el corpus a través de una tarjeta de 16 GB. El contexto largo es una herramienta, no un reemplazo para la arquitectura de la información.
Servidor Pequeño de Múltiples Usuarios
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.
Prefiere encolar sobre el desbordamiento incontrolado. Una política de admisión más lenta es menos dañina que que todas las solicitudes crucen de repente PCIe durante la decodificación.
Recomendación Final para Contexto Largo en 16 GB
Para contexto largo en 16 GB, la caché 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 la descarga 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 máxima. Si 128K aún no encaja, un modelo más pequeño es a menudo la optimización más limpia; si encaja pero arrastra, reducir el contexto es a menudo 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 de GPU
- vLLM: caché KV cuantizada (FP8)
- vLLM: caché automática de prefijo
- Ollama: documentación de longitud de contexto
- Ollama FAQ:
OLLAMA_KV_CACHE_TYPEy Flash Attention - llama.cpp-adaptive-turboquant — fork 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 una GPU de 16GB VRAM
- Qwen 3.6 27B y 35B MTP vs Estándar en GPU de 16GB