Running a 35B local LLM on a laptop's integrated GPU with 64 GB of shared memory

A 35-billion-parameter mixture-of-experts model and a 27-billion-parameter dense one are run on the integrated Radeon 860M of a ThinkPad with 64 GB of LPDDR5X, through Ollama and, on the same hard-linked weights, LM Studio. The piece explains why an integrated GPU's capacity is the system RAM and its speed is that RAM's bandwidth, measures both models on the GPU and on the CPU, and records a conclusion that had to be withdrawn after three measurement errors. It ends with the decision not to reserve dedicated video memory, a Claude Code hookup over MCP, a priced answer on whether the 64 GB were worth it and what memory prices are doing in 2026.


El portátil es un Lenovo ThinkPad con un AMD Ryzen AI 7 PRO 450, cuya Radeon 860M integrada es la única GPU de la máquina, y 64 GB de LPDDR5X soldados a la placa. Quería un modelo de lenguaje funcionando en él que bastara para resumir, extraer datos y hacer borradores, sin conexión, y al que Claude Code pudiera pasarle trabajo. Me llevó un día, el 21 de octubre de 2026, y acabó en un repositorio público pequeño, apu-llm: una línea lo instala todo en Windows, y un comando llamado apu le pregunta cosas al modelo, lo mide y se lo sirve a Claude Code.

El modelo que se quedó es Qwen3.6 35B-A3B, 35.000 millones de parámetros de los que unos 3.000 millones trabajan en cada token. Escribe 11,7 tokens por segundo en la GPU integrada, lee un prompt largo a 93 y deja libres 11 o 12 GB con un navegador y un editor abiertos. Por el camino hubo una medida que hice mal, que llegué a registrar como hallazgo y retiré 37 minutos después, y ese error dice más sobre cómo medir este tipo de máquina que la tabla final. Todos los números que siguen salen del diario del repositorio y de los archivos de benchmark que guarda.

El nombre26 · oct 21Read noteAntes de apu-llm pasé por thinkpad-local-llm, unified-memory-llm y ryzen-ai-llm. Lo del ThinkPad es casual: cualquier portátil con este tipo de chip funciona igual. Unified memory es la palabra que usa Apple, y los Mac tienen sus propias herramientas; esto es un repo de Windows. Ryzen AI lo ata a AMD, cuando un Intel Core Ultra debería ir por el mismo camino de Vulkan. APU también es palabra de AMD, ya lo sé, pero nombra lo que importa: una CPU y una GPU que comparten la misma memoria.

Por qué la GPU integrada no tiene memoria propia

Una tarjeta gráfica de sobremesa tiene sus propios chips de memoria en su propia placa, GDDR7 en una NVIDIA actual, conectados a la GPU por un bus ancho y a nada más. Una GPU integrada está en la misma pieza de silicio que los núcleos de la CPU y no tiene chips propios. Lee y escribe en la misma LPDDR5X que usa la CPU. El firmware aparta al arrancar una porción pequeña y fija de esa RAM (aquí 512 MB, el valor por defecto de la BIOS, que es lo que Windows muestra como memoria dedicada de la GPU), y todo lo demás que necesita la GPU lo toma prestado del resto de la RAM según lo va pidiendo, a través de su propia traducción de direcciones, como memoria compartida.

Ese reparto separa las dos preguntas que plantea un modelo local. Si un modelo cabe es una cuestión de capacidad, y en este portátil la capacidad de la GPU es una buena parte de 64 GB, más que los 32 GB de la tarjeta de consumo más grande de NVIDIA. Lo rápido que va es una cuestión de ancho de banda de memoria, y ahí la GPU integrada se queda muy atrás. La memoria son cuatro chips en un bus de 128 bits a 8000 transferencias por segundo, así que como mucho 16 bytes por 8000 millones, 128 GB/s, tienen que dar servicio a la CPU y a la GPU a la vez. Una RTX 5090 tiene 1.792 GB/s para ella sola1.

1NVIDIA, Compare GeForce graphics cards, ancho de banda de memoria de la RTX 5090 (32 GB GDDR7) y de la RTX 5080 (16 GB GDDR7, 960 GB/s).

El ancho de banda importa por cómo escribe un modelo. Cada token nuevo es una pasada por la red (un paso de decodificación), y esa pasada multiplica las activaciones del token por cada matriz de pesos que atraviesa. La aritmética es poca, un par de operaciones por peso, mientras que cada uno de esos pesos tiene que viajar de la RAM al procesador. Por eso la generación está limitada por la memoria: el tiempo por token es más o menos los bytes de pesos leídos divididos por el ancho de banda, y las unidades de cálculo esperan. Con los pesos guardados a unos 4,8 bits cada uno (cuantización al formato Q4_K_M), los bytes que lee un modelo por token son sus parámetros activos por 0,6 bytes.

Aquí el tipo de modelo lo decide todo. Un modelo denso hace pasar cada token por todos sus pesos. Un mixture of experts sustituye el bloque feed-forward de cada capa por muchos bloques pequeños y un router que elige unos pocos por token: Qwen3.6 35B-A3B tiene 256 expertos y activa 8 más uno compartido, así que en cada token trabajan unos 3 de sus 35.000 millones de parámetros1. Los 35.000 millones tienen que estar en memoria igualmente, porque el token siguiente puede querer otros expertos, pero por cada token solo se leen unos 2 GB.

