Volver a artículos
CategoríaPersonal

Cambié LLMs por SOM y destrabé la lectura de exámenes en Fleury

13 de octubre de 2026
Tags
Inteligencia ArtificialArquitecturaAutomatizaciónProductividad
Cambié LLMs por SOM y destrabé la lectura de exámenes en Fleury

Hook

Tiempo estimado de lectura: 6 min

Me pasé meses afinando prompts, encadenando llamadas a GPT y quemándome la cabeza para leer órdenes médicas en Grupo Fleury, solo para ver que nuestra precisión se clavaba en 85%. Daba rabia. Pagábamos una factura carísima cada mes, esperábamos más de dos segundos por documento y encima nos comíamos errores de JSON en medio del flujo.

Ahí decidí probar con SOM (System One Model) y básicamente destrabé un avance de dos años en dos días. Superamos la barrera del 85% y clavamos 92% de precisión leyendo exámenes, desplomando el tiempo de respuesta y el gasto en tokens. Si tu equipo todavía le mete un LLM generativo a decisiones simples para clasificar texto tipado, están quemando plata sin sentido.

El contexto

En Grupo Fleury, el reto de nuestro producto era bien directo en teoría y bien fastidioso en la práctica: agarrar el texto de órdenes médicas escaneadas, casi siempre con un OCR ruidoso y abreviaturas truncadas, y extraer las siglas exactas de cada examen del catálogo oficial.

Nuestra arquitectura anterior sufría para hacer esto. Metíamos tres llamadas a GPT en fila (una para los exámenes, otra para los datos de la orden y una tercera para la sede) y después mandábamos todo a un BERT para intentar conectar el texto suelto con la sigla correcta. Cada archivo tardaba casi cinco segundos en el flujo total. Quemábamos plata en tokens de salida generando JSON, siempre con el riesgo de que el modelo inventara un campo o rompiera el parseo de nuestra aplicación.

Usar un LLM generativo para esto sale caro y tarda. Un modelo autorregresivo se la pasa prediciendo la siguiente palabra para escupir texto libre; ponerlo a decidir si un examen está o no en la orden es básicamente usar un martillo para apretar un tornillo. Y ahí fue cuando el concepto de System One Models (SOM), que vino con fuerza con soluciones como Jev de TypeSafe y Microsoft-Decision-1, cambió nuestra forma de ver las cosas.

La lógica de SOM es otra: en lugar de mandar un prompt y esperar que genere texto, le pasamos el texto de la orden y opciones cerradas con preguntas tipadas. El modelo hace una sola pasada por la red y devuelve probabilidades calibradas (sea un booleano sí/no, una opción múltiple o una escala de puntajes). Cero generación de texto, cero errores de formato y la respuesta lista para caer directo en la lógica del software.

Qué pasó

Nos encerramos en la sala en octubre de 2026 para una maratón de dos días. La meta era directa: arrancar esa etapa pesada de lectura de exámenes que dependía de GPT y meter inferencia de una sola pasada de lleno, probando Microsoft-Decision-1 y Jev directo por OpenRouter.

Nuestro primer intento fue ingenuo. Intentamos tirarle el catálogo completo de exámenes de un solo golpe al modelo para que evaluara todas las opciones en modo exhaustivo. Cuando abrí la planilla y calculé la proyección de esa prueba en bruto, casi me caigo de la silla: correr el catálogo entero se iba a más de dieciocho mil dólares al mes en la escala real de Fleury, del grupo Fleury. Salió mal de entrada.

Me di cuenta al instante de que necesitábamos un filtro previo y barato antes de pegarle a la API. Ahí armé la estrategia de S80Y, creando una lógica de K adaptativo que define la cantidad exacta de siglas candidatas según las menciones del propio texto, usando un conteo local que no gasta ni medio centavo de token.

Con esa base lista, disparamos 51 rondas en vivo contra nuestro set cerrado de 527 documentos de prueba, mezclando órdenes médicas reales seudonimizadas con entradas sintéticas bien difíciles.

Los números validaron la prueba al toque. El costo mensual de la etapa de exámenes, que antes nos costaba US$ 839 combinando GPT con BERT, se desplomó a US$ 406 con S80Y. Y la mediana del tiempo de respuesta bajó de unos 2,2 segundos a 1,20 segundos por archivo. Fue básicamente lograr dos años de mejoras de producto en solo dos días de laboratorio, demostrando el impacto real de este nuevo modelo en nuestro desarrollo de software.

El punto de quiebre

Me di cuenta de que mandarle todo el catálogo de exámenes de un solo golpe al modelo era una tontería. El truco no pasaba por paralelizar a lo loco; había que hacer un prefiltrado local en milisegundos antes de tocar la red. En el pipeline S80Y básicamente contamos cuántas siglas tienen match exacto en el texto en bruto (nuestro nA) y calculamos de forma dinámica cuántas candidatas van: K = clamp(round(12 * nA + 10), 20, 120). Si la orden médica menciona dos exámenes obvios, mandamos unas 34 preguntas; si menciona diez, abrimos la cancha. Cortamos la mitad de los tokens sin perder nada de contexto clínico.

