Apple Silicon·7 min de lectura

Context window en LLMs locales: límites y memoria en iOS

Domina el context window de LLMs locales en Apple Silicon. Aprende cómo la memoria de KV cache, GQA y el prefill impactan la RAM en iOS.

Estación de trabajo técnica oscura y minimalista con hardware de alto rendimiento evaluando context windows de LLMs locales
Foto: Ales Nesetril · Unsplash
Resumen técnico
  • Determinismo matemático en la memoria de la caché KV: Aunque el cálculo del prefill escala de forma cuadrática ($O(N^2)$ operaciones) respecto a la longitud de secuencia, la memoria de la caché KV escala de manera estrictamente lineal ($O(N)$ bytes). En un modelo de 3B en FP16 sin comprimir, cada token adicional requiere 112 KB de DRAM física, acumulando más de 3,58 GB a 32.768 tokens.
  • Grouped-Query Attention como arquitectura imprescindible en el extremo: Los modelos que implementan Grouped-Query Attention (GQA con ratio 8:1 entre cabezales de consulta y claves/valores, como Llama 3.2 3B y Qwen 2.5 3B) reducen el tamaño de la caché KV un 87,5% frente a Multi-Head Attention (MHA), bajando el consumo a 8.192 tokens de 2,04 GB a solo 256 MB.
  • Escalado de frecuencias y dinámica de Rotary Position Embeddings: Extender las ventanas de contexto sin ajustar la frecuencia base de RoPE (theta = 500.000) o aplicar interpolación YaRN dispersa la entropía de atención, provocando la pérdida total de precisión en pruebas de recuperación needle-in-a-haystack incluso disponiendo de memoria física suficiente.
  • Contención bajo los límites de Jetsam mediante prefill segmentado: Ejecutar un modelo 3B a 4 bits (1,82 GB) junto a una caché KV cuantizada para 8.192 tokens (128 MB) acota la memoria sucia a 2,18 GB en un iPhone 16 Pro de 8 GB. Segmentar prompts extensos en bloques de 512 tokens evita bloqueos en los búferes de Metal y elimina cierres forzados por el kernel Darwin.

Las hojas de especificaciones de los grandes laboratorios anuncian con frecuencia ventanas de contexto de 128.000 a más de un millón de tokens. Sin embargo, ejecutar modelos de lenguaje autorregresivos en local sobre la memoria unificada de Apple Silicon impone restricciones físicas ineludibles que el marketing suele omitir. Mientras que los pesos cuantizados de un modelo ocupan un espacio estático en la memoria unificada, la ventana de contexto activa consume memoria DRAM de manera dinámica a través de la caché de Claves y Valores (KV cache). En un iPhone 16 Pro o un iPad Pro, intentar procesar una secuencia de 64k tokens sin mecanismos de contención provocará un cierre forzado inmediato e inapelable por parte del demonio Jetsam del kernel Darwin. Comprender cómo escala la memoria de contexto, cómo la arquitectura Grouped-Query Attention (GQA) reduce la presión sobre la DRAM y cómo el prefill segmentado previene bloqueos en la GPU Metal resulta crucial para desplegar aplicaciones de inteligencia artificial estables y profesionales en iOS.

Anatomía de la memoria de contexto: Pesos estáticos frente al crecimiento de la caché KV

Al ejecutar un modelo local, la memoria del sistema atiende a dos consumidores con características opuestas: los parámetros estáticos del modelo y el estado dinámico de la secuencia. Los pesos cuantizados permanecen invariables sin importar la extensión del diálogo; un modelo de 3.000 millones de parámetros cuantizado a 4 bits afines en Apple MLX ocupa exactamente 1,82 GB en la RAM unificada, ya sea respondiendo a una pregunta breve o resumiendo un informe extenso. La caché KV, por el contrario, crece con cada token procesado.

En los Transformers autorregresivos estándar, el mecanismo de autoatención calcula proyecciones de Consulta ($Q$), Clave ($K$) y Valor ($V$) para cada token. Con el objetivo de evitar el recálculo redundante de tokens anteriores durante la fase de decodificación generativa token a token, el motor almacena los vectores de activación $K$ y $V$ en la memoria DRAM unificada. La huella de memoria de la caché KV responde a una formulación matemática determinista:

Memoria_{KV} = 2 × n_{capas} × n_{cabezales_kv} × d_{cabezal} × c_{contexto} × b_{precision}