1Qwen, Qwen3.6-35B-A3B model card, Hugging Face, abril de 2026: 35B en total, 3B activos, 256 expertos, 8 enrutados y 1 compartido activos por token, Apache 2.0.

## La máquina Memoria64 GB LPDDR5X-80004 × 16 GB, soldada, 63,1 GB visibles para Windows Bus128 bits Ancho de banda teórico128 GB/scompartido por CPU y GPU Memoria dedicada de la GPU512 MBvalor por defecto de la BIOS ## Bytes leídos por token, Q4_K_M Qwen3.6 35B-A3B~2 GB~3B parámetros activos Qwen3.8 27B~16 GBdenso, todos los pesos ## Techo solo por ancho de banda Qwen3.6 35B-A3B~64 tok/s Qwen3.8 27B~8 tok/s

Los techos son lo que permitiría un sistema de memoria perfecto, y ninguno real llega. Leer un prompt es otra carga de trabajo: el motor pasa cientos de tokens del prompt por cada peso mientras lo tiene a mano, así que el coste deja de estar en mover bytes y pasa a estar en hacer cuentas, que es donde deberían notarse las muchas unidades paralelas de una GPU. Al escribir, CPU y GPU deberían quedar casi empatadas, porque beben de la misma memoria, y al leer debería ganar la GPU. Esa predicción es lo que acabaron confirmando las medidas de más abajo, después de parecer que la contradecían.

Ollama ignora la GPU que ve

Ollama 0.40.7 se instaló con winget install Ollama.Ollama. Su ventana se abre con una pantalla de cuenta opcional, que para uso local no hace falta, y luego enseña unas integraciones que lanzan agentes de programación, Claude Code entre ellos, contra un modelo local.

La primera pantalla de Ollama. La cuenta es para los modelos más rápidos y grandes que Ollama aloja; el enlace de debajo del botón se la salta.La página de integraciones que viene después: cada entrada lanza un agente contra un modelo que sirve Ollama.

El primer modelo funcionó en la CPU, cosa que la app no enseña y el registro del servidor sí. La detección de GPU rechazó la Radeon dos veces, por dos motivos distintos:

TEXT Copy

level=WARN msg="dropping ROCm device — no rocblas support for gfx target" gfx_target=gfx1152 supported="map[gfx1030:true gfx1100:true ... gfx1150:true gfx1151:true gfx1200:true ...]" level=INFO msg="dropping integrated GPU; to enable, set OLLAMA_IGPU_ENABLE=1" library=Vulkan description="AMD Radeon(TM) 860M Graphics" level=INFO msg="inference compute" id=cpu library=cpu total="63.1 GiB" available="30.3 GiB" level=INFO msg="vram-based default context" total_vram="0 B" default_num_ctx=4096

ROCm, la pila de cálculo de AMD, identifica cada GPU por su arquitectura de instrucciones, y la 860M es gfx1152. Las bibliotecas de ROCm que trae Ollama están compiladas para gfx1150 y gfx1151 (la 890M y el Ryzen AI Max) y no para esta, así que ROCm la descarta. Vulkan, la API gráfica que también ejecuta shaders de cálculo, encuentra la GPU y funciona con ella, y entonces es Ollama quien la descarta a propósito por ser integrada. El arreglo es la variable que nombra el propio registro, OLLAMA_IGPU_ENABLE=1, puesta para el usuario. Tras reiniciar:

TEXT Copy

level=INFO msg="inference compute" library=Vulkan description="AMD Radeon(TM) 860M Graphics" type=iGPU total="47.6 GiB" available="45.3 GiB" level=INFO msg="vram-based default context" total_vram="47.6 GiB" default_num_ctx=262144

La última línea es un efecto secundario que conviene pillar. Ollama calcula su contexto por defecto a partir de la memoria de vídeo que cree tener, y con 47,6 GiB salta de 4.096 tokens a 262.144. La caché KV para un cuarto de millón de tokens se come gigas antes de escribir una sola palabra, así que apu pide 16.384 tokens en cada petición. La detección en sí tarda de 20 a 30 segundos, lo bastante para que la comprobación de arranque de la app de escritorio se rinda una vez y apunte ollama server not ready, continuing anyway; luego se recupera sola.

Los dos modelos bajaron en paralelo por la wifi de casa a 7 o 9 MB/s entre los dos, cerca de una hora para 21 GB y 18 GB. Una de las descargas se quedó en el 2 % sin dar error mientras el archivo en disco ya medía 20,2 GB. Ollama reserva el archivo entero antes de escribir en él, así que su tamaño no dice nada; el progreso real está en los JSON -partial-N que tiene al lado, y al relanzar la descarga siguió donde se había quedado.

Dos motores, una sola copia de los pesos

