17°
Portada del artículo: Un modelo que no escribe, solo decide: puse a Intern-Decision a predecir la lluvia sin entrenarlo
ModelosBenchmarksGPUDatos

Un modelo que no escribe, solo decide: puse a Intern-Decision a predecir la lluvia sin entrenarlo

Intern-Decision salió el 26 de septiembre de 2026: modelos de 0,8B a 4B que no generan texto y devuelven una probabilidad por pregunta en una sola pasada. Lo instalé el mismo día, tropecé con tres fallos al instalarlo, uno de los cuales lo hacía entre 2 y 3,2 veces más lento, y lo puse a predecir la lluvia de mañana en 27.256 días de siete ciudades chilenas sin entrenarlo. El 2B llega a un AUC de 0,823, casi lo mismo que un Naive Bayes entrenado con 74.145 filas, y queda bajo la regresión logística.

Efrain Garay 26 de septiembre de 2026

Reproduciendo el resumen

La semana pasada apareció una categoría nueva de modelo de lenguaje: uno que no escribe. Jev, de TypeSafe AI, recibe texto y devuelve números: probabilidades para categorías, preguntas de sí o no y calificaciones. Pero Jev, según esa presentación, funciona solo como API.

Hoy, 26 de septiembre, Shanghai AI Lab subió a Hugging Face Intern-Decision: la misma idea con pesos abiertos, licencia Apache 2.0 y tres tamaños: el más grande ocupa unos 9 GiB de memoria de video y los otros dos caben en tarjetas modestas. Cuando lo bajé tenía cero descargas.

Lo instalé esa misma mañana y le hice la pregunta que ya le hice a nueve modelos en la serie de algoritmos: ¿va a llover mañana? La diferencia es que a este no lo entrené.

bench · resultadoslisto · exit 0

$ python banco.py 2B lluvia

0,823intern-2B · sin entrenar, solo prompt
0,847logística · entrenada, 74.145 filas
0,883boosting · entrenado, 74.145 filas

veredicto > Sin entrenarlo con estos datos, el 2B quedó 0,024 de AUC por debajo de la regresión logística entrenada y empató al Naive Bayes, a 21,8 ms por consulta.▋

Qué es

Un modelo de lenguaje normal responde generando texto, token a token. Intern-Decision hace otra cosa: recibe un estado (un texto, y opcionalmente imágenes) y un esquema de preguntas cerradas, arma una plantilla con un marcador <decision> por pregunta y hace una sola pasada hacia adelante. En la posición anterior a cada marcador lee los logits, se queda solo con los de las opciones permitidas (A, B, C…) y aplica softmax después de dividirlos por una temperatura fijada de fábrica.

No hay generate() ni muestreo. Por eso contesta en milisegundos, y por eso puede responder varias preguntas por el precio de una.

Cómo responde Intern-Decision: una pasada, sin generar textoLa misma solicitud que envía la prueba de lluvia, dibujada sobre un día real del test, guardado junto a los datos de la medición. Modelo: 2B.
Cómo responde Intern-Decision: una pasada, sin generar textoestado del díaTemuco · 2021-08-07máx 10,5 °C · humedad 86 %plantillapregunta: ¿llueve mañana?respuesta: <decision>una sola pasadaQwen3.5 afinadosin generate() ni muestreologits del marcadorposición antes de <decision>solo A = no, B = sísoftmax(logits / T)T = 2,10calibración de fábricarespuesta tipadalluvia: P(sí) = 0,32más la etiqueta de decisiónCómo responde Intern-Decision: una pasada, sin generar textoestado del díaTemuco · 2021-08-07máx 10,5 °C · humedad 86 %plantillapregunta: ¿llueve mañana?respuesta: <decision>una sola pasadaQwen3.5 afinadosin generate() ni muestreologits del marcadorposición antes de <decision>solo A = no, B = sísoftmax(logits / T)T = 2,10calibración de fábricarespuesta tipadalluvia: P(sí) = 0,32más la etiqueta de decisión

