Ir al contenido

Optimizando mi configuración de LLMs locales para tareas por lotes

Marc Alier
Autor
Marc Alier
Página personal y Cajón Desastre.

En una ejecución reciente tuve LLMs locales trabajando más de 28 horas, masticando cuatrocientos treinta y siete ficheros markdown. El modelo era qwen3.5:122b, servido vía Ollama en dos Mac Studio sobre una red local privada. La tarea, nada glamurosa: leer un fichero, devolver un JSON con un resumen de dos frases, las personas nombradas, las etiquetas de temas, las ideas clave que el fichero argumenta. Repetir. Agregar entre ficheros. Escribir los andamios por entrada.

Si intento hacerlo con claude code me quedo sin tokens en un suspiro, y aun pagando proveedores chinos de nube baratos acabaré no haciendo este tipo de optimizaciones del repositorio de contenidos porque se puede encarecer pronto.

Desde entonces he empezado a sustituir aquel pipeline por DS4 ejecutando DeepSeek V4 Flash Q4 sobre el mismo hardware. La latencia por llamada ha caído de ciento cincuenta segundos a unos doce. Misma tarea. Misma forma de prompt. Motor distinto, el doble de tamaño en RAM. Una mejora rotunda en rendimiento, e incluso noto que la máquina Studio funciona más fresca.

Este post es la nota de optimización. Lo que quiero de la flota local es un LLM de calidad con coste variable que se acerque a cero, para tareas por lotes — indexación de wikis, auditoría de referencias, limpieza de transcripciones, clasificación en masa. El tipo de trabajo donde el cuello de botella es la latencia y la fiabilidad, no la inteligencia. Dos motores, dos posturas, una compensación que vale la pena nombrar.

El caso de uso
#

Un índice wiki sobre un repositorio personal de escritura e investigación. Unos cuatrocientos ficheros markdown: capítulos, borradores, material de fuentes, notas de memoria — ¡incluso mi tesis doctoral entera está ahí dentro! Para cada fichero quiero un pequeño artefacto estructurado: un resumen que el índice pueda mostrar, entidades nombradas para poblar las facetas de personas/temas/ideas-clave, referencias cruzadas entre ellas.

Esto es extracción masiva. Prompt de sistema reutilizable; contenido de usuario variable; salida JSON estructurada. El modelo no necesita ser listo — necesita ser fiable, predecible y estar lo bastante disponible como para tirar adelante cientos de llamadas sin romperse.

Llamar a un LLM en este registro es un deporte distinto a conversar con uno. La salida es la entrada del siguiente paso del pipeline. Si el veinte por ciento de las llamadas vuelven vacías, es el veinte por ciento de la wiki que falta. Si duplicas la longitud de contexto y la calidad se degrada silenciosamente, el corpus que hay que trocear es tu fichero más grande. La superficie de ingeniería que importa es la latencia, la previsibilidad y el fallo elegante.

El patrón wiki de Karpathy
#

A principios de abril de 2026 Andrej Karpathy publicó un tweet que se hizo viral: “a large fraction of my recent token throughput is going less into manipulating code, and more into manipulating [knowledge].” Esbozaba un sistema donde las fuentes en bruto — artículos, papers, repositorios, datasets, incluso imágenes — caen en un directorio raw/, y un agente LLM las compila incrementalmente en una wiki estructurada: ficheros markdown enlazados con resúmenes, backlinks, páginas de conceptos. Dos días después lo completó con un idea file — un gist de GitHub que describe el patrón conceptualmente, sin código adjunto, bajo la teoría de que en la era de los agentes la idea es más útil de compartir que la implementación.

Aquel tweet describe el proyecto que estoy construyendo casi palabra por palabra. El repositorio que estoy indexando son años de escritura — capítulos, borradores, transcripciones de fuentes, notas de memoria, todo el lote. El bootstrap que ejecuté es el paso de compilación incremental que Karpathy nombra. Las operaciones que esboza río abajo — ingesta, consulta, lint — son lo que viene a continuación para mí. No inventó el patrón, pero lo hizo legible: lo nombró, le dio forma, lo hizo público en el momento en que el utillaje sobre hardware local lo había alcanzado. Este verano estará en todas partes.

Versatilidad frente a especialización
#