Después vino LM Studio (winget install ElementLabs.LMStudio, versión 0.4.26), para tener algo contra lo que contrastar Ollama. Los dos se confunden con facilidad, porque por debajo son casi el mismo programa. Los dos están construidos sobre ggml, la biblioteca de tensores de llama.cpp, y los dos leen modelos en GGUF, el formato de archivo de llama.cpp, que guarda los pesos cuantizados y el tokenizador en un solo fichero. Para arquitecturas recientes Ollama tiene su propio motor sobre ggml, pero para este modelo su API dice runner: llamacpp. Con Qwen3.6 35B-A3B, por tanto, los dos motores ejecutan llama.cpp sobre el mismo archivo; lo que cambia es el envoltorio y los valores por defecto.

Ollama guarda cada modelo como blobs direccionados por contenido en ~/.ollama/models/blobs, y el blob más grande de un modelo es el propio GGUF (empieza por los cuatro bytes GGUF). En vez de descargar 40 GB otra vez, le di a LM Studio un hard link a ese blob: una segunda entrada de directorio para los mismos bytes en disco, que no ocupa espacio y garantiza que los dos motores usan pesos idénticos byte a byte. LM Studio lo listó como qwen3.6-35b-a3b, 35B, qwen35moe, 21.72 GB y lo cargó sin convertir nada.

lms import mueve el archivo por defecto.

Lanzado sobre el blob de Ollama, le quitaría el GGUF a Ollama de debajo. lms import --hard-link (-L) añade un segundo nombre; borrar el modelo en un motor lo deja intacto en el otro. Un hard link necesita que los dos almacenes estén en el mismo volumen NTFS y, a diferencia de un enlace simbólico en Windows, no pide permisos de administrador.

La primera vez que se abre, LM Studio ofrece un modelo de inicio, Gemma 4 E4B de Google con 6,33 GB, que me salté, y luego dos ajustes avanzados: el Developer Mode, apagado, que esconde las opciones del motor, de descarga en GPU y del servidor, y un servicio local que arranca al iniciar sesión, encendido. Encendí el primero y apagué el segundo. El motor que se queda residente es Ollama, y dos servidores cargados desde el arranque estarían reteniendo memoria cada uno para nada.

La oferta del primer arranque de LM Studio: Gemma 4 E4B, 7,9B parámetros en total, 6,33 GB de descarga.Los valores de fábrica: Developer Mode apagado, el servicio al iniciar sesión encendido. Los dos se cambiaron.

La primera diferencia que apareció es la que le costó la mañana a Ollama: LM Studio no necesita ningún interruptor para la GPU integrada. Trae versiones de llama.cpp para CPU, CUDA y Vulkan y eligió la de Vulkan por su cuenta. La segunda diferencia es más rara. Preguntado por la memoria de la GPU, lms runtime survey contestó 31,76 GiB, donde Ollama había dicho 47,6 para el mismo chip:

TEXT Copy

AMD Radeon(TM) 860M Graphics (Vulkan, Integrated) 31.76 GiB RAM: 63.14 GiB

31,76 GiB es más o menos la mitad de la RAM más los 512 MB reservados, que coincide con la memoria de GPU compartida que Windows ofrece a una GPU integrada y enseña en el Administrador de tareas. 47,6 GiB son unas tres cuartas partes de la RAM. Los dos motores leen cifras distintas para la misma memoria, y solo un modelo de más de 32 GB diría cuál respeta de verdad el controlador. No se cargó nada tan grande, así que la pregunta sigue abierta; los dos modelos usados aquí caben bajo cualquiera de los dos techos.

Ollama

LM Studio

un servicio de fondo con CLI y una app de escritorio mínima Forma una app de escritorio a la que se le añadieron servidor y CLI (lms)

apagada hasta poner OLLAMA_IGPU_ENABLE=1 GPU integrada encendida, elige sola el runtime de Vulkan

47,6 GiB Memoria de GPU que dice 31,76 GiB

a los 5 minutos Descarga por inactividad a la hora (jitModelTTL)

55 s Carga en frío de este modelo 124 s

11,7 tok/s Escritura, mismos pesos 9,4 tok/s

93 tok/s Lectura, mismos pesos 83 tok/s

MIT Licencia la CLI lms MIT, la app cerrada

In both Formato de archivo: GGUF In both Biblioteca de tensores: ggml

Las licencias están en GitHub: el repositorio de Ollama y la CLI lms de LM Studio son MIT1, mientras que la app de LM Studio no es open source. LM Studio lleva además una protección de carga que rechaza los modelos que calcula que no van a caber, otro motivo por el que su cifra de memoria más baja le importa a quien lo usa.

1ollama/ollama y lmstudio-ai/lms, los dos MIT; la app de escritorio de LM Studio no tiene repositorio público.

El motor26 · oct 21Read noteSe queda Ollama. Con los mismos bytes escribió un 25 % más rápido y leyó un 12 % más rápido, es open source, funciona como un servicio que puedo programar, y su API dice cuánto del modelo está en la GPU. La ventaja real de LM Studio es que la GPU funciona sin tocar nada, y eso a Ollama se lo da un script de instalación con una variable. Dejo LM Studio instalado como segunda opinión: si un número de Ollama me parece raro, el mismo archivo con otro envoltorio es la comprobación más rápida.

La GPU integrada parecía más lenta que la CPU

