Ir al contenido

Ingeniería

Qué modelos funcionan realmente en MLX

Cómo saber, antes de descargar ocho gigabytes, si un modelo de Hugging Face va a cargar en Apple Silicon: el formato, la arquitectura, la cuantización y las cuatro trampas fáciles de pasar por alto.

Actualizado 2026-09-12Medido 2026-09-07

La página de un modelo en Hugging Face no dice si la cosa va a funcionar en tu Mac. Te enteras después de la descarga, por un error que nombra un campo de un fichero que nunca has abierto.

Todo lo que sigue se comprueba a partir de la lista de ficheros de un repositorio y de su config.json, en unas dos peticiones. Vale para MLX en general y no solo para Runlix: las trampas están en el formato y en las configuraciones de los modelos, y atrapan a cualquier motor que las lea.

Primera pregunta: ¿hay un fichero safetensors?

MLX carga safetensors. No GGUF, no .bin de PyTorch, no ONNX, no GGML.

Es con diferencia la decepción más frecuente, y la razón es que la mayor parte del material sobre «ejecutarlo en local» no habla de MLX en absoluto: habla de llama.cpp, cuyo contenedor GGUF no es intercambiable con los safetensors. GGUF es el contenedor de llama.cpp; lleva sus propios esquemas de cuantización y sus propios metadatos, y leerlo significaría implementar ese contenedor. Un modelo publicado solo como GGUF no funciona en MLX, y ninguna configuración del mundo cambia eso.

El atajo práctico: busca una versión del modelo en mlx-community. Esa organización vuelve a publicar modelos convertidos a safetensors de MLX, normalmente en varias cuantizaciones, y si existe una, casi siempre es lo correcto que descargar.

Un repositorio que solo tiene pytorch_model.bin también queda fuera, lo que sorprende a la gente porque los pesos «están ahí». Un ejemplo real: BAAI/bge-m3 publica exclusivamente pesos de PyTorch, así que no carga, y la razón es el formato, no la arquitectura, que sí está soportada.

Segunda pregunta: ¿qué dice model_type?

Abre el config.json del repositorio —Hugging Face lo muestra en el navegador— y busca model_type. Esa cadena decide qué implementación lee los pesos, y si no la implementa nada, el modelo no carga.

Sobre esa cadena hay dos cosas que conviene saber, porque las dos llevan a conclusiones equivocadas.

Existen los alias. mistral es otro nombre de llama en lo que a la implementación respecta: la arquitectura tiene la misma forma, así que un modelo Mistral funciona allí donde funcione llama, aunque el nombre no lo sugiera en absoluto. La propia biblioteca de MLX mantiene una tabla de reasignación para esto, y es lo que hay que consultar en vez de una lista que escribió alguien a mano.

Los modelos de visión se esconden tras nombres de modelos de texto. gemma3 y qwen2_5_vl tienen un model_type que parece el de un modelo de texto, y comprobar la arquitectura primero deja pasar un modelo de visión. Las señales fiables están en otra parte del repositorio: un preprocessor_config.json, un bloque vision_config dentro del config.json, o un nombre que contenga _vl, vision, llava o paligemma. Búscalas antes de mirar la familia.

Tercera pregunta: ¿cómo está cuantizado?

Los modelos MLX cuantizados llevan en config.json un bloque quantization con el número de bits y el tamaño de grupo. Cuatro bits es el caso habitual y funciona bien; ocho bits cuesta más memoria y queda más cerca del original.

La trampa aquí se llama cuantización por tensor. Algunos editores cuantizan distintos tensores con distinta precisión y lo anotan como un mapa dentro de la configuración en lugar de como un único ajuste. Un motor que aplique una sola cuantización a todo el modelo leerá esos pesos con el número de bits equivocado, y eso no falla en voz alta. Produce números erróneos de una manera que todavía se parece a texto.

Un ejemplo real que tropieza con esto: Qwen3.8-27B-Uncensored-OptiQ-4bit. El nombre dice cuatro bits; la configuración dice otra cosa para algunos tensores.

Cuarta pregunta: ¿declara la configuración algo exótico?

Tres campos provocan error silencioso en lugar de un fallo limpio, y por eso un motor cuidadoso los rechaza en vez de adivinar.

rope_scaling describe cómo se estira la información de posición para alcanzar un contexto más largo. default, llama3 y yarn son los esquemas implementados habitualmente. Cualquier otra cosa significa que las posiciones se calcularán de manera distinta a como se entrenó el modelo, y la salida será plausible y degradada en lugar de estar visiblemente rota.

Sobre YaRN en particular conviene saber que, cuando declara mscale_all_dim, escala también la atención y no solo las frecuencias. Pasarlo por alto no produce un error: produce logits todos desviados por el mismo factor, de modo que la ordenación sigue pareciendo sensata mientras los valores no lo son.

sliding_window limita hasta dónde llega la atención hacia atrás. Y aquí está la trampa, y es buena: Qwen2.5 declara sliding_window: 131072 y luego pone use_sliding_window: false. Una comprobación que lea solo el primer campo rechaza un modelo que está perfectamente bien. Hay que leer los dos.