Dos posturas se sientan en los extremos del espectro de los LLM locales.

Ollama es el extremo versátil. Sirve cualquier modelo de su biblioteca — Qwen, Llama, Mistral, Gemma, Phi, lo que sea que puedas pillar como GGUF. Una instalación, GUI y CLI, una API HTTP, y puedes cambiar de modelo por tarea. Si cambias de modelo cada semana, Ollama es la herramienta correcta: la fricción de probar uno nuevo es un solo comando ollama pull.

DS4 es el extremo especializado, el recién llegado. Sirve un modelo — DeepSeek V4 Flash cuantizado en q2 o q4 — y está dedicado a hacer que ese único modelo funcione tan bien como un Mac Studio permita. Caché KV residente en disco, kernels conscientes de MoE, decodificación especulativa MTP, una API HTTP compatible con OpenAI por encima. No puede servir ningún otro modelo. Eso no es un bug; es el diseño y la intención.

La compensación es directa. Si te comprometes con un modelo y lo usas intensamente — mismo prefijo de prompt, cientos de llamadas al día, coste de prefill amortizado sobre miles de inferencias — la especialización se paga sola rápidamente. Si saltas entre modelos, el motor especializado es coste hundido. La respuesta correcta depende de cuánto lo uses de verdad.

Ollama + qwen3.5:122b — el titular versátil
#

qwen3.5:122b es un Mixture-of-Experts potente, 125 mil millones de parámetros totales, capacidad de sobra. Servido vía Ollama es una instalación de una línea y una presencia permanente en la LAN. Ha sido el “Tier 1” de mi taller durante meses: todo lo que es mecánico y voluminoso y por lo que no quiero pagar una API va ahí.

Para el bootstrap de la wiki, dos observaciones merecen quedar registradas.

El precipicio de contexto. Capé cada llamada a 12k tokens de entrada con un techo duro de 16k vía --num-ctx 16000. Pasado el 16k, la calidad se degrada de manera visible — colas truncadas, entidades nombradas que se pierden, cualificadores numéricos que caen. El capítulo de 30k, la transcripción de 70k, el fichero de cosmovisión de 50k, todos tuvieron que trocearse, resumirse por trozo y reagregar. Cada trozo es otra llamada de Ollama.

El modo de fallo de salida vacía. A lo largo de la ejecución, entre el dieciocho y el veinte por ciento de las llamadas devolvía len=0 — un completado vacío. Ni JSON malformado, ni contenido rechazado, simplemente nada. A través de ficheros de todos los tamaños; no predicho por tamaño, tipo, ni contenido. Reintentar la misma llamada suele producir el mismo resultado. Mi mitigación fue una pasada de reintentos con gpt-5-mini vía OpenAI — unos veinte céntimos por cada cien ficheros. Barato, pero no gratis, y no es la cuestión.

DS4 + DeepSeek V4 Flash — la pila especializada
#

DS4 es un motor de inferencia alpha construido por antirez, dedicado a DeepSeek V4 Flash — un modelo MoE de 284B totales / 13B activos. La especificación del modelo afirma hasta un millón de tokens de contexto; yo ejecuto el servidor con --ctx 200000 y he probado ficheros hasta 70k tokens. Expone una API HTTP compatible con OpenAI en el puerto 8000 y mantiene una caché KV SHA1 en disco que persiste entre reinicios del servidor.

Tres de esas propiedades importan para la extracción por lotes:

  1. La caché KV reutiliza prefijos de prompt. Cuando el prompt de sistema es idéntico en cada llamada — y en un pipeline de extracción estructurada siempre lo es — el coste de prefill se paga una vez, luego queda en caché en disco. De la segunda llamada en adelante el coste por llamada baja dramáticamente. A lo largo de una ejecución larga eso se compone en el ahorro más grande.

  2. 200k de contexto (el modelo reclama más, yo solo he probado hasta aquí). Se acabó trocear los ficheros de 70k. Todo entero entra, todo entero sale resumido. Menos lógica de agregación, menos riesgo de perder una sección.

  3. Notablemente mejor en salida JSON estructurada en mis primeras pruebas. Cero fallos de salida vacía en las primeras ejecuciones.