La primera comparación usó un script pequeño, tools/compare_engines.py: los mismos pesos y los mismos prompts en cada motor, 256 tokens escritos para medir la escritura, un prompt de 2.906 tokens para medir la lectura, temperatura 0, razonamiento apagado y los tiempos que da cada motor, para que la red y el JSON no cuenten. Salió esto:

Motor, dispositivo Escritura (tok/s) Lectura (tok/s)

LM Studio, GPU integrada con Vulkan 7,1 62

Ollama, GPU integrada con Vulkan 7,6 no comparable

Ollama, solo CPU 11,3, 10,8 55, 52

La GPU escribía un tercio más despacio que la CPU con la misma memoria. Estaba trabajando, eso estaba claro (su motor de cálculo rondaba el 48 % de uso y Windows contaba 23,4 GB de memoria de GPU compartida ocupada), solo que despacio. 7 tokens por segundo a 2 GB por token son 14 GB/s, una novena parte del ancho de banda teórico, y yo tenía una hipótesis a mano que encajaba: en Windows, la memoria compartida pasa por la traducción de direcciones de la GPU y podría ser un camino más lento que la porción dedicada, aunque los chips sean los mismos. Hasta había algo que la apoyaba. Las pruebas de la propia AMD dicen que reservar más memoria dedicada añade de un 17 a un 22 % en modelos pequeños1, y una issue de llama.cpp describe una GPU con memoria compartida que va más lenta que la CPU en Windows2. Lo escribí como hallazgo y lo registré en un commit.

1AMD, Accelerating Llama.cpp Performance in Consumer LLM Applications with AMD Ryzen AI 300 Series, 30 de octubre de 2024: alrededor de un 22 % con Llama 3.2 1B en una máquina de 16 GB, hasta un 17 % con Mistral Nemo 12B. 2llama.cpp, issue #10330.

Luego miré cuándo se había tomado cada fila, y la tabla se vino abajo por tres lados.

Las filas de GPU se midieron mientras el segundo modelo seguía descargándose, con la red, el disco y la comprobación de hash ocupados; las de CPU llegaron cuando ya había terminado la descarga.

Todos los prompts empezaban por Run 1., Run 2., el mismo texto en cada ejecución del script, y Ollama tiene una caché de prompts. Una ejecución posterior releyó el prompt de 2.908 tokens a 7.000 o 9.000 tokens por segundo y seguía contando los 2.908 como evaluados.

Una petición con las opciones por defecto reutilizó un modelo que seguía cargado con num_gpu: 0 de la prueba de CPU. Una ejecución etiquetada como GPU estaba al 0 % en la GPU, y solo lo decía /api/ps (size_vram: 0).

Cada trampa tiene su arreglo, y los tres están ya en el script y en apu bench. Cada prompt empieza con un valor aleatorio, así que ningún motor puede reutilizar una caché entre ejecuciones. Antes de cada configuración se descarga el modelo (keep_alive: 0), y después se le pregunta al motor dónde estuvo de verdad; pedir una ubicación no prueba que se haya dado. Durante la medida no se ejecuta nada más, aparte del navegador y el editor que siempre están abiertos. La medida limpia:

Ollama, Qwen3.6 35B-A3B Escritura (tok/s) Lectura (tok/s) Ubicación comprobada

GPU integrada con Vulkan 11,7 (9,5, 11,7, 12,8) 93 (96, 93, 77) 20,6 GB, 100 % GPU

Solo CPU 11,2 (11,6, 11,2, 10,5) 53 (54, 52, 53) 20,9 GB, 0 % GPU

Al escribir es un empate dentro de la dispersión de las ejecuciones, y al leer un prompt largo la GPU es 1,8 veces más rápida, que es lo que predecía el mecanismo. 11,7 tokens por segundo a 2 GB cada uno son unos 23 GB/s de tráfico de pesos, una quinta parte del ancho de banda teórico, en los dos dispositivos, así que lo que frena la generación aquí es común a CPU y GPU y no señala al camino de la memoria compartida. LM Studio en las mismas condiciones, con el mismo archivo enlazado, escribió a 9,4 (7,8, 9,4, 9,7) y leyó a 83 (84, 78, 83)1. Carga con cuatro slots paralelos por defecto, lo que podría explicar parte de la diferencia; no lo aislé.

1El contador de uso de LM Studio marcó todos los tokens generados como razonamiento, aunque el script pedía el razonamiento apagado. La velocidad por token no depende de lo que diga el token, así que la comparación vale, pero su interruptor de razonamiento no hizo efecto por esta API.

Retirado26 · oct 21Read noteLa versión equivocada sigue en el historial del repositorio, el commit a04b954, con un título como si fuera cierta, y el diario la conserva como Hallazgo 3 con una línea que dice que se retiró. La dejé a propósito. La tabla retirada es lo más útil que dio el día para cualquiera que mida una máquina de memoria compartida: cada una de esas trampas parece una propiedad del hardware hasta que miras las horas.

Un modelo denso de 27B lee todos los pesos

