Probando una IA local en casa: el que acierta y el que miente con buena letra

Probando una IA local en casa: el que acierta y el que miente con buena letra
ContenidoContents

Esta semana, veinticinco empresas tecnológicas —Nvidia, Microsoft, Meta e IBM entre ellas— firmaron un documento pidiendo que no se pongan restricciones a los modelos de IA de pesos abiertos. Leyéndolo me entró el gusanillo: una cosa es opinar sobre modelos abiertos y otra es haber ejecutado uno.

Y además tenía una cuenta pendiente. Hace poco descarté montar un generador de preguntas de examen para Moodle porque cada llamada a la API me costaba dinero. Pocos céntimos, pero por uso y pagando yo. Así que la pregunta era obvia: ¿podría hacérmelo gratis mi propio servidor?

Lo he probado. Y por el camino me he equivocado dos veces, que suele ser la parte interesante.

El escenario: un servidor que ya está ocupado

Nada de laboratorio limpio. Un Mac mini M4 con 16 GB de RAM que ya sostiene:

  • esta web y el blog
  • un Moodle (aula.sergiocomeron.com)
  • un Jitsi en Docker
  • el stack de monitorización (Prometheus, Grafana, Loki, Jaeger)
  • PostgreSQL

Con unos 8 GB de RAM libres y justo de disco. Eso descarta de entrada los modelos grandes: el invitado tiene que caber sin echar a nadie.

La instalación (aburrida, que es lo mejor que se puede decir de algo en producción)

1brew install ollama

47 MB. Y una decisión pequeña pero deliberada: no lo dejé como servicio permanente. En una máquina de producción, lo que arranca solo al encender es una decisión, no un descuido. Lo levanto a mano cuando lo necesito:

1OLLAMA_FLASH_ATTENTION=1 OLLAMA_KV_CACHE_TYPE=q8_0 ollama serve

Y me bajo un modelo pequeño, no el más grande que quepa:

1ollama pull qwen3:4b     # 2,3 GB en disco

Primer intento: un muro de texto en inglés

Le di unos apuntes sobre el modelo OSI y le pedí 4 preguntas tipo test en formato GIFT, que es el que Moodle sabe importar. Y esto es lo que me devolvió:

Okay, I need to create exactly 4 multiple-choice questions in Moodle's GIFT
format based on the given text about the OSI model. Let me start by
understanding the text thoroughly.

The text describes the OSI model's seven layers...

Párrafo tras párrafo, en inglés, hasta quedarse sin espacio y cortarse a media frase.

Qué es eso de “pensar en voz alta”

Los modelos actuales vienen en dos sabores. Los clásicos: les preguntas y responden. Y los razonadores, que antes de contestar escriben un monólogo interno resolviendo el problema. No es un capricho: en tareas difíciles aciertan más así.

Lo normal es que ese monólogo vaya por un canal aparte —la API lo devuelve en un campo thinking— y tú solo enseñes la respuesta final. Aquí ese canal volvía vacío y todo el monólogo caía mezclado con la respuesta. Volveré sobre esto, porque el error era mío.

Qué es el “presupuesto de tokens” (y por qué existe si es gratis)

Al lanzar una petición pones un límite de cuánto texto puede generar (num_predict, o max_tokens en las APIs de pago). En la nube ese número es dinero. En mi servidor no cuesta ni un céntimo.

¿Y por qué ponerlo entonces? Porque un modelo no sabe parar solo: puede enrollarse o entrar en bucle repitiendo lo mismo indefinidamente. Es el freno de mano.

Pero en local también pagas, solo que no en euros:

  • En segundos: a ~28 tokens/s, 5.000 tokens son casi 3 minutos de espera.
  • En RAM: todo lo generado se acumula en memoria, en una máquina que ya sostiene otras cosas.

En la nube pagas por token. En tu casa pagas por segundo.

Yo había puesto el límite en 1.500. El modelo gastó unos 1.400 pensando y le quedaron 100 para responder. Es como dar dos folios de examen y que el alumno gaste folio y tres cuartos en el “a ver, déjame que me organice”.

Segundo intento: me bajo uno que no piense

La conclusión parecía evidente: el problema es que este modelo se enrolla. Así que probé uno no razonador, de la misma familia y tamaño parecido, para que la única variable fuera esa:

1ollama pull qwen2.5:3b   # 1,9 GB

7 segundos. Formato impecable. Cuatro preguntas limpias. Y entonces las leí:

::Protocolo IP::¿Qué protocolo opera en la capa de red del modelo OSI? {
=El protocolo TCP      ← marcada como CORRECTA
~El protocolo IP       ← la respuesta buena, marcada como error
~El protocolo UDP
~El protocolo HTTP
}

::TCP y UDP::¿Cuál de los siguientes protocolos no garantiza la entrega...? {
=TCP                   ← es UDP
~UDP
...
}

Dos de cada cuatro preguntas con la respuesta equivocada marcada como buena.