No se muestrea ningún token. La respuesta entera son dos logits leídos en una posición, y por eso un modelo de 0,8B contesta en unos 20 ms en GPU.

Los tres tamaños están afinados desde Qwen3.5, que mezcla atención normal con atención lineal. Ese detalle de arquitectura es el que más me costó en la instalación.

En 65 segundos y con narración: un oráculo que no habla, solo levanta una tarjeta con un número. Lo que se rompió al instalarlo, los 19,9 ms por consulta, el AUC de 0,823 prediciendo la lluvia sin entrenar y el techo de 0,62 en sus probabilidades. Todas las cifras son las medidas. Sin sonido por defecto: actívalo en los controles.Verlo en el visualizador de reels →

Instalación, y lo que se rompió

El README pide Python 3.12, pip install -r requirements.txt e importar DecisionEngine desde la carpeta del modelo. Lo hice al pie de la letra, dentro de un entorno aislado en mi máquina con la RTX 4070 Ti SUPER, y tropecé tres veces.

1. El modelo no encuentra su propio tokenizador. La primera carga falla con Couldn't instantiate the backend tokenizer, aunque tokenizer.json está ahí, también con la versión de transformers que fija el modelo (5.14.1). La causa está en su inference.py: usa Path(__file__).resolve().parent como carpeta del checkpoint. En la caché de Hugging Face, inference.py es un enlace simbólico a blobs/<hash>, así que resolve() apunta a la carpeta de blobs, donde ningún archivo conserva su nombre. Se arregla pasando la carpeta del snapshot explícita: DecisionEngine(checkpoint=snap). Guardé la reproducción con las dos cargas: la que falla sale de la carpeta blobs y la que pasa el snapshot carga sin problemas.

2. Corre, pero entre 2 y 3,2 veces más lento de lo que debería. Al cargar, transformers avisa en una línea fácil de perder: The fast path is not available because one of the required library is not installed. Qwen3.5 usa atención lineal, y su camino rápido necesita flash-linear-attention y causal-conv1d. Ninguna de las dos está en el requirements.txt del modelo. Sin ellas, transformers cae a una implementación en PyTorch puro.

3. causal-conv1d no compila con el CUDA que tenía. Para esta combinación de torch y CUDA se compila desde el código. Con el nvcc 13.0 falla en los encabezados de la glibc de Fedora 43 (mathcalls.h: error: exception specification is incompatible with that of previous function "rsqrt"). Con el nvcc 13.1 compila; lo verifiqué después con un archivo mínimo, y da igual si el compilador del host es gcc 14 o gcc 15. Lo que usé, limitado a la arquitectura de mi tarjeta:

export CUDA_HOME=/usr/local/cuda-13.1 PATH=/usr/local/cuda-13.1/bin:$PATH
export TORCH_CUDA_ARCH_LIST=8.9 NVCC_CCBIN=/usr/bin/g++-14 CC=gcc-14 CXX=g++-14 MAX_JOBS=8
uv pip install flash-linear-attention
uv pip install --no-build-isolation causal-conv1d

Los dos caminos usan núcleos de cálculo distintos y pueden dar probabilidades levemente distintas; no cuantifiqué esa diferencia sobre el test completo. Todas las predicciones de lluvia que siguen se hicieron con el camino rápido.

Cuánto tarda cada consulta

Medí dentro de un contenedor con límites de pod: 8 CPU, 24 GB de RAM y la GPU por CDI. Doscientas consultas por modelo después de calentar, midiendo desde que entra el diccionario hasta que sale la respuesta. Hice dos tipos: el ejemplo del README (tres preguntas a la vez) y la consulta de lluvia (una pregunta).

Milisegundos por consulta, de la solicitud a la respuestaLa consulta de lluvia dentro del pod de 8 CPU y 24 GB: 200 veces por modelo en GPU, 30 en CPU.
0.8B con camino rápido19,81 ms
2B con camino rápido21,87 ms
4B con camino rápido43,57 ms
0.8B sin las dos librerías63,22 ms
2B sin las dos librerías64,22 ms
4B sin las dos librerías85 ms