Rendimiento de hardware en el M3 Ultra: ~38 tokens por segundo de prefill, 32 de generación — consistente con los números documentados por antirez. La latencia por llamada en el pipeline de enriquecimiento en vivo es de 6,3 a 25,9 s, media 11,6 s para una llamada de 2k de entrada y 500 tokens de salida (últimas 200 llamadas de una ejecución de 1.241). La misma forma de llamada con qwen3.5:122b corría a 90–290 s, media 150–200 s. Un orden de magnitud en el tiempo de reloj que más importaba.

Latencia media por llamada, en segundosGráfico de barras verticales. Ollama + Qwen3.5:122b: ~175s de media. DS4 + DeepSeek V4 Flash: 11,6s de media. Medido en Mac Studio M3 Ultra con la misma forma de llamada (2k de entrada, 500 tokens de salida).

Latencia media por llamadasegundos (más bajo es mejor)

050100150200~175sOllama +Qwen3.5:122b11,6sDS4 +DeepSeek V4 Flash Q4

Mac Studio M3 Ultra · llamada de 2k de entrada, 500 tokens de salida · diferencia ≈15×

La imagen de fiabilidad es más nítida que la de latencia, y la que decide si el pipeline es utilizable en absoluto. Cero fallos silenciosos en 1.241 llamadas, frente a uno de cada cinco con Qwen. El prompt de sistema le dice al modelo “si el contexto es demasiado fino, muestra INSUFFICIENT_CONTEXT y nada más” — DeepSeek V4 Flash obedece el 15,6 % de las veces. El andamio se mantiene en su sitio; nada se inventa. Qwen, cuando fallaba, fallaba en silencio.

MétricaDS4 + DeepSeek V4 FlashOllama + Qwen3.5:122b
Latencia por llamada, media11,6 s150–200 s
Latencia por llamada, rango6,3 – 25,9 s~90 – 290 s
Fallos silenciosos de salida vacía0 / 1.241~18–20 %
Rechazos honestos (andamio mantenido)194 / 1.241 (15,6 %)n/a
Presupuesto de contexto que aguanta calidad200k tokens (probados)~16k efectivos
Reutilización de caché entre llamadasSHA1 en disco, persistenteninguna

Una observación poco científica que merece quedar registrada: el Mac Studio funciona más fresco con DS4 a casi máxima GPU que con Ollama+Qwen3.5:122b a carga comparable. Sin benchmark, solo la temperatura de la carcasa.

No atado a DS4. El truco de la caché KV en disco no es propietario. llama.cpp puede mantener caché de prefijos en memoria hoy mismo y tiene caché persistente en disco en el roadmap; Ollama va por encima y lo heredará. El patrón — motor especializado, reutilización de prefijo de prompt — es portable, y la optimización se extenderá a cualquier modelo que estés sirviendo en cada momento.

Generación en catalán
#

No estoy comparando la calidad de generación de estos dos motores en este post. Esa es una pregunta distinta, y en textos lo bastante largos y de peso no confiaría en ninguno de los dos para que me escriba el trabajo. Para el catalán en particular, mi norma vigente es que cualquier cosa generada por un modelo local por debajo del umbral aproximado de ~250B parámetros efectivos pierde el idioma — el ritmo, el vocabulario que no se traduce. Qwen3.5:122b no pasa la prueba. DeepSeek V4 Flash, con trece mil millones de parámetros activos en inferencia, queda en la misma clase efectiva de tamaño y espero que falle la misma prueba hasta que una tanda real de traducción me diga lo contrario.

La traducción con catalán como lengua objetivo, en mi taller, va a Claude o a un modelo frontera de OpenAI. La flota local cubre solo el granel ES/EN. El ahorro de coste vive en el lado mecánico en granel; la voz y el idioma no son para ahorrar.

Desmonetización, en el sentido de Diamandis
#

En Bold (2015), Peter Diamandis y Steven Kotler describen seis efectos que siguen una vez una tecnología se digitaliza: se vuelve engañosa, disruptiva, desmonetizada, desmaterializada, democratizada. La desmonetización es la que importa aquí. Hace un año, indexar cuatrocientos ficheros markdown personales con un LLM no era económicamente obvio — a precios de API frontera la factura habría sido real, los límites de tasa la habrían estirado a lo largo de semanas. Hoy, sobre hardware que ya poseo, el mismo trabajo es una sola ejecución por lotes a cero coste variable. La llamada marginal es gratis.