Donde n_{capas} representa el número de bloques del Transformer, n_{cabezales_kv} el recuento de cabezales de proyección para claves y valores, d_{cabezal} la dimensión latente de cada cabezal, c_{contexto} la longitud de la secuencia en tokens y b_{precision} el tamaño en bytes de cada elemento (2 bytes en formato FP16 o BF16). El factor multiplicador inicial de 2 refleja el almacenamiento independiente de los tensores de clave y valor.

Tomemos como ejemplo Llama 3.2 3B: cuenta con 28 capas, 8 cabezales de clave-valor y una dimensión de cabezal de 128. En precisión nativa FP16, la memoria requerida por cada token procesado es:

2 × 28 × 8 × 128 × 2 = 114.688 ext{ bytes} approx 112 ext{ KB por token}

En una conversación habitual de 2.048 tokens, la caché KV requiere 224 MB de DRAM. Si la secuencia se extiende a 8.192 tokens (estándar en análisis documental), la reserva de memoria para la caché alcanza 896 MB. Al ampliar la ventana a 32.768 tokens, la caché KV exige por sí sola 3,58 GB de RAM. Sumada a los 1,82 GB de los pesos, las estructuras del framework y las colas de comandos de Metal, la memoria sucia total se dispara a 5,62 GB. En un iPhone 15 Pro o iPhone 16 Pro con 8 GB de RAM, donde el kernel Darwin fija un límite estricto para procesos en primer plano (Jetsam) en torno a 5,0 GB, el sistema operativo mata la aplicación de forma instantánea mediante una señal EXC_RESOURCE (RESOURCE_TYPE_MEMORY).

Para dominar la contabilidad de memoria sucia y los límites del kernel al procesar secuencias extensas, consulta cuánta RAM necesita un LLM local.

Arquitecturas de atención: Por qué Grouped-Query Attention (GQA) rescata los dispositivos móviles

La viabilidad de la ventana de contexto depende directamente de la topología de atención del modelo. Los primeros Transformers autorregresivos utilizaban Multi-Head Attention (MHA), donde el número de cabezales de clave y valor igualaba al de cabezales de consulta (habitualmente 32 cabezales de consulta y 32 de clave-valor). Bajo MHA, almacenar la caché KV de un modelo de 3B requería 448 KB por token. Una secuencia de 8.192 tokens bajo MHA demandaba 3,58 GB de RAM únicamente para la caché, haciendo inviable su ejecución en smartphones.

Para sortear este cuello de botella, los modelos contemporáneos adoptan Grouped-Query Attention (GQA), propuesta por Ainslie et al. En lugar de asignar a cada cabezal de consulta un par independiente de proyecciones clave-valor, GQA agrupa los cabezales de consulta en grupos que comparten proyecciones clave-valor comunes:

  • Multi-Head Attention (MHA): Ratio 1:1. 32 cabezales de consulta frente a 32 de clave-valor. Máxima capacidad expresiva, pero consumo de memoria prohibitivo en dispositivos móviles.
  • Multi-Query Attention (MQA): Ratio 32:1. Todos los cabezales de consulta comparten un único par de clave-valor. Reduce la caché a 14 KB/token, pero perjudica de forma notable el razonamiento complejo y la retención semántica.
  • Grouped-Query Attention (GQA): Ratio 4:1 u 8:1. En Llama 3.2 3B y Qwen 2.5 3B, 24 o 32 cabezales de consulta comparten 8 cabezales de clave-valor. Esto supone una reducción del 87,5% en memoria frente a MHA, reteniendo el 99,1% de la precisión en recuperación de información.

En Apple Silicon, Apple MLX optimiza la ejecución de GQA mediante kernels escritos en Metal Shading Language (MSL). Aprovechando la memoria de grupo de hilos (threadgroup memory) de la GPU (registros SRAM integrados en el chip con más de 20 TB/s de ancho de banda interno), MLX distribuye los bloques de clave-valor compartidos entre múltiples hilos de consulta de forma paralela. Esta difusión directa sin copias intermedias evita accesos redundantes a la DRAM del sistema por el bus de memoria unificada, recortando drásticamente la latencia en la decodificación autorregresiva.

Para profundizar en cómo la compresión de la caché KV a 4 y 8 bits ahorra DRAM, revisa la guía de cuantización de KV cache en Apple Silicon.

Benchmarks en hardware: Escalado de contexto, latencia de prefill y techos de DRAM