Sin flash-linear-attention ni causal-conv1d, transformers cae a PyTorch puro para la atención lineal. Un segundo de animación son 20 ms medidos.

0.8B en bf16298,12 ms
2B en bf16647,65 ms
4B en bf161635,06 ms
0.8B en float32533,41 ms
2B en float321175,88 ms
4B en float323213,97 ms

Mediana de 30 consultas en un Ryzen 7 7800X3D con cuota de 8 CPU y sin GPU visible. Un segundo de animación es un segundo medido.

En GPU, media de 200 consultas: con camino rápido el p95 queda a menos de 0,3 ms de la media, y sin él a menos de 1 ms. En CPU, mediana de 30, porque la dispersión es mayor: el 4B en float32 va de 3,2 s en la mediana a 5,6 s en el p95. En la tabla del README, medida en una RTX 4090, el autor declara 34, 33 y 44 ms.

ModeloCon camino rápidoSin las dos libreríasMemoria pico (MiB asignados por PyTorch)Declarado (RTX 4090)
Intern-Decision-0.8B19,9 ms63,3 ms1.94834,0 ms
Intern-Decision-2B21,8 ms64,1 ms4.25533,3 ms
Intern-Decision-4B42,5 ms85,4 ms9.05644,2 ms

Latencia media del ejemplo de tres preguntas, que es la que declara el README. La de lluvia, con una sola pregunta, queda dentro de 1,1 ms de esa cifra; la figura de arriba usa la de lluvia.

En CPU, con el mismo pod (cuota de 8 CPU) y sin GPU visible, la mediana del 0,8B es 0,30 segundos por consulta en bf16 y 0,53 en float32. El 4B llega a 1,6 segundos en bf16 y 3,2 en float32, con un p95 de 5,6. De a una consulta por vez, el 0,8B en bf16 da unas 200 decisiones por minuto; el mismo modelo en la GPU, unas 3.000. El motor carga en bf16 por defecto y acepta dtype="float32"; en este Ryzen, que sí tiene instrucciones bf16, bf16 fue el más rápido.

Dos cosas me llamaron la atención. La consulta del README, con tres preguntas, y la de lluvia, con una, tardan casi lo mismo; no es una prueba limpia de que tres cuesten lo mismo que una, porque los estados tienen largos distintos, pero va en la dirección que promete la idea. Y en mi tarjeta, más modesta que la del autor, el 0,8B y el 2B quedan por debajo de lo que declara. No sé con qué instalación midió.

La prueba propia: ¿llueve mañana?

La serie de algoritmos usa siempre la misma tabla: datos diarios de NASA POWER para siete ciudades chilenas, de La Serena a Punta Arenas. Se entrena con 1984-2012 (74.145 filas) y se prueba con 2016-2026 (27.256 días). La pregunta es si mañana caerá al menos 1 mm.

A Intern-Decision no le di las filas de entrenamiento. Por cada día de prueba le mandé un estado en texto con la misma información meteorológica que usan los modelos entrenados, pero escrita: valores redondeados, el viento en ocho rumbos, la fecha completa en vez de sus senos y cosenos, y el nombre de la ciudad. Más una pregunta de sí o no:

Weather station in Temuco, Chile (latitude -38.7). Date: 2021-08-07.
Today: max temperature 10.5 °C, min temperature 0.2 °C, precipitation 0.7 mm
(yesterday 9.6 mm), relative humidity 86 %, dew point 3.3 °C, surface pressure
99.16 kPa (+0.39 kPa since yesterday), wind 4.9 m/s from the S, solar radiation
12.3 MJ/m².

rain (noul): Will it rain at least 1 mm tomorrow at this station?

Lo escribí en inglés porque su banco de pruebas está en inglés. La probabilidad de “sí” es la predicción. Con eso se calcula el AUC, la misma métrica que usa toda la serie, sobre los mismos 27.256 días.