Y el gran acierto de Decision-1 está en su primitiva booleana, el noul. En vez de rezar para que el LLM escupa un JSON válido y pagar carísimo cada token generado en la respuesta, mandamos las preguntas por lote y recibimos probabilidades calibradas en una sola pasada de inferencia. El token de salida cuesta literalmente cero.

Armar la llamada queda súper directo contra el endpoint de Azure Foundry, sin depender de ningún SDK pesado:

python

import json
import urllib.request

def avaliar_exames(texto_pedido: str, candidatas: list[dict], url: str, api_key: str):
    questions = {
        item["sigla"]:
        {
            "type": "noul",
            "instructions": f"¿Se solicitó el examen {item['nome']} ({item['sigla']}) en la orden médica?",
            "criteria": {"true": "Examen explícitamente solicitado.", "false": "No mencionado o descartado."}
        }
        for item in candidatas
    }
    payload = json.dumps({"model": "microsoft-decision-1", "state": texto_pedido, "questions": questions}).encode("utf-8")
    req = urllib.request.Request(f"{url}/providers/microsoft/v1/systemone", data=payload, headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"})
    with urllib.request.urlopen(req) as resp:
        respostas = json.loads(resp.read().decode("utf-8")).get("answers", {})
    return [sigla for sigla, dados in respostas.items() if dados.get("noul", 0) >= 0.93]

Este script manda la orden médica en el state y evalúa las candidatas en paralelo. La ingeniería de software tradicional retoma el control: un if con un umbral de 0,93 filtra las aprobaciones al instante, sin alucinaciones de formato, destrabando ese 92% de precisión en nuestro producto.

Lecciones que aprendí

Después de darle tantas vueltas a las mediciones y a las pruebas en el producto, varias cosas quedaron clarísimas. Puedo resumir la experiencia en cuatro puntos que me habrían ahorrado varias desveladas si alguien me los hubiera dicho antes.

Primero: acortar la pregunta creyendo que estás ahorrando tokens es una trampa. Con la emoción de abaratar la llamada a la API, intentamos recortar las descripciones y dejar nada más el nombre canónico del examen. El resultado fue un golpe feo de casi 9 puntos en el F1. El modelo necesita los sinónimos detallados y las variaciones clínicas ahí en el criterio para tomar la decisión con seguridad, sobre todo cuando la redacción médica viene repleta de abreviaturas.

Segundo: si la respuesta cabe en un conjunto cerrado, usar un LLM generativo es tirar la plata a la basura. No tiene sentido pagar carísimo por token de salida y esperar dos o tres segundos para recibir un JSON con un valor fijo. El System One resuelve esto en una sola pasada directa, sin cobrar nada por la salida y entregando el dato al instante.

Tercero: las decisiones en cascada le ganan al paralelismo ciego. Al principio daban ganas de disparar todo al mismo tiempo. Pero aprendí rápido que dividir la responsabilidad en etapas secuenciales con prefiltros inteligentes funciona mucho mejor. Haces la clasificación rápida primero y solo ejecutas la lógica pesada donde de verdad hay ambigüedad.

Y por último, la calibración teórica no se sostiene sola con nuestro idioma. El modelo puede prometer una precisión hermosa en los benchmarks de afuera, pero con términos médicos reales la distribución cambia por completo. Congelar el umbral de confianza sin correr una buena batería de pruebas con datos propios es garantía de sustos en producción.

Lo que le diría a mi yo del pasado

Si pudiera retroceder unos meses en el tiempo, me tocaría el hombro y me diría: deja de quemar semanas afinando un prompt gigante para resolver lo que es, básicamente, una seguidilla de condiciones lógicas.

Perdimos días valiosos tratando de forzar a un LLM generativo a escupir JSON perfecto en cadenas larguísimas, metiendo capas y capas de validación solo para esquivar alucinaciones de formato. Cuando, la verdad, lo único que necesitábamos era un puntaje rápido y bien calibrado para decidir qué camino tomar en el flujo del producto.

Confía más en la división clásica: mándale la inferencia probabilística rápida al modelo System One para que decida en milisegundos y deja las reglas de negocio dentro del código determinista de toda la vida. La ganancia real de velocidad y entrega del equipo no pasa por agrandar el modelo. Viene directo de simplificar el contrato de la API.

Ahorra neuronas. Y resuélvelo de una vez.

Reflexión final

Para mí, la ingeniería de software con IA está cambiando de rumbo. Pasamos demasiado tiempo forzando a los LLM a escupir texto corrido cuando, en el fondo, solo nos hacía falta un medidor estadístico rápido y calibrado en la puerta de entrada.

Ver al SOM destrabando nuestro producto en Fleury me demostró lo prometedora que es esta tecnología. Puedes recortar costos y tirar la latencia al piso sin depender de tanta pirueta con los prompts.

¿Cómo resuelve tu equipo el triaje y la clasificación hoy? ¿Todavía andan peleando con tiempos de respuesta altísimos? Cuéntame acá abajo en los comentarios. Y si conoces a alguien en tu equipo que viva sufriendo porque la validación de JSON revienta en producción cada semana, pásale este post. La charla apenas empieza.