Cuando el coste marginal se acerca a cero, los casos de uso que emergen son los que no compensaban la factura antes. La indexación wiki de un corpus personal es uno. Limpieza de transcripciones a escala, borradores multilingües para cosas que vas a reescribir igualmente, búsqueda semántica sobre cientos de papers, auditoría de referencias, extracción de ontologías — cada uno era “interesante pero no lo bastante interesante” a precios de API frontera, y cada uno es un proyecto secundario ahora.

Esa es la optimización que importa. No “Ollama frente a DS4” — esa decisión es pequeña, y la respuesta cambia a medida que llama.cpp se pone al día. La optimización es encontrar los flujos de trabajo que solo tienen sentido una vez que el coste por llamada ha desaparecido.

Referencia técnica rápida
#

Si quieres probar el camino DS4 en una máquina Apple Silicon con suficiente memoria (256–512 GB para el build Q4, 96–192 GB para el Q2):

# 1. Clona + compila (~30 segundos)
mkdir -p ~/Code && cd ~/Code
git clone https://github.com/antirez/ds4.git
cd ds4 && make

# 2. Descarga el modelo (Q4: 153 GB, Q2: 81 GB) — GGUFs publicados por antirez
./download_model.sh q4     # o `q2` para el build más pequeño

# 3. Arranca el servidor
mkdir -p ~/.ds4-kv
./ds4-server \
  --ctx 200000 \
  --kv-disk-dir ~/.ds4-kv \
  --kv-disk-space-mb 32768

# 4. Llámalo como cualquier endpoint de OpenAI
curl -s http://192.168.1.35:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model": "deepseek-v4-flash",
       "messages": [{"role":"user","content":"Hola"}]}'

Por defecto el servidor debería escuchar en 0.0.0.0:8000, aunque la versión que compilé escuchaba en 127.0.0.1:8000 y hubo que reconfigurarla explícitamente para alcanzarla desde la LAN. El --kv-disk-dir es donde vive la caché KV SHA1 — mantenedlo en NVMe interno, no en almacenamiento externo. La primera llamada a un servidor en frío tarda diez a sesenta segundos en cargar los pesos; las siguientes llamadas los reutilizan.

Relacionados

La IA dice que has hecho los deberes con IA.

·4 mins
ChatGPT me resume sobre el artículo en The Guardian: https://www.theguardian.com/commentisfree/2024/feb/13/software-student-cheated-combat-ai Robert Topinka, profesor en la Birkbeck, University of London, explora el dilema que enfrentan los profesores con el uso de IA por parte de los estudiantes en la redacción de ensayos. Tras detectar un ensayo marcado como “100% generado por IA”, Topinka se encuentra en una situación difícil cuando un estudiante excepcionalmente brillante impugna esta acusación. El caso subraya los desafíos de los detectores de IA, como Turnitin, que pueden confundir el uso legítimo de apoyo tecnológico por parte de los estudiantes con trampa. Topinka argumenta la necesidad de adaptar la evaluación académica a la era de la IA, proponiendo alternativas como presentaciones y podcasts para demostrar el pensamiento crítico y original de los estudiantes, evitando acusaciones injustas y promoviendo la igualdad de oportunidades educativas.

La IA dice que los deberes los ha hecho la IA

·4 mins
ChatGPT me resume sobre el artículo en The Guardian: https://www.theguardian.com/commentisfree/2024/feb/13/software-student-cheated-combat-ai Robert Topinka, profesor en Birkbeck, University of London, explora el dilema al que se enfrentan los profesores con el uso de IA por parte de los estudiantes en la redacción de ensayos. Tras detectar un ensayo marcado como “100% generado por IA”, Topinka se encuentra en una situación difícil cuando un estudiante excepcionalmente brillante impugna esa acusación. El caso subraya los desafíos de los detectores de IA, como Turnitin, que pueden confundir el uso legítimo de apoyo tecnológico por parte de los estudiantes con hacer trampa. Topinka argumenta la necesidad de adaptar la evaluación académica a la era de la IA, proponiendo alternativas como presentaciones y pódcast para demostrar el pensamiento crítico y original de los estudiantes, evitando acusaciones injustas y promoviendo la igualdad de oportunidades educativas.