Descargué un segundo modelo sabiendo que iba a ser lento. Qwen3.8 27B saca 33,7 en el Artificial Analysis Intelligence Index frente al 18,2 de Qwen3.6 35B-A3B1, casi el doble de puntuación, y es denso, así que cada token lee sus unos 16 GB enteros.

1Artificial Analysis Intelligence Index, modos de razonamiento, según BenchLM, actualizado el 20 de octubre de 2026: Qwen3.8 27B 33,7, Qwen3.6 35B-A3B 18,2, Claude Opus 5.5 57,6, GPT-5.6 Sol 58,9.

Ollama, Qwen3.8 27B Escritura (tok/s) Lectura (tok/s) Ubicación comprobada

GPU integrada con Vulkan 2,6 (2,3, 2,8) 13,8 (14, 14) 16,3 GB, 100 % GPU

Solo CPU 2,2 (2,1, 2,3) 9,1 (9, 9) 17,0 GB, 0 % GPU

Una respuesta de 256 tokens tarda unos 100 segundos, y un prompt de 2.900 tokens tarda tres minutos y medio en leerse antes de que salga la primera palabra. El tráfico de pesos es mayor que el del MoE, unos 42 GB/s, así que la memoria rinde mejor con una lectura grande y secuencial por matriz que con muchas lecturas pequeñas de expertos repartidas por 35.000 millones de parámetros (una lectura plausible de los dos números, que no comprobé). Aun así el modelo denso escribe cuatro veces y media más despacio, porque cada token arrastra ocho veces más datos.

Lo que cabe en 64 GB frente a la frontera, en el Artificial Analysis Intelligence Index (modos de razonamiento) a 20 de octubre de 2026. Las barras azules funcionan en este portátil. El 23 de GPT-5 high (agosto de 2025) es una estimación de Artificial Analysis, y las versiones del índice no son comparables entre sí.

El gráfico pone al modelo de diario en su sitio, por debajo del GPT-5 de agosto de 2025 y a un tercio de la frontera actual. Alucina cuando no sabe, y sus respuestas hay que revisarlas. Los benchmarks de la propia Alibaba lo ponen por delante de su predecesor y del MoE de Gemma 4 en programación con agentes, lo que encaja con el uso que tiene aquí, el de alguien que hace borradores y cuyo trabajo se revisa.

Las puntuaciones publicadas por Alibaba para Qwen3.6-35B-A3B (las barras más oscuras) frente a dos modelos MoE y dos densos de tamaño parecido: 73,4 en SWE-bench Verified, 86,0 en GPQA Diamond. Figura de Qwen (Alibaba), de la ficha del modelo en Hugging Face.

Dos modelos26 · oct 21Read noteAsí que el MoE va por defecto y el denso espera a las preguntas cortas y difíciles. A 2,6 tok/s un párrafo de respuesta es un minuto, que está bien para una pregunta enrevesada y no sirve para un documento. Quedarme solo con el de 27B habría sido tener un modelo más listo que evito usar; quedarme solo con el MoE, no tener a quién recurrir cuando se le queda grande algo. El disco es barato, y en memoria solo está uno.

Las dos tablas dan las cifras en las que se apoya el resto del texto:

11,7 tok/sQwen3.6 35B-A3B escribiendo en la Radeon 860M, empatado con los 11,2 de la CPUmedida limpia, 3 ejecuciones, mediana 1,8×cuánto más rápido lee la GPU integrada un prompt largo que la CPU, 93 frente a 53 tok/smisma medida 2,6 tok/sel denso Qwen3.8 27B escribiendo en la misma GPU2 ejecuciones, mediana 20,6 GBQwen3.6 35B-A3B cargado, 100 % en la GPU, contexto de 16.384/api/ps tras la medida 10,9 a 12,7 GBRAM libre con ese modelo cargado y las apps de siempre abiertasapu stats, dos lecturas

Gemma no26 · oct 21Read noteLa primera sugerencia de LM Studio, Gemma 4 E4B, es un buen modelo para un portátil de 16 GB, y el instalador del repo se lo da a las máquinas de 14 a 27 GB. Con 64 GB dejaría casi toda la memoria parada para ganar tiempo en respuestas que ya son lo bastante rápidas. Lo usaría para trabajo masivo y trivial (miles de clasificaciones de una línea), donde la velocidad por elemento es lo único que cuenta.

Por qué no se reserva nada para la GPU

Los 512 MB reservados se pueden subir. AMD llama al ajuste Variable Graphics Memory, y está en AMD Software, en Rendimiento y Ajuste; convierte la cantidad de RAM que se elija en memoria de vídeo dedicada. Lo que no puede es cambiar con Windows en marcha. La reserva la fija el firmware al arrancar, antes de que exista el sistema operativo, y Windows ve como RAM lo que queda. Reservar memoria supone un reinicio, y devolverla, otro.

El hallazgo retirado había sido el motivo para probarlo, y la medida limpia se llevó casi todo el motivo. CPU y GPU escriben a menos de un 5 % la una de la otra, las dos a una quinta parte del ancho de banda teórico, y la CPU no pasa en absoluto por la traducción de direcciones de la GPU. Si el cuello de botella fuera la memoria compartida, la CPU se habría escapado. El 17 a 22 % de AMD se midió con modelos de 1B y 12B, y aquí el coste sería permanente: reservar 24 GB para la GPU le quita 24 GB a todos los demás programas cuando no hay ningún modelo cargado, que en esta máquina es casi todo el día.