AUC sobre los mismos 27.256 días de pruebaAUC · más es mejor
  1. Boosting, 594 rondas (entrenado)0,883
  2. Bosque de 200 árboles (entrenado)0,882
  3. Regresión logística (entrenada)0,847
  4. Intern-Decision-2B (sin entrenar)0,823
  5. Naive Bayes gaussiano (entrenado)0,822
  6. Intern-Decision-4B (sin entrenar)0,821
  7. Intern-Decision-0.8B (sin entrenar)0,803
  8. Persistencia: mañana igual que hoy0,709

Modelos entrenados: tabla unificada de la serie (transformer/vs_models.json), entrenados con 1984-2012. Intern-Decision: sin entrenamiento, una consulta por día, dentro del pod con la RTX 4070 Ti SUPER.

Leído con calma: un modelo al que no entrené con estas estaciones ordena los días mejor que la regla ingenua de “mañana igual que hoy”, y queda a 0,0004 de un Naive Bayes que sí se entrenó con 74.145 filas. Pero la regresión logística más simple, un archivo de 1,8 KB que contesta en menos de un milisegundo en CPU (0,4 ms, medidos en la serie con un hilo y fuera de este contenedor), le gana por 0,024. Y los modelos de árboles, el bosque y el boosting, por 0,06.

El 4B no mejora al 2B. Saca 0,821 contra 0,823, con el doble de memoria y el doble de latencia. En el promedio de los benchmarks del autor el 4B sí gana, así que esto parece propio de la tarea.

El problema no está en el orden, está en la escala

El AUC solo mira si los días lluviosos quedan por encima de los secos. No mira si la probabilidad dice la verdad. Y ahí aparece lo que más me sorprendió.

En el 10 % de días que cada modelo considera más probables de lluvia, llovió el 63,2 % de las veces con el 2B, el 63,6 % con el 4B y el 63,3 % con la regresión logística. En ese extremo aciertan en la misma proporción. Lo que cambia es el número que ponen al lado.

Probabilidades comprimidas: el 2B no pasa de 0,62 ni el 4B de 0,68Cada punto es un tramo de probabilidad predicha; su altura es cuántas veces llovió de verdad al día siguiente. El tamaño del punto es la cantidad de días del tramo.
0,00,00,20,20,40,40,60,60,80,81,01,0techo 2B 0,62techo 4B 0,68probabilidad de lluvia predichalluvia observada
  • regresión logística entrenada
  • Intern-Decision-2B sin entrenar
  • Intern-Decision-4B sin entrenar

Los mismos 27.256 días de prueba para las tres curvas. Sobre la diagonal el modelo se queda corto: en el tramo de 0,5 a 0,6 del 2B, el más alto con al menos 30 días, predijo 0,52 en promedio y llovió el 79 % de las veces.

El máximo que emitió el 2B en los 27.256 días fue 0,62. Solo el 2 % de los días llegó a 0,5 o más, y apenas el 1,3 % lo superó; en el tramo de 0,5 a 0,6, con 547 días, predijo 0,52 en promedio y llovió el 79 %. Su etiqueta de decisión (el campo decision, que elige la opción más probable y en un empate exacto dice “no”) marca lluvia en 346 de 27.256 días: acierta el 5 % de los días que sí llovieron. El 0,8B es peor: su máximo fue exactamente 0,50, en 6 días, y como el empate se resuelve a “no”, su etiqueta no marcó lluvia ni un solo día.

Dónde gana sin entrenar

Separado por ciudad, el resultado no es parejo. El 2B le gana a la regresión logística en tres de las siete ciudades, y no siguen un patrón simple de frecuencia: La Serena, donde casi nunca llueve, Santiago, y Punta Arenas, donde más llueve.

CiudadDías con lluvia al día siguienteRegresión logísticaIntern-Decision-2B
La Serena2,2 %0,8360,886
Santiago9,7 %0,7350,771
Punta Arenas39,2 %0,5600,617
Valparaíso7,4 %0,8500,809
Concepción20,5 %0,8600,815
Temuco26,1 %0,8390,779
Puerto Montt36,5 %0,8280,780