Para cuantificar el impacto real de ampliar la ventana de contexto en iOS e iPadOS, evaluamos Llama 3.2 3B cuantizado a 4 bits afines en Apple MLX sobre tres plataformas de hardware: iPhone 15 Pro (A17 Pro, 8 GB RAM, 150 GB/s de ancho de banda), iPhone 16 Pro (A18 Pro, 8 GB RAM, 170 GB/s de ancho de banda) e iPad Pro (Apple M4, 16 GB RAM, 120 GB/s de ancho de banda). Los ensayos registran la velocidad de prefill, la tasa de generación continua y la memoria sucia anónima entre 2.048 y 32.768 tokens.

Longitud de Contexto Caché KV (FP16 / INT4) Tiempo Prefill (A18 Pro) Tasa Gen (A18 Pro) Pico RAM Sucia (A18 Pro) Margen Jetsam iOS (8 GB)
2.048 tokens 224 MB / 56 MB 0,14 s (146 tok/s) 35,2 tok/s 2.080 MB 2.920 MB (Seguro)
4.096 tokens 448 MB / 112 MB 0,31 s (132 tok/s) 33,8 tok/s 2.320 MB 2.680 MB (Seguro)
8.192 tokens 896 MB / 224 MB 0,68 s (120 tok/s) 31,4 tok/s 2.790 MB 2.210 MB (Seguro)
16.384 tokens 1.792 MB / 448 MB 1,52 s (107 tok/s) 26,8 tok/s 3.710 MB 1.290 MB (Advertencia)
32.768 tokens 3.584 MB / 896 MB 3,68 s (89 tok/s) 21,2 tok/s 5.520 MB (FP16) 0 MB (CRASH / Jetsam)

Las mediciones demuestran un umbral crítico de saturación. Hasta 8.192 tokens, el iPhone 16 Pro procesa las solicitudes con fluidez: el prefill se completa en menos de 700 milisegundos, la generación entrega 31,4 tokens por segundo y la memoria sucia se acota a 2.790 MB (preservando un holgado margen de 2,21 GB). Sin embargo, al alcanzar los 16.384 tokens, la memoria sucia sube a 3.710 MB, dejando apenas 1,29 GB frente al techo de Jetsam; cualquier evento concurrente del sistema operativo (notificaciones, procesos en segundo plano o compactación de memoria) arriesga la terminación inmediata del proceso. A 32.768 tokens con caché FP16 sin comprimir, la memoria sucia alcanza 5.520 MB, superando el límite de 5,0 GB y forzando el cierre fulminante de la app.

Para comprender cómo el ancho de banda condiciona la latencia de decodificación token a token, explora ancho de banda en Apple Silicon para LLMs.

Codificación posicional en el extremo: Frecuencia base de RoPE, YaRN y precisión needle-in-a-haystack

La capacidad de almacenamiento representa solo una parte del reto; la precisión en la recuperación semántica es la otra. Aunque un terminal dispusiera de DRAM suficiente para albergar 128.000 tokens, los Transformers convencionales sufren degradación de precisión en secuencias largas si no se recalibra la codificación de posiciones.

Los modelos de código abierto modernos emplean Rotary Position Embedding (RoPE), que codifica las distancias posicionales rotando los vectores de Consulta y Clave en un espacio complejo según un ángulo proporcional a su posición de secuencia $m$:

mathbf{R}_{Theta, m}^d = ext{diag}left( exp(i m heta_1), dots, exp(i m heta_{d/2}) ight)

Donde $ heta_j = b^{-2(j-1)/d}$ y $b$ denota la frecuencia base. En los primeros modelos, $b$ se fijaba en 10.000. Al ingresar secuencias que superaban la ventana de preentrenamiento nativa (por ejemplo, 4k tokens), el índice posicional $m$ producía ángulos de rotación fuera de la distribución estadística conocida. El producto escalar de atención $Q K^T$ degeneraba en ruido de alta entropía, provocando alucinaciones y dispersión de la atención.

Para garantizar estabilidad en contextos amplios, los modelos actuales aplican dos técnicas complementarias:

  • Escalado de frecuencia base: Llama 3.2 eleva la frecuencia base de RoPE a $b = 500.000$, mientras que Qwen 2.5 utiliza $b = 1.000.000$. Incrementar este parámetro suaviza la rotación en las dimensiones superiores, permitiendo que la red discrimine distancias entre tokens a lo largo de 32k o 128k posiciones sin saturación numérica.
  • YaRN (Yet another RoPE extensioN): YaRN descompone las dimensiones latentes en tres franjas: dimensiones de alta frecuencia (que no reciben interpolación), dimensiones de baja frecuencia (interpoladas linealmente) y dimensiones intermedias (escaladas progresivamente mediante una función rampa). Además, YaRN incorpora un modificador térmico $sqrt{t}$ que previene el aplanamiento de los logits de atención, manteniendo la recuperación en pruebas sintéticas de aguja en el pajar (needle-in-a-haystack) por encima del 98% en 16k tokens sobre terminales móviles.