Sin reserva26 · oct 21Read noteEstuve a punto de hacerlo, mientras la tabla retirada todavía parecía cierta: AMD Software, 24 GB, reinicio, volver a medir, reinicio de vuelta si no cambiaba nada. Cuando llegó la medida limpia, dos reinicios por unos pocos puntos, en el mejor caso, sobre un cuello de botella al que los números no apuntaban, no compensaban. El repo dice claramente que esto está sin probar. Si alguien con el mismo chip lo prueba, apu bench escribe un archivo que me gustaría ver.

Claude Code le pasa trabajo

El comando apu habla con la API nativa de Ollama (/api/chat, /api/ps) y escribe los tiempos en la salida de error y la respuesta en la salida estándar, así que apu ask ... > answer.md queda limpio. Cada petición se apunta en ~/.apu/log.jsonl, y apu stats resume ese registro. El mismo código funciona como servidor MCP por la entrada y la salida estándar, registrado una vez para todos los proyectos:

POWERSHELL Copy

claude mcp add --scope user apu -- "$(Get-Command apu | % Source)" mcp

La ruta absoluta importa, porque una sesión de Claude Code abierta antes de que apu llegara al PATH no encontraría el nombre a secas. Claude Code tiene entonces dos herramientas: local_llm_status, y local_llm_ask, que recibe un prompt y una lista de rutas de archivo. El servidor lee los archivos él mismo, así que su contenido llega al modelo local sin pasar por el contexto de Claude. La descripción de la herramienta es lo que le dice a Claude cuándo usarla: sin conexión, gratis y privado, más flojo que Claude, bueno para resumir, clasificar, extraer, primeros borradores y todo lo que no deba salir de la máquina, y que compruebe la respuesta antes de fiarse de ella.

API nativa26 · oct 21Read noteOllama también habla la API compatible con OpenAI, y usarla habría hecho que apu funcionara con cualquier motor. Elegí la nativa porque da lo que yo quería medir: tiempo de carga, de prompt y de generación desde dentro del motor, y /api/ps diciendo cuántos bytes están en la GPU. La tercera trampa de arriba solo se ve con ese último campo.

La primera tarea delegada salió de una sesión nueva sin interfaz: que el modelo local resumiera en tres viñetas, en español, las notas del artículo del repositorio, y devolver su respuesta sin cambios con una valoración de una línea. El modelo cargó en 29 segundos y escribió a 14,7 tokens por segundo. La respuesta, recortada, y la revisión de Claude, tal cual:

Modelo localEstablece requisitos de documentación rigurosa (notas de contexto, mediciones verificadas) y aclara explícitamente la relación entre Ollama y LM Studio [...] Detalla las mediciones técnicas en la máquina de referencia (860M), contrastando el uso de memoria GPU (47,6 GiB en Ollama frente a 31,76 GiB en LM Studio), tiempos de descarga y rendimiento de generación bajo condiciones idénticas. Justifica decisiones de arquitectura como la selección del repositorio apu-llam [...] y el beneficio económico de contar con 64 GB de RAM en laptops para ejecutar grandes modelos de lenguaje.

Estadísticas228 tok at 14.7 tok/s · prompt 870 tok at 137 tok/s · load 29.2s · total 51.0s

ClaudeLa estructura es buena y cubre las tres partes del archivo, pero tiene errores que lo hacen poco fiable sin revisarlo. Dice tiempos de descarga donde el archivo habla del tiempo hasta descargar el modelo de memoria por inactividad (5 min frente a 1 h). Presenta la velocidad de generación como medida, cuando el archivo la marca como pending. Escribe apu-llam en lugar de apu-llm. Y da como justificada la compra de 64 GB, cuando el archivo solo la plantea como pregunta pendiente.

Cuatro errores de hecho en un resumen con la forma bien puesta, y el modelo más fuerte cazó los cuatro. Ese es el reparto de trabajo que pide la descripción de la herramienta, y la prueba demuestra que funciona y que hace falta. La transcripción completa está en el repositorio, en docs/evidence/.

Por qué MCP26 · oct 21Read noteUna línea en CLAUDE.md diciendo usa apu ask para el trabajo masivo habría funcionado en este repo y en ningún otro, y Claude habría tenido que pegar el contenido de los archivos en un comando de shell. Como herramienta MCP aparece en todos los proyectos con su propia descripción de cuándo usarla, recibe rutas en vez de contenidos y tiene su propia entrada de permisos, así que puedo permitirla sin permitir Bash.

Lo que compraron los 64 GB

El portátil costó unos 4.000 euros, y los 64 GB fueron buena parte de por qué elegí esa configuración. Si merecieron la pena, solo para este uso, tiene una respuesta más estrecha que un sí o un no.

