Producto
Cosas que costaron un día averiguar
Relatos de defectos que no se anunciaron: un cargador que revienta en vez de fallar, un valor por omisión invertido entre dos ficheros, y una frontera donde un tipo equivocado compila perfectamente en ambos lados.
Actualizado 2026-09-12
Construir un motor de inferencia consiste en leer muchísimo código que funciona y averiguar por qué funciona. De vez en cuando uno lo averigua por las malas. Los relatos que siguen son de esa segunda clase.
Tienen una cosa en común, y es también lo que justifica escribirlos: ninguno de ellos produjo un mensaje de error. Un defecto que revienta se corrige en una hora. Un defecto que devuelve una salida plausible se publica, y lo encuentra semanas después alguien que hasta entonces había supuesto que el modelo era sencillamente mediocre.
Las notas de abajo hablan de MLX, de los ficheros de configuración que publican los modelos, y de la frontera entre dos lenguajes. Ninguna es específica de Runlix: quien escriba cualquier cosa que cargue pesos de MLX, o que llame a Rust desde C#, se topará con ellas.
Por qué estas y no las demás
Las notas internas del motor suman un par de docenas de entradas, y no todas pertenecen a una página pública. Deciden dos reglas.
Se publica lo que pertenece a la biblioteca de otro. Cómo se comporta MLX, qué da por
supuesto mlx-lm, qué puede contener el config.json de un modelo. Ese conocimiento no es
nuestro para guardarlo: es el precio de haber leído con cuidado la biblioteca de otra persona, y
alguien lo está buscando ahora mismo porque se ha dado contra el mismo muro.
Se guarda lo que es nuestro. El diseño de la caché paginada, cómo el muestreo materializa sus candidatos, la decisión de recortar antes de la proyección final. Eso costó mediciones y es la ventaja del motor, no un hecho general sobre MLX.
La línea no es secretismo por el secretismo. Es que la primera categoría es conocimiento que necesitan los usuarios de otro, y la segunda es trabajo.
Para quién están escritas
Para tres clases de lector, y el primer párrafo de cada nota le dice cuál es usted.
Si está portando una arquitectura de modelo —desde mlx-lm, o desde cualquier implementación
de referencia hacia cualquier lenguaje—, dos de estas notas describen exactamente las trampas con
las que va a encontrarse, y la tercera trata de la frontera que construirá para llamar a su
trabajo desde una aplicación.
Si usa MLX desde C o desde Rust en vez de desde Python, la nota del cargador le ahorra un día, y la de la frontera C describe una clase de defecto que empeora cuanto más tiempo pasa sin que nadie la busque a propósito.
Si no hace ni lo uno ni lo otro, una de ellas sigue mereciendo la lectura: que un defecto que devuelve un valor plausible cueste más caro que uno que revienta no tiene nada de específico de los motores de inferencia, y lo que se sigue de ahí tampoco.
Lo que no son
No son tutoriales. Aquí no hay material de iniciación, y ninguna explica qué es un transformador ni cómo se instala nada: ese material existe, está bien escrito en otros sitios, y repetirlo solo añadiría páginas que nadie necesita.
Tampoco son notas de versión. Aquí no se anuncia ninguna funcionalidad. Cada una es un defecto cuya búsqueda duró lo bastante como para que escribirlo pareciera más barato que dejar que la siguiente persona perdiera el mismo día.
Con qué frecuencia aparecen
Despacio, y es deliberado, no falta de material.
Una nota se publica cuando el defecto se entiende lo bastante bien como para decirse en una frase, y ni un día antes. La mitad del valor de escribirla está justamente en esa exigencia: si el relato necesita tres párrafos de reservas para describir qué salió mal, la investigación no estaba terminada, y la respuesta correcta es volver a terminarla en vez de publicar las reservas.
Eso significa que no hay calendario. Quien quiera saber cuándo aparece una, en la suscripción hay una categoría para exactamente eso y para nada más.
Cómo se verifica todo esto
Detrás de cada afirmación de estas notas hay un número o una reproducción, y allí donde aparece un número, lleva al lado la fecha en que se midió.
Es una costumbre que este proyecto aprendió cara. Tres cifras escritas a mano en un documento interno resultaron ser, al medirlas de nuevo, 33 en lugar de 32, 26 en lugar de 24, y 1294 en lugar de 605: la última equivocada por más del doble. Un número dentro de un texto corrido no tiene a nadie que lo mantenga. Por eso los números de aquí llevan fecha, y si alguno se ha desviado, esa fecha es el aviso.
La frontera donde compilan los dos lados y uno de ellos miente
A través de una ABI de C, una función mal escrita no es un error de compilación y una mal tipada no la ve ni nm. Una declaración de 32 bits sobre un valor de 64 convirtió 23347 MB en 2,8 GB: plausible, y equivocado por un factor de ocho.
Medido 2026-09-11El cargador que revienta en vez de fallar
Cargar pesos de MLX en el flujo de GPU no lanza ningún error. Devuelve un código distinto de cero que probablemente no comprobaste, y después leer los datos mata el proceso. Aquí está el porqué, y qué hacer al respecto.
Medido 2026-09-06Un valor por omisión que está invertido entre dos ficheros
Cuando la configuración de un modelo no menciona tie_word_embeddings, phi3 supone false y llama supone true. Copia cualquiera de los dos y obtienes un modelo que acierta en una familia y se equivoca en silencio en la otra.
Medido 2026-09-06