Optimización de KV Cache: Eficiencia de Memoria para LLMs en Producción
Actualizado el 11 de diciembre de 2025
Actualización de diciembre 2025: La inferencia tradicional desperdicia 60-80% de la memoria de KV cache debido a fragmentación. PagedAttention de vLLM reduce el desperdicio a menos del 4%, permitiendo mejoras de rendimiento de 2-4x. Un modelo de 70B con contexto de 8K requiere ~20GB de cache por solicitud, ~640GB para un lote de 32. El KV cache ahora frecuentemente supera el consumo de memoria de los pesos del modelo. Las técnicas de optimización permiten contextos más largos y lotes más grandes en hardware existente.
Los sistemas de inferencia de LLM desperdician 60-80% de la memoria de KV cache asignada debido a fragmentación y sobreasignación.¹ Ese desperdicio se traduce directamente en menor rendimiento, mayores costos y límites artificiales en las longitudes de contexto. PagedAttention, introducido por vLLM, redujo el desperdicio de KV cache a menos del 4%, permitiendo mejoras de rendimiento de 2-4x que transformaron la economía de inferencia en producción.² Comprender las técnicas de optimización de KV cache ayuda a las organizaciones a maximizar la utilización de GPU y atender más usuarios con la infraestructura existente.
La gestión de KV cache se ha convertido en el cuello de botella crítico para despliegues de LLM en producción. El consumo de memoria crece linealmente con la longitud de secuencia y el tamaño del lote, agotando rápidamente incluso GPUs de alta memoria como H100 y H200. Dominar las técnicas de optimización de cache permite contextos más largos, lotes más grandes e inferencia más rentable a escala.
Por qué importa el KV caching
Los modelos transformer calculan atención sobre todos los tokens anteriores al generar cada nuevo token. Sin caching, generar 1,000 tokens requiere recalcular la atención desde cero 1,000 veces—aumentando cuadráticamente el costo con la longitud de secuencia.
Solución de KV caching: Almacenar tensores de key y value de tokens anteriores, reutilizándolos para cálculos de atención posteriores. Cada nuevo token calcula atención contra valores en cache en lugar de regenerarlos.
Impacto en memoria: Un modelo de 70B parámetros generando 8,192 tokens con tamaño de lote 32 requiere aproximadamente 40-50GB de memoria de KV cache solo—frecuentemente superando los propios pesos del modelo.³
El problema de escalabilidad: La memoria de KV cache crece como:
Memoria = tamaño_lote × longitud_secuencia × num_capas × 2 × dim_oculta × bytes_precisión
Para Llama 3.1-70B con FP16: - Cache por token: ~2.5MB - Contexto de 8K: ~20GB por solicitud - Lote de 32: ~640GB de KV cache total
PagedAttention: la optimización fundamental
PagedAttention de vLLM revolucionó la gestión de KV cache tratando la memoria de GPU como memoria virtual de sistema operativo:⁴
Cómo funciona
Asignación tradicional: Reservar bloques de memoria contiguos para la máxima longitud de secuencia posible. Un contexto máximo de 4K asigna 4K de cache incluso para solicitudes de 100 tokens, desperdiciando 97.5% de la memoria reservada.
Asignación paginada: Dividir el KV cache en bloques de tamaño fijo (páginas). Asignar páginas bajo demanda conforme las secuencias crecen. Liberar páginas cuando las secuencias terminan.
Mapeo de tabla de bloques: Como las tablas de páginas del SO, PagedAttention mantiene mapeos entre posiciones lógicas de secuencia y ubicaciones físicas de memoria. Las secuencias ven memoria continua mientras el almacenamiento físico permanece no contiguo.
Impacto en rendimiento
- Desperdicio de memoria: 60-80% → menos del 4%
- Rendimiento: mejora de 2-4x versus asignación tradicional
- Fragmentación de memoria: Virtualmente eliminada⁵
Implementación en vLLM
from vllm import LLM, SamplingParams
# PagedAttention habilitado por defecto
llm = LLM(
model="meta-llama/Llama-3.1-70B-Instruct",
tensor_parallel_size=4,
gpu_memory_utilization=0.90, # Usar 90% de memoria GPU
max_model_len=32768,
)
vLLM gestiona automáticamente la asignación de páginas, desasignación y compartición de memoria sin configuración explícita.
Prefix caching y compartición de memoria
PagedAttention permite compartición eficiente de memoria entre solicitudes con prefijos comunes:
System prompts compartidos: Cuando múltiples solicitudes usan system prompts idénticos, las páginas físicas que almacenan esos tokens se comparten en lugar de duplicarse.
Prefix caching automático: El Automatic Prefix Caching (APC) de vLLM detecta prefijos comunes entre solicitudes y comparte bloques de KV cache automáticamente:
llm = LLM(
model="meta-llama/Llama-3.1-8B-Instruct",
enable_prefix_caching=True,
)
Impacto en producción: Las aplicaciones con system prompts consistentes o contexto repetido (RAG con documentos comunes, ejemplos few-shot) ven ahorros dramáticos de memoria y reducción de latencia. Tasas de cache hit del 87%+ son alcanzables con prompts bien estructurados.⁶
Cuantización de KV cache
Comprimir valores de KV cache reduce los requisitos de memoria a costa de una degradación menor de precisión:
KV cache FP8
Las GPUs Hopper y Blackwell soportan KV cache FP8 nativo:
# vLLM FP8 KV cache
llm = LLM(
model="meta-llama/Llama-3.1-70B-Instruct",
kv_cache_dtype="fp8",
)
FP8 reduce a la mitad la memoria de KV cache versus FP16 con impacto mínimo en calidad para la mayoría de aplicaciones. La optimización se vuelve esencial para inferencia de contexto largo donde el cache domina el consumo de memoria.
KV cache INT4
Soporte experimental de KV cache de 4 bits reduce aún más la memoria:⁷ - Reducción de memoria: 4x versus FP16 - Impacto en calidad: Depende de la tarea, requiere evaluación - Mejor para: Aplicaciones de contexto largo con memoria limitada
Selección de cuantización
| Precisión | Ahorro de Memoria | Impacto en Calidad | Caso de Uso |
|---|---|---|---|
| FP16 | Base | Ninguno | Por defecto, crítico en calidad |
| FP8 | 50% | Mínimo | Inferencia en producción |
| INT8 | 50% | Bajo | Despliegues sensibles al costo |
| INT4 | 75% | Moderado | Restricciones extremas de memoria |
Estrategias de evicción de cache
Cuando la presión de memoria excede la capacidad disponible, las políticas de evicción de cache determinan qué tokens descartar:
Atención de ventana deslizante
Mantener solo tokens recientes en cache, descartando contexto antiguo:
# Ventana deslizante conceptual
def sliding_window_cache(kv_cache, window_size):
if len(kv_cache) > window_size:
kv_cache = kv_cache[-window_size:]
return kv_cache
Simple pero efectivo para aplicaciones donde el contexto reciente importa más. La ventana deslizante arquitectural (como Mistral) implementa esto nativamente.
Evicción basada en atención
Remover tokens con puntuaciones de atención más bajas, manteniendo contexto importante:
PagedEviction (2025): Algoritmo de evicción por bloques adaptado para PagedAttention que identifica y remueve bloques de baja importancia sin modificar kernels CUDA.⁸
Caching guiado por entropía: Asignar presupuesto de cache basado en la entropía de atención por capa—capas con patrones de atención más amplios reciben más cache, capas enfocadas reciben menos.⁹
Streaming LLM
Para generación de longitud infinita, Streaming LLM mantiene: - Tokens iniciales de "attention sink" (primeros 4-8 tokens) - Tokens recientes dentro de la ventana deslizante - Descarta contexto intermedio
El enfoque permite generación teóricamente ilimitada con memoria fija, aunque la calidad se degrada para tareas que requieren dependencias de largo alcance.
Offloading de KV cache
Cuando la memoria GPU resulta insuficiente, transferir cache a niveles de almacenamiento más lentos:
Offloading a CPU
Mover caches de secuencias inactivas a RAM del sistema:
# Integración de LMCache para offloading
from lmcache import LMCacheEngine
cache_engine = LMCacheEngine(
backend="cpu",
max_gpu_cache_size="20GB",
cpu_cache_size="100GB",
)
Impacto en latencia: La transferencia CPU-GPU añade 10-50ms por recuperación de cache. Adecuado para cargas de trabajo por lotes o cuando los límites de memoria GPU impiden servir en absoluto.
Rendimiento: LMCache con vLLM logra reducción de latencia de 3-10x versus recómputo al cachear en memoria CPU en lugar de regenerar.¹⁰
Offloading a disco
Para casos extremos, cachear en almacenamiento NVMe: - Latencia: 100-500ms por recuperación - Caso de uso: Contextos muy largos que de otro modo serían imposibles - No adecuado para aplicaciones interactivas
Caching por niveles
Los sistemas de producción frecuentemente implementan caching multinivel:
- GPU HBM: Secuencias activas generando activamente
- CPU RAM: Secuencias tibias recientemente activas
- NVMe SSD: Secuencias frías para potencial reutilización
Políticas inteligentes de promoción y degradación mueven el cache entre niveles basándose en patrones de acceso.
Routing consciente de KV cache
La inferencia distribuida se beneficia de enrutar solicitudes a pods que mantienen cache relevante:
Framework llm-d
Framework nativo de Kubernetes con routing consciente de KV cache:¹¹
# Configuración de routing de cache llm-d
routing:
strategy: kv_cache_aware
cache_hit_weight: 0.8
load_balance_weight: 0.2
Resultados de rendimiento: - 87% de tasa de cache hit con cargas de trabajo con muchos prefijos - 88% más rápido en time-to-first-token para cache hits tibios - Reducción significativa en cómputo redundante a través del clúster
Patrones de implementación
Sesiones persistentes: Enrutar solicitudes de la misma conversación al mismo pod.
Hashing de prefijos: Hashear system prompts para determinar routing al pod, asegurando cache hits de prefijos.
Routing consciente de carga: Balancear localidad de cache contra utilización del pod para prevenir puntos calientes.
Guía de dimensionamiento para producción
Estimación de memoria
Calcular requisitos de KV cache antes del despliegue:
def estimate_kv_cache_memory(
num_layers: int,
hidden_dim: int,
num_kv_heads: int,
head_dim: int,
max_seq_len: int,
max_batch_size: int,
precision_bytes: int = 2, # FP16
) -> float:
"""Estimar memoria de KV cache en GB"""
per_token = num_layers * 2 * num_kv_heads * head_dim * precision_bytes
total = per_token * max_seq_len * max_batch_size
return total / (1024 ** 3)
# Ejemplo Llama 3.1-70B
memory_gb = estimate_kv_cache_memory(
num_layers=80,
hidden_dim=8192,
num_kv_heads=8, # GQA
head_dim=128,
max_seq_len=8192,
max_batch_size=32,
)
print(f"Memoria de KV cache: {memory_gb:.1f} GB")
Planificación de capacidad
Regla general: Reservar 40-60% de la memoria GPU para KV cache, el resto para pesos del modelo y activaciones.
Ejemplo H100 80GB: - Pesos del modelo (70B FP16): ~140GB → 2x GPU con paralelismo de tensores - Disponible por GPU para cache: ~30-35GB después de pesos y overhead - Máximo de secuencias concurrentes: Depende de la longitud promedio de contexto
Prioridad de optimización
- Habilitar PagedAttention: Por defecto en vLLM, gran ganancia de eficiencia
- Habilitar prefix caching: Si las cargas de trabajo tienen prefijos comunes
- Implementar FP8 KV cache: Al usar GPUs Hopper/Blackwell
- Añadir routing consciente de cache: A escala de clúster con inferencia distribuida
- Considerar offloading: Solo cuando la memoria GPU resulte insuficiente
Monitoreo y observabilidad
Rastrear métricas de KV cache en producción:
Métricas clave: - Utilización de cache: Porcentaje de cache asignado en uso - Tasa de cache hit: Efectividad del prefix cache - Tasa de evicción: Frecuencia de desbordamiento de cache - Fragmentación de memoria: Espacio desperdiciado dentro de bloques asignados
Endpoint de métricas de vLLM:
# Métricas de Prometheus disponibles en /metrics
# kv_cache_usage_percent
# kv_cache_total_blocks
# kv_cache_used_blocks
# prefix_cache_hit_rate
Umbrales de alertas: - Utilización de cache > 90%: Escalar capacidad o reducir tamaño de lote - Tasa de hit < 50%: Revisar configuración de prefix caching - Tasa de evicción alta: Aumentar asignación de memoria u optimizar prompts
Las organizaciones que despliegan inferencia de LLM en producción pueden aprovechar la experiencia en infraestructura de Introl para planificación de capacidad GPU y optimización en despliegues globales.
El imperativo de eficiencia de memoria
La optimización de KV cache representa una de las mejoras de mayor impacto para despliegues de LLM en producción. PagedAttention por sí solo ofrece mejoras de rendimiento de 2-4x—equivalente a duplicar o cuadruplicar la inversión en GPU sin costo adicional de hardware.
El panorama de optimización continúa evolucionando. FastGen de Microsoft demostró 50% de reducción de memoria mediante compresión adaptativa. El caching guiado por entropía asigna presupuesto inteligentemente entre capas. El routing consciente de cache permite ganancias de eficiencia a escala de clúster previamente imposibles.
Para organizaciones ejecutando inferencia a escala, la optimización de KV cache debería estar entre las primeras optimizaciones evaluadas. Las técnicas requieren mini
[Contenido truncado para traducción]