Y antes de culpar al modelo: mi primer prompt usaba una plantilla con marcadores (::Título de la pregunta::) y el modelo la copió literalmente, devolviendo cosas como ::Título::Capa física {=capa_fisica~capa_fisica}, con la respuesta correcta y la incorrecta idénticas. Rehice el prompt con un ejemplo completo resuelto y eso arregló el formato… pero no la corrección factual. El fallo de arriba es ya del prompt bueno.

Tercer intento: ¿y si el problema era yo?

Aquí es donde el experimento dio la vuelta. Me hicieron la pregunta obvia: ¿no será cuestión de configuración? Fui a comprobarlo:

1ollama show qwen3:4b
Capabilities
  completion
  tools
  thinking      ← lo soporta perfectamente

El modelo declara capacidad de razonamiento separado. Así que probé las dos configuraciones con la misma petición:

Configuración Campo thinking Campo content
"think": false 0 caracteres 3.659 caracteres de monólogo en inglés
"think": true 3.880 caracteres (limpio)

Ahí estaba mi error. Yo usaba think: false creyendo que así lo callaba. Lo que hace en realidad es decirle a Ollama “no esperes razonamiento”: el modelo razona igualmente —no puede evitarlo, es como está entrenado— y al no haber etiquetas que parsear, todo ese monólogo se vuelca en la respuesta.

La configuración correcta es la contraria: dejarle pensar y leer el otro canal. Con think: true y presupuesto de sobra:

1body = {
2    "model": "qwen3:4b",
3    "messages": [{"role": "user", "content": PROMPT}],
4    "think": True,                          # ← la clave
5    "options": {"num_predict": 12000},      # ← margen de sobra
6}

Resultado:

  • 180 segundos (3 minutos), 4.876 tokens
  • 18.520 caracteres de razonamiento, todos en el canal thinking
  • 1.029 caracteres en content: GIFT limpio, sin una palabra de más
::Función de la capa física::¿Cuál es la función principal de la capa física...? {
=Transmite bits por el medio
~Agrupa bits en tramas y detecta errores
~Realiza direccionamiento lógico y enrutamiento
~Garantiza la entrega extremo a extremo
}

::Capa con direcciones MAC::¿En qué capa se utilizan las direcciones MAC...? {
=La capa de enlace de datos
~La capa física
~La capa de red
~La capa de transporte
}

Cuatro de cuatro, correctas. Sin nada que rescatar del ruido.

La comparación de verdad

Razonador bien configurado No razonador
Modelo qwen3:4b (2,3 GB) qwen2.5:3b (1,9 GB)
Tiempo 180 s 7 s
Tokens generados 4.876 (mayoría pensando) 221
Salida GIFT limpio GIFT limpio
Aciertos 4/4 2/4
Impacto en producción Ninguno medible Ninguno medible

Ese es el intercambio real: 26 veces más lento a cambio del doble de aciertos. Y mientras generaba, medí mis servicios: el aula respondió en 0,14 s y la web en 0,05 s. Ni se enteraron.

La lección: el fallo que no se ve

Yo tenía un validador comprobando la salida: llaves equilibradas, una sola respuesta correcta, distractores suficientes. Dio por buenas las cuatro preguntas del modelo rápido. Porque mi validador sabe de llaves y de signos, pero no sabe de redes.

Fíjate en la diferencia entre los dos fallos:

  • El del razonador mal configurado era escandaloso: te llenaba la pantalla de inglés, imposible no verlo.
  • El del modelo rápido es silencioso: te entrega algo impecable, bien formateado, listo para importar… y con la respuesta cambiada.

El segundo no lo caza ningún validador automático. Solo lo caza alguien que sepa de la materia. Y si no lo caza nadie, llega al examen. Y del examen, al alumno.

Mi conclusión no es la que esperaba al empezar. Iba buscando si un modelo pequeño podía sustituir a uno de pago, y acabé aprendiendo otra cosa: ese monólogo que me parecía ruido era el trabajo. Quítale a un modelo el rato de pensar y te queda un texto perfecto por fuera y vacío por dentro. Los tres minutos no son el precio del formato; son el precio de que las respuestas estén bien.

Entonces, ¿se puede?

Sí. Gratis en euros, se puede. Un modelo de 2,3 GB, en un servidor que ya está haciendo otras cinco cosas, genera preguntas de examen correctas sin mandarle los apuntes a nadie. Y para un centro educativo, que los datos de sus alumnos no salgan del edificio no es un detalle menor: ahí no compite la calidad, compite el reglamento de protección de datos.

Pero gratis no es lo mismo que sin coste. Se paga en minutos de espera, en leerse la documentación de verdad antes de dar algo por imposible —lección aprendida— y en un profesor revisando las preguntas antes de ponerlas. Que, bien mirado, es exactamente lo que hace un profesor con cualquier examen.

De momento los modelos se quedan instalados, porque esto no ha hecho más que empezar. Quiero probar modelos algo más grandes a ver hasta dónde aguanta la máquina y darles usos que no sean preguntas de examen. Iré contando.


Este experimento es también el episodio 20 del podcast, Probando una IA local en casa, por si prefieres escucharlo.

CompartirShare