layer_types aparece en modelos que mezclan tipos de atención entre capas. Cualquier cosa que no sea atención completa en todas las capas significa que el modelo espera un comportamiento que una implementación sencilla no ofrece.

Quinta pregunta: ¿cabe?

MLX corre en la GPU, y en Apple Silicon la GPU comparte memoria con todo lo demás. El techo no es la cifra de RAM de la caja: es el conjunto de trabajo que recomienda Metal, y es más bajo. En una máquina de 24 GB eso devolvió 23347 MB, y ese es el techo para todo, no solo para los pesos.

Una estimación gruesa que aguanta: los pesos en disco se parecen mucho a la memoria que ocupan, y un prompt largo cuesta bastante más por encima. Medido en un llama pequeño, el pico de memoria con un prompt de 4096 tokens fue 1,68× los pesos. Duplicar el tamaño de los pesos es una cifra segura para planificar.

Así que un modelo de cuatro bits cuyos ficheros suman 8 GB quiere unos 16 GB disponibles para ir cómodo con prompts largos, lo que en una máquina de 16 GB significa que es lo único que estás ejecutando.

Leer una ficha de modelo sin dejarse engañar

Las fichas las escribe gente contenta con su modelo, lo cual es justo, y no están escritas para decirte si va a cargar. Ayudan tres costumbres.

Ignora el número de parámetros del nombre y mira los tamaños de fichero. «7B» te informa sobre la arquitectura, no sobre lo que vas a descargar. El mismo modelo de 7B existe como 15 GB de pesos a 16 bits, 8 GB a 8 bits y 4 GB a 4 bits, y el nombre es idéntico en los tres casos. La lista de ficheros es la cifra honesta.

Ignora por completo las tablas de benchmarks para este fin. No dicen nada sobre si el formato es el correcto, y un modelo que puntúa bien y no carga puntúa cero en tu máquina.

Mira lo que el repositorio contiene de verdad y no lo que describe la ficha. Con frecuencia una ficha describe el modelo original mientras el repositorio guarda una conversión, o al revés. Los ficheros no tienen opiniones.

Cuando la respuesta es «todavía no»

Hay una respuesta intermedia entre «funciona» y «no funciona», y merece entenderse porque ahí aterrizan muchos modelos.

La biblioteca de MLX implementa bastante más de cien arquitecturas. Cualquier motor concreto implementa menos —Runlix implementa seis— y la diferencia no es un defecto de ninguna de las dos partes: una arquitectura traducida hay que verificarla contra una referencia antes de poder fiarse de ella, y es la verificación la que lleva tiempo.

Así que vale la pena consultar dos listas en vez de una: las arquitecturas propias del motor y las de la biblioteca. Una familia que está en la segunda y no en la primera es todavía no — conocida, traducible, a la espera de verificarse. Una familia que no está en ninguna es otra historia: hoy nadie la ejecuta sobre MLX, y esperar a un motor no lo cambia.

Lo que nada de esto te dice

Todo lo anterior trata de si los pesos cargarán y producirán números. No dice nada sobre si el modelo es bueno, sobre si habla bien tu idioma, sobre si su licencia permite lo que pretendes hacer, ni sobre si la cuantización le ha costado algo que importe para tu tarea.

La cuantización de cuatro bits, en particular, no sale gratis. Suele ser un buen intercambio, y en modelos pequeños a veces no lo es: cuanto más pequeño es el modelo, más trabajo estaba haciendo cada bit. Si un modelo de cuatro bits te decepciona, probar la versión de ocho bits del mismo es un experimento más barato que cambiar de modelo.

La versión corta

Antes de descargar, comprueba cinco cosas en este orden:

  1. hay safetensors — si no, para ahí;
  2. no es un modelo de visión — mira primero preprocessor_config.json y vision_config, porque el nombre no te lo va a decir;
  3. model_type está implementado — recordando que existen alias y que mistral significa llama;
  4. la cuantización es un ajuste, no un mapa por tensor;
  5. rope_scaling, sliding_window y layer_types son corrientes — y lee los dos campos de la ventana deslizante.

Por qué «no lo sé» es una respuesta de verdad

Cualquiera de estas comprobaciones puede quedarse sin conclusión: el repositorio puede no responder, o puede no tener config.json ninguno. La tentación es adivinar, porque un veredicto parece más útil que un encogimiento de hombros.

No lo es. Un motor que adivina cuando no puede saberlo acabará adivinando mal, y con aplomo, y tú te pasarás la sesión de depuración con la hipótesis equivocada. No saber merece decirse en voz alta.

Runlix hace estas comprobaciones por ti, en la fila, antes de la descarga, con el motivo escrito al lado del veredicto, incluido cuando el motivo es que no ha podido averiguarlo. Pero lo que importa son las comprobaciones, no la herramienta: son cinco preguntas a un fichero que cualquiera puede leer, y conocerlas vale más que cualquier aplicación que las conteste en tu lugar.