Tengo una hipótesis que no probé. La regresión logística aprende un solo conjunto de pesos para las siete ciudades; recibe la latitud (su tercer coeficiente más fuerte en valor absoluto), pero no el nombre de la ciudad. El modelo de lenguaje lee “La Serena” como contexto, y en La Serena, donde casi nunca llueve, ese contexto puede valer más que un peso compartido. Punta Arenas, donde llueve el 39 % de los días, no encaja en esa explicación. También puede ser otra cosa: el AUC por ciudad mide cómo ordena dentro de cada ciudad, y ahí cualquier ventaja local cuenta.

Lo que esta medición no dice

  • Es una sola tarea. Tabular, numérica y en un dominio donde un modelo entrenado con 74.000 filas tiene toda la ventaja. En clasificación de texto libre, que es para lo que el autor lo muestra, el resultado puede ser otro.
  • No ajusté la redacción del estado. Escribí un prompt razonable y no lo cambié después de ver resultados, a propósito: ajustar el texto mirando el test sería entrenar a mano sobre el test.
  • El modelo pudo haber visto datos de clima en su preentrenamiento. No hay forma de saber cuánto de la temporada 2016-2026 conoce Qwen3.5.
  • La latencia es por consulta, de a una. Según su README el motor recibe una solicitud por llamada; no medí lotes ni consultas en paralelo.
  • La CPU la medí en el mismo pod con cuota de 8 CPU (Ryzen 7 7800X3D), no en una CPU vieja. Mi otra máquina, un i5-9400F, estaba ocupada con otro trabajo y descarté lo que medí ahí.

Cuándo lo usaría y cuándo no

Lo usaría para decisiones sobre texto donde no tengo datos etiquetados todavía: clasificar tickets, enrutar solicitudes, decidir si un mensaje necesita respuesta humana. Veinte milisegundos por consulta en una tarjeta de consumo, varias preguntas en una sola pasada y un JSON tipado en vez de texto que hay que parsear. No lo medí en esas tareas; es donde lo probaría primero, como clasificador inicial mientras se juntan etiquetas.

No lo usaría donde ya tengo datos para entrenar algo simple. En esta prueba, con 74.145 filas de entrenamiento, una regresión logística de 1,8 KB le ganó en calidad y en latencia, y corre en cualquier parte. Tampoco usaría su probabilidad tal cual para decidir con un umbral: en mi prueba estaba comprimida y la etiqueta de decisión casi nunca decía que sí.

Y si lo instalas, instala también flash-linear-attention y causal-conv1d. Sin ellas se paga entre 2 y 3,2 veces la latencia sin ningún aviso más que una línea en el registro.


Medido el 26 de septiembre de 2026 en una RTX 4070 Ti SUPER de 16 GB, dentro de un contenedor con 8 CPU y 24 GB (Fedora 43), con torch 2.14.0+cu130 (el README fija 2.9.1), transformers 5.14.1, flash-linear-attention 0.5.2, causal-conv1d 1.7.0 y el driver NVIDIA 595.91. Datos de NASA POWER, la misma tabla de toda la serie.

Fuentes

  • Intern-Decision, colección de InternLM en Hugging Face, publicada el 26 de septiembre de 2026. Pesos de 0,8B, 2B y 4B con licencia Apache 2.0, y el README con los benchmarks y latencias declaradas.
  • internlm/Intern-Decision, el repositorio del proyecto.
  • Jev introduces a new shape of LLM, Simon Willison, 21 de septiembre de 2026. La presentación de los modelos de decisión y de Jev, que según ella funciona solo como API.
  • Qwen3.5-4B, el modelo base del 4B.
  • flash-linear-attention y causal-conv1d, las dos librerías del camino rápido que faltan en su instalación.
  • NASA POWER, la fuente de los datos diarios de las siete estaciones.

Comentarios

Todavía no hay comentarios. El primero es tuyo.

Se revisa antes de publicarse. El correo no se guarda ni aparece en ninguna parte.