Lo que compra aquí la RAM es sitio. Con la sesión de siempre abierta (Chrome con unos 49 procesos, Cursor, Claude Code, Anki), Windows ya usaba 32 GB antes de cargar ningún modelo. Con Qwen3.6 35B-A3B cargado encima, quedan libres de 10,9 a 12,7 GB. Una configuración de 32 GB de la misma máquina no podría tener este modelo junto a esa sesión; tendría que cerrar cosas o bajar a un modelo más pequeño, y el instalador del repo les da a las máquinas de 28 a 47 GB el Gemma 4 26B-A4B, que saca 16,7 en el mismo índice. La cifra de uso favorece un poco el argumento, porque Windows y Chrome cogen más memoria cuando hay más.

La velocidad es otra cosa, y la comparación justa para ella es una GPU de sobremesa. Una RTX 5090 tiene 32 GB de memoria propia con catorce veces el ancho de banda del portátil; salió a 1.999 dólares en enero de 20251, y en septiembre de 2026 la más barata anunciada en Alemania pasaba de 5.000 euros2, más que todo este portátil, sin contar el ordenador que la rodea. Cargaría el modelo de 20,6 GB y lo movería mucho más rápido. No cargaría un modelo de más de 32 GB, que este portátil al menos puede intentar. La RTX 5080, a 999 dólares y con 16 GB, no puede tener este modelo entero y lo repartiría con la CPU.

1NVIDIA, NVIDIA Blackwell GeForce RTX 50 Series Opens New World of AI Computer Graphics, nota de prensa, 6 de enero de 2025: RTX 5090 a 1.999 dólares, RTX 5080 a 999. 2Hagedoorn, GeForce RTX 5090 Street Prices in EU Now Exceed €5,000, Guru3D, 14 de septiembre de 2026, con precios de Geizhals y la escasez de GDDR7 y DRAM como causa.

Alquilar sale todavía más barato a quien lo use de vez en cuando. Un pod de RunPod con una RTX 5090 costaba 0,69 dólares la hora en la nube comunitaria y 1,19 en la segura, y una A100 de 80 GB, 1,791, que es lo que pagué ese mismo día al alquilar una A100 para hacer fine-tuning de Stable Diffusion. A 1,19, cuatro mil dólares dan para unas 3.400 horas. Eso sí, una GPU en la nube no deja los datos en la máquina y cuesta montarla cada vez, que son justo las dos cosas para las que sirve un modelo que contesta en segundo plano a Claude Code. En calidad por euro, la API de un modelo de frontera gana a los dos, según el índice de arriba, siempre que los datos puedan salir.

1RunPod, Pricing, página actualizada el 8 de octubre de 2026.

Así que la cuenta honesta es estrecha, y es economía de la inferencia a la escala más pequeña. Los 4.000 euros compraron un portátil que iba a necesitar igualmente; el coste que hay que poner frente a este uso es la diferencia de precio entre las configuraciones de 32 y 64 GB en el momento de la compra, y esa es la cifra que hay que buscar. Por esa diferencia, la RAM compra un ayudante para borradores privado y siempre disponible, algo por debajo del GPT-5 de agosto de 2025, que escribe más o menos a la velocidad a la que lee una persona. Quien quiera un modelo rápido o uno de frontera estará mejor servido con una tarjeta de sobremesa o con una API.

Si se va a abaratar

La memoria y los modelos se mueven en direcciones opuestas, y en una máquina como esta cambian números distintos.

La memoria se ha encarecido mucho. Los fabricantes pasaron obleas a la HBM, la DRAM apilada que alimenta los aceleradores de IA, y a la DRAM de servidor, y al resto del mercado le faltó. Counterpoint Research contó subidas de alrededor del 50 % a principios de 2025 y esperaba que los precios se duplicaran más o menos a mediados de 20261. TrendForce midió luego que los precios de contrato de la DRAM convencional subieron de un 93 a un 98 % solo en el primer trimestre de 2026, y esperaba otro 58 a 63 % en el segundo2. Su previsión para la LPDDR4X y la LPDDR5X de móviles y portátiles finos, la memoria de este portátil, era una subida de en torno al 90 % en ese primer trimestre, la mayor de su historia3. Las subidas se están frenando: de un 10 a un 15 % previsto para el cuarto trimestre4.

1Robinson, Commodity memory prices set to double as fabs pivot to AI market, The Register, 19 de noviembre de 2025, citando a Counterpoint Research y TrendForce. 2TrendForce, Rapid Contract Price Surge Drives 1Q26 DRAM Industry Up 81% QoQ, 1 de junio de 2026. 3TrendForce, Memory Price Outlook for 1Q26 Sharply Upgraded, 2 de febrero de 2026, que también preveía la DRAM de PC por encima del 100 %. 4TechNews, AI 伺服器新增需求支撐 4Q26 記憶體合約價漲勢,消費端壓力未減, 30 de septiembre de 2026, con la previsión de TrendForce para la DRAM convencional; para la DRAM móvil no da porcentaje, solo que subirá menos que en el tercer trimestre.

Cuándo se da la vuelta es donde las fuentes no coinciden. TrendForce espera que la DRAM de servidor siga subiendo cada trimestre hasta la segunda mitad de 20271. El Bloomsbury Intelligence and Security Institute ve los precios altos durante 2027 y 2028, normalizándose solo cuando las fábricas nuevas lleguen a producir en volumen, y no descarta un exceso de oferta en 2028 o 2029 si la demanda de IA se enfría2. Nadie de los que encontré espera memoria barata antes de 2028, y la fecha de después depende de una curva de demanda que nadie ve.