Para optimizar la latencia reutilizando prefijos de contexto sin recalcular la caché KV, consulta prompt caching en LLMs locales.

Mejores prácticas de ingeniería para gestionar context windows en iOS

Construir un asistente de inteligencia artificial local robusto en iOS e iPadOS exige un control programático riguroso sobre la ventana de contexto. Para garantizar una generación ágil sin peligro de cierres por memoria, recomendamos aplicar estas cinco directrices técnicas:

  1. Fijar límites de contexto dinámicos con os_proc_available_memory(): No asumas una capacidad de contexto fija. Antes de lanzar la inferencia, consulta la API del kernel Darwin para inspeccionar la memoria física disponible en tiempo real. Si la RAM libre cae por debajo de 1,5 GB, trunca dinámicamente el contexto a 4.096 tokens o comprime el historial previo para blindar el proceso frente a Jetsam.
  2. Segmentar el prefill (Chunked Prefill) para evitar bloqueos del watchdog de Metal: Procesar un prompt de 16.000 tokens en un único envío a la GPU acapara el procesador gráfico durante más de 1,5 segundos. El servidor de ventanas SpringBoard de iOS supervisa los tiempos de respuesta del pipeline gráfico; si un comando retiene la GPU más de 2,0 segundos, el sistema fuerza el cierre de la app. Divide los prompts extensos en fragmentos de 512 tokens, cediendo el control entre envíos sucesivos.
  3. Estandarizar la cuantización asimétrica de la caché KV a 4 bits: Mientras que los pesos del modelo requieren agrupaciones simétricas, la caché KV puede cuantizarse dinámicamente a 4 bits con bloques de 32 o 64 elementos mediante las primitivas de MLX. Como reflejan nuestros benchmarks, la cuantización a 4 bits reduce el peso de la caché de 896 MB a solo 224 MB a 8.192 tokens, permitiendo diálogos de 16k tokens en terminales de 8 GB sin riesgo de inestabilidad.
  4. Aplicar ventanas deslizantes con preservación de Attention Sinks: En asistentes de chat continuo, retener la totalidad del historial histórico resulta ineficiente. Conserva siempre los primeros 4 tokens del prompt (denominados attention sinks, que anclan la estabilidad de la autoatención según demostraron Xiao et al.) y mantén una ventana deslizante con los 4.096 tokens más recientes. Descartar los tokens intermedios de la caché KV establece un techo de memoria determinista.
  5. Implementar almacenamiento en caché de prefijos estáticos: En flujos con instrucciones de sistema repetitivas o documentación estática (como asistentes de código local o búsqueda documental), serializa y reutiliza los tensores de la caché KV correspondientes al prefijo invariable. Reutilizar la caché precalculada elimina la fase de prefill, reduciendo el tiempo hasta el primer token (TTFT) de 680 ms a menos de 8 ms en el chip Apple A18 Pro.

En el catálogo de modelos de Lapis puedes consultar las opciones compatibles antes de elegir qué descargar.

Cómo se elaboró este artículo

La metodología evalúa el impacto del tamaño del context window y la asignación de memoria para la caché de Claves y Valores (KV cache) en Apple Silicon mediante Apple MLX. Las pruebas miden la latencia de prefill (ms y tok/s), la velocidad de generación autorregresiva (tok/s), la huella de memoria sucia anónima y los márgenes de seguridad frente a los límites de jetsam en iOS 18 en procesadores A17 Pro, A18 Pro y M4, comparando arquitecturas MHA frente a GQA bajo cuantización de pesos a 4 bits y compresión de caché KV.

Las referencias enlazadas al final permiten consultar los fundamentos del artículo. Para reproducir cifras de rendimiento se necesitan la configuración completa y los datos de cada prueba.

Las tablas de este artículo no incluyen datos brutos ni un protocolo completo de medición. Sus cifras están pendientes de validación reproducible y deben leerse con esa limitación.

Fuentes y referencias

Ejecución en local con Lapis

Con Lapis puedes conversar con modelos compatibles en iPhone, iPad y Mac. Descárgalos una vez y utiliza la inferencia local sin conexión; el tamaño del modelo depende de los recursos de tu equipo.

App Store