1TrendForce, Long-Term Agreements Cap Price Increases; Server DRAM Contract Prices Expected to Rise 13-18% QoQ in 3Q26, 9 de julio de 2026. 2Mellor, Memory semiconductor supercycle set to run through 2028, Blocks and Files, 21 de enero de 2026, citando a BISI, Micron e IDC.

Para este portátil la pregunta no tiene recorrido en un sentido: su LPDDR5X está soldada a la placa, así que los 64 GB son los que va a tener toda su vida, al precio que llegue la memoria. Existe un estándar de módulos LPDDR5X sustituibles para portátiles (CAMM2, de JEDEC, publicado en diciembre de 20231), pero esta máquina no lo usa.

1JEDEC, JEDEC Publishes New CAMM2 Memory Module Standard, nota de prensa del 5 de diciembre de 2023 (JESD318), que cubre módulos DDR5 y LPDDR5/5X para portátiles.

Los modelos van en la otra dirección, y solo mueven uno de los dos números. El mixture of experts se ha extendido a los modelos abiertos que la gente usa de verdad: Qwen3.6 35B-A3B lee 3.000 millones de parámetros por token, y gpt-oss-120b de OpenAI tiene 117.000 millones de parámetros con 5.100 millones activos, publicado ya cuantizado a 4 bits (MXFP4) para que quepa en una sola GPU de 80 GB, mientras que gpt-oss-20b cabe en 16 GB1. Eso recorta los bytes leídos por token, que es justo lo que necesita una máquina con poco ancho de banda como esta, y es lo que hace que aquí se pueda usar un modelo de 35B. Los bytes que hay que tener cargados siguen donde estaban, y un modelo más disperso suele ser más grande en total, así que la ganancia se nota como velocidad en las máquinas que ya tienen la capacidad. Y la capacidad es la parte cuyo precio se ha duplicado. Mi apuesta, y no es más que eso, es que dentro de dos años una máquina de 64 GB moverá un modelo mejor que este a la misma velocidad, y que la máquina en sí costará más que lo que costó esta.

1OpenAI, gpt-oss-120b model card, Hugging Face, agosto de 2025: 117B parámetros en total y 5,1B activos, 21B y 3,6B en gpt-oss-20b, MXFP4 en los pesos MoE.

Instalarlo

Todo lo de arriba que hubo que hacer a mano cabe en una línea de PowerShell:

POWERSHELL Copy

irm https://raw.githubusercontent.com/yago-mendoza/apu-llm/main/install.ps1 | iex

El script instala Python con winget si falta (el python de la Microsoft Store no cuenta, porque solo abre la Store), instala apu con pip para el usuario, añade al PATH la carpeta Scripts de usuario de pip, cosa que pip no hace y que la primera vez dejó apu inalcanzable, y lanza apu setup. Ese paso pregunta antes de cada cosa: Ollama, el interruptor OLLAMA_IGPU_ENABLE, el modelo que corresponde a la RAM de la máquina y el registro en Claude Code. Después, abre Ollama desde el menú Inicio; lanzada desde un script, su app de escritorio no levantó el servidor.

TEXT Copy

apu ask "question" ask the local model apu ask "fix this" -f app.py with files as context (-f repeats) cat log.txt | apu ask "why?" or piped input apu ask --think "hard one" let it reason first (slower, better) apu ping alive? which model, where loaded, how fast right now apu stats loaded model, free RAM, median speed of recent requests apu bench repeatable benchmark, saved with the machine's specs apu models / apu use <model> downloaded models / change the default apu doctor checks every piece, prints the fix for each failure

En la máquina de referencia apu doctor pasó sus ocho comprobaciones, desde que el interruptor esté puesto hasta que el modelo esté al 100 % en la GPU y el servidor MCP registrado. La primera llamada tras cinco minutos sin uso paga que Ollama haya descargado el modelo: 33,8 segundos para volver a leer 20,6 GB del SSD, y la línea de velocidad lo dice.

Una llamada en caliente: apu ping contesta en 1,5 s, y apu stats enseña 12,4 GB libres y una mediana de 11,2 tok/s en las cinco últimas peticiones.

Siete minutos después Ollama había descargado el modelo tras sus cinco minutos de inactividad: el mismo ping tardó 36,4 s, 33,8 de ellos cargando, y la RAM libre era de 10,9 GB.

Quien lo ejecute en otra máquina recibe de apu bench un JSON con las características de esa máquina, en ~/.apu/bench/. Un pull request que lo añada a bench/results/ añade una fila a la tabla del repositorio, que de momento solo tiene este portátil.

Para qué sirve

Tras un día con él, el sitio que se ha ganado es aquel para el que se hizo la herramienta MCP: Claude Code le delega trabajo de texto en masa (resumir, clasificar, extraer, reformatear muchos archivos) y revisa lo que vuelve. Eso lo hace bien, sin conexión y sin coste por petición, y para eso se queda instalado.