Clasificar Texto Sucio a Gran Escala: Lo que aprendí combinando JEV y Modelos Flash

Clasificar Texto Sucio a Gran Escala: Lo que aprendí combinando JEV y Modelos Flash

Estoy trabajando en un proyecto donde me enfrenté a un reto típico de procesamiento de lenguaje natural en el mundo real: clasificar miles de órdenes de mantenimiento.

Si alguna vez has trabajado con datos generados por humanos en el día a día — tickets de soporte, descripciones de fallas, bitácoras operativas o reportes de cualquier índole—, sabes que esos registros tienen problemas:

  • Textos cortísimos y truncados a 40 caracteres: «fuga sello bba», «alineac motor», «cambio rodamiento».
  • Abreviaturas que ningún diccionario estándar reconoce.
  • Categorías históricas asignadas al azar por personas que tenían prisa y marcaron lo primero que apareció en el menú desplegable.

Cuando tienes un volumen masivo de datos por procesar, la primera tentación hoy en día es decir: «Metámosle un prompt a un modelo grande de IA y que resuelva».

Pero cuando haces números, la realidad te frena en seco: mandar cientos de miles de filas a un modelo es lento, puede ser caro dependiendo de tu presupuesto y propenso a fallar si el modelo inventa respuestas o rompe el formato JSON.

Para evaluar alternativas viables, decidí hacer un pequeño experimento sobre una muestra representativa. Quería probar una arquitectura híbrida de dos etapas: utilizar primero un clasificador rápido y económico (TypeSafe Jev, que explico por dentro en JEV y el paradigma System One), filtrar los casos difíciles mediante un enrutador de incertidumbre, y enviar solo las dudas a un modelo de la familia Flash, pues no necesito solo la inteligencia de los LLMs, necesito un equilibrio de inteligencia y velocidad (Gemini 3.8 Flash, DeepSeek Flash y GPT-6 Luna de OpenAI).

Pero antes de tocar cualquier modelo de lenguaje, hubo un paso preliminar que cambió por completo mis resultados: el análisis exploratorio de datos (EDA) y la normalización con diccionarios técnicos.

Si estás buscando estrategias para clasificar texto sucio, categórico y estructurado en tus propios proyectos, acá te comparto los números reales, los tropiezos y las lecciones que me dejó este experimento.


El desafío: Clasificación multietiqueta sobre texto ruidoso

El objetivo para el negocio es la tarea de tomar el texto de una orden y predecir simultáneamente varias dimensiones técnicas bajo un catálogo cerrado:

  1. Filtro de alcance: ¿La orden realmente corresponde al equipo objetivo o a un componente periférico?
  2. Detección de evento: ¿Se trata de una falla o rotura real, o simplemente de una rutina/inspección programada?
  3. Tipo de intervención: Correctivo, preventivo, predictivo o administrativo.
  4. Componente intervenido: Identificar la pieza física específica (por ejemplo: sellos, rodamientos, acople, válvulas) dentro de una taxonomía jerárquica.
  5. Modo de falla: El síntoma físico observable (vibración, fuga, ruido, sobrecalentamiento, taponamiento, etc.).

La dificultad no está solo en entender la jerga técnica, sino en garantizar coherencia lógica y apego estricto a esquemas. Por ejemplo: si no hay falla, el modo de falla no puede inventarse; y el componente debe coincidir exactamente con una lista cerrada de opciones (enum) para que el resultado pueda guardarse directamente en una base de datos sin romper nada.


El paso previo que nadie quiere hacer: Análisis exploratorio (EDA) y diccionarios técnicos

Existe hoy una creencia ingenua de que la IA generativa vuelve obsoleta la limpieza tradicional de datos: “Pásale el texto tal como viene en la base de datos, el LLM es inteligente y va a entender lo que significa”.

Esto es un error. Si le entregas al modelo una cadena cruda como:

«mpv bba transfer sci cbm vib alta»

El modelo tiene que gastar capacidad de inferencia adivinando si mpv es un archivo de video, si sci es Science o Sistema Contra Incendio, y si cbm son metros cúbicos o Monitoreo de Condición. Cuando multiplicas esa ambigüedad por cientos de miles de filas, la tasa de alucinaciones y desvíos se multiplica.

Minando el vocabulario real con EDA

En lugar de sentarme a adivinar abreviaturas, hice un análisis exploratorio sistemático sobre los textos, usando técnicas de Procesamiento de Lenguaje Natural (NLP):

  1. Minería de frecuencias: Extraje todos los tokens no reconocidos por un diccionario estándar de español y calculé su frecuencia de aparición. Me encontré con que abreviaturas como mpv aparecían más de 3.200 veces, sci 2.340 veces, mtto 2.120 veces, bba 1.660 veces y vib más de 1.050 veces.
  2. Construcción de un glosario curado: Creé una tabla de normalización donde cada término técnico mapea a su expansión inequívoca (bba → bomba, mtto → mantenimiento, cbm → monitoreo de condición).
  3. Reglas para términos contextuales: Algunas abreviaturas son polisémicas. Por ejemplo, sem suele significar «semanal» si acompaña a una rutina de mantenimiento, pero significa «semana» si va precedido de un número (sem:#num). El normalizador revisa una ventana de vecinos a cada lado antes de expandir.
  4. Protección blindada de identificadores: Una regla crucial: cualquier token que contenga números o patrones de código o serie (como P-101A, 130-P-011B o TAG-45) jamás debe ser alterado por el diccionario para no destruir referencias a equipos.
---
title: PIPELINE DE NORMALIZACIÓN DE TEXTO TÉCNICO
---
flowchart LR
    RAW["<strong>Texto Crudo (Raw)</strong><br/><code>mpv bba transf</code>"] --> GLO["<strong>Expansión con Glosario</strong><br/><code>mantenimiento preventivo<br/>bomba transferencia</code>"]
    GLO --> ORT["<strong>Corrección Ortográfica</strong><br/><code>mantenimiento preventivo<br/>bomba transferencia</code>"]
    ORT --> NORM["<strong>Texto Normalizado</strong><br/><em>Payload listo para el modelo</em>"]

El impacto medido: +5% de precisión sin tocar prompts

¿Valió la pena el esfuerzo de construir este diccionario? Los datos me demostraron que sí:

  • En el clasificador base (JEV), la precisión en tipo de mantenimiento pasó de 69,2% con texto original a 74,2% con texto normalizado (+5,0% de mejora directa).
  • En un baseline zero-shot, el salto fue todavía más dramático: de 22,5% a 30,0%.
  • Al desarmar la jerga local y entregarle al modelo español técnico estándar, el motor puede concentrarse en la lógica de clasificación en lugar de jugar a descifrar jeroglíficos.

La arquitectura del experimento: ¿Por qué dos etapas?

Mandar el 100% de los datos a un LLM generalista suele ser un desperdicio de recursos. Muchos textos son sencillos y predecibles («inspección semanal de rutina» o «cambio de aceite programado»), mientras que otros son altamente ambiguos («se ajusta equipo por ruido extraño»).

Por eso probé un embudo en dos fases:

---
title: ARQUITECTURA DE CLASIFICACIÓN EN DOS ETAPAS
---
flowchart TD
    INPUT["<strong>Muestra de Órdenes</strong><br/><em>(Texto de mantenimiento)</em>"] --> STAGE1["<strong>ETAPA 1: CLASIFICADOR BASE</strong><br/><em>TypeSafe JEV (Rápido, económico)</em><br/>Predicción + Confianzas probabilísticas"]

    STAGE1 --> ROUTER{"<strong>ENRUTADOR DE INCERTIDUMBRE</strong><br/><em>Detección de casos dudosos</em>"}

    ROUTER -- "¿Caso seguro?<br/>(Alta confianza)" --> AUTO["<strong>APROBACIÓN AUTOMÁTICA</strong><br/><em>Paso directo a DB</em>"]
    ROUTER -- "¿Caso ambiguo o discrepante?<br/>(Baja confianza)" --> STAGE2["<strong>ETAPA 2: VERIFICADOR LLM</strong><br/><em>Modelos Flash con salida JSON</em><br/>(Gemini / DeepSeek / OpenAI)"]

    AUTO --> CONS["<strong>RESULTADO CONSOLIDADO</strong>"]
    STAGE2 --> CONS

Fase 1: El rol de JEV

En mis pruebas iniciales, TypeSafe Jev (jev-1.13.0) demostró ser ideal como primera línea de defensa: procesa lotes enteros en milisegundos, alcanza un 74% de precisión base sobre el texto normalizado y devuelve además un puntaje de confianza probabilística para cada campo.

El Enrutador: Mandar al LLM solo lo necesario

No quería quemar tokens en lo obvio. Diseñé un enrutador con reglas simples para detectar qué registros eran dudosos:

  • Cuando la categoría histórica del sistema entraba en contradicción directa con la predicción de Jev.
  • Cuando la confianza del clasificador caía por debajo de un umbral (por ejemplo, confianza < 0,60 en el componente específico).
  • Cuando Jev detectaba una falla pero no podía precisar el síntoma y caía en la opción genérica "otro".
  • Cuando había incoherencias lógicas internas.

En mi muestra de prueba, este enrutador aislaba los casos difíciles (alrededor de 246 registros) y los enviaba al segundo filtro: un verificador con modelos Flash configurado con Structured Outputs (JSON Schema estricto). Es el mismo patrón de capas que describo en JEV vs. Laya: el modelo rápido decide y el LLM solo entra cuando hay duda.


Comparando Modelos Flash: Gemini vs. DeepSeek vs. OpenAI

Sobre esa muestra de órdenes dudosas puse a competir tres alternativas representativas del mercado en tareas de extracción estructurada:

  1. Gemini 3.8 Flash
  2. DeepSeek Flash
  3. GPT-6 Luna (OpenAI)

Buscaba responder tres preguntas prácticas: ¿cuál es más rápido?, ¿cuál respeta mejor las reglas del esquema JSON? y ¿cuál es más consistente si le hacemos la misma pregunta varias veces?

A continuación los resultados de telemetría y ejecución que obtuve:

Tabla 1: Rendimiento comparativo en la muestra de casos dudosos (246 órdenes)

Métrica EvaluadaGemini 3.8 FlashDeepSeek FlashOpenAI GPT-6 Luna
Órdenes Respondidas con Éxito246 (100%)226 (91,9%) (20 caídas)246 (100%)
Fallos de Esquema (Enums inválidos)0 fallos2 lotes fallidos (enum inválido)0 fallos
Latencia Media por Lote (10 órdenes)6,93 s3,51 s28,46 s
Latencia Percentil 95 (p95)5,29 s5,17 s35,10 s
Tokens de Razonamiento (Thoughts)0 (Respuesta directa)0 (Thinking apagado)54.000 a 171.000 tokens
Costo Relativo por LoteMuy BajoMínimoModerado-Alto
Estabilidad Interna (3 pasadas)97,6% en detección falla99,1% (en lotes válidos)95,2% en detección falla

Lo que aprendí al comparar los modelos

1. La velocidad de DeepSeek Flash y el peligro de los esquemas rotos

DeepSeek Flash demostró una velocidad impresionante: apenas 3,5 segundos en promedio por lote. Para tareas de alto volumen, esa agilidad es tentadora.

Sin embargo, me topé con un problema crítico: falló al validar las opciones cerradas del enum. En dos lotes (20 órdenes en total), el modelo inventó nombres de componentes que no existían en la lista permitida.

[!WARNING] En un script de prueba interactivo esto parece menor, pero en un pipeline de datos automatizado, un valor fuera de catálogo hace que el validador rechace el lote completo. Si vas a usar un modelo con esta debilidad, estás obligado a programar lógica de reintento o un paso de normalización adicional.

2. El sobrecosto de los modelos de razonamiento (OpenAI)

GPT-6 Luna respondió todas las órdenes y respetó el formato, pero mostró una desventaja importante para este caso de uso: los tokens de razonamiento forzados.

  • El modelo generó decenas de miles de tokens de pensamiento invisible (thoughts) antes de emitir el JSON final.
  • Esto elevó la latencia media a casi 30-37 segundos por lote, tardando más de 12 minutos en procesar la muestra completa.
  • A pesar de todo ese tiempo pensando, su concordancia en la identificación de componentes complejos apenas rondó el 26% frente a la base. Para clasificar texto corto con categorías bien delimitadas, un modelo que “sobrepiensa” añade demora y costo sin aportar mejoras notables de calidad.

3. El balance de Gemini 3.8 Flash

Gemini 3.8 Flash se ubicó en el punto óptimo para esta tarea:

  • Cero fallos de esquema: Respetó el 100% de las opciones cerradas en un JSON con decenas de categorías jerárquicas.
  • Latencia ágil y estable: Entre 6 y 8 segundos por lote, sin saltos abruptos de tiempo.
  • Alta consistencia: En una prueba donde pasé la misma muestra 3 veces consecutivas, el modelo mantuvo una decisión idéntica en más del 97% de los casos para la clasificación principal.

¿En qué coinciden los modelos entre sí?

Cuando puse a los modelos a votar sobre las mismas órdenes dudosas, encontré un patrón fascinante sobre los límites del procesamiento de texto:

DecisiónAcuerdo entre Gemini y DeepSeekAcuerdo entre Gemini y OpenAI
Detección de Falla vs. Rutina94,7%92,7%
Tipo de Intervención93,4%90,7%
Modo o Síntoma83,5%79,6%
Componente Físico Específico57,7%76,7%

En las decisiones generales (¿ocurrió una falla?, ¿es correctivo o preventivo?), el consenso entre modelos independientes supera el 93%.

Pero en el momento en que les pides identificar la pieza exacta involucrada, el acuerdo cae drásticamente. ¿Por qué? Porque cuando el texto original es demasiado corto («ajuste mecánico por ruido»), ningún modelo de IA puede adivinar con certeza si el ruido venía del rodamiento, del acople o del ventilador.

Y eso me llevó al siguiente hallazgo del experimento.


El hallazgo del texto extendido: Más contexto vence a mejores prompts

Muchos sistemas de clasificación cometen el error de alimentar al modelo solo con el título o texto breve del registro. Para evaluar el impacto del contexto, tomé un subconjunto de 30 órdenes y corrí una prueba A/B:

  • Pase A: Solo el texto breve (máximo 40 caracteres).
  • Pase B: Texto breve + la bitácora o descripción extendida que el operario anotó en el sistema.
{
  "type": "bar-horizontal",
  "title": "IMPACTO DEL CONTEXTO EN LA CERTEZA DEL MODELO",
  "subtitle": "Comparativa A/B: Solo Texto Breve vs. Texto Breve + Bitácora (30 Órdenes)",
  "unit": "%",
  "max": 100,
  "categories": ["Pase A (Solo Texto Breve)", "Pase B (Texto + Bitácora)"],
  "series": [
    {
      "name": "Alta Certeza (Automatizable)",
      "data": [20, 80]
    },
    {
      "name": "Incertidumbre Alta (Riesgo)",
      "data": [70, 13]
    }
  ],
  "colors": ["#00ff9d", "#fc4269"]
}

Al incluir el texto de la bitácora:

  • El 30% de casos ambiguos desapareció por completo.
  • Más de la mitad de los componentes que estaban mal identificados cambiaron a la categoría correcta.
  • El costo en tokens apenas subió un 18% (menos de 2 centavos de dólar por cada mil órdenes).

La lección aquí es clara: Si tu texto original es escaso, no gastes días afinando el prompt; busca si en tu base de datos existe un campo de notas, comentarios o bitácora, límpialo e inclúyelo en el payload. La ganancia en precisión supera cualquier técnica de prompt engineering.


Escalando a producción: El benchmark masivo de 2.000 órdenes multiequipo

Un experimento con 200 o 300 órdenes de un solo tipo de equipo es un excelente punto de partida. Pero en ingeniería de software, la verdadera prueba de fuego ocurre cuando sueltas tu arquitectura sobre un lote masivo con datos heterogéneos y múltiples disciplinas en simultáneo.

Para validar si el tándem JEV + LLM aguantaba el ritmo a escala industrial, corrí un benchmark sobre 2.000 órdenes de trabajo reales y estratificadas, expandiendo la taxonomía a 4 disciplinas y 21 familias de equipos (equipos rotativos, estáticos y recipientes a presión, eléctricos e instrumentación/control).

Los números de rendimiento y calidad confirmaron la viabilidad del flujo en producción:

[!NOTE] Telemetría de Rendimiento: 198,43 segundos de reloj total (menos de 3 minutos y medio) a una velocidad sostenida de 10,08 órdenes procesadas por segundo sobre 2.000 OTs multiequipo.

{
  "type": "bar-horizontal",
  "title": "DISTRIBUCIÓN DEL SEMÁFORO DE CALIDAD (2.000 ÓRDENES)",
  "subtitle": "Muestra multiequipo estratificada en 4 disciplinas y 21 familias",
  "unit": "%",
  "max": 100,
  "categories": ["Verde (100% Automatizable)", "Amarillo (Certeza Media)", "Rojo (Triaje Manual)"],
  "series": [
    {
      "name": "Porcentaje de Lote",
      "data": [71.0, 13.25, 15.75]
    }
  ],
  "colors": ["#00ff9d", "#f59e0b", "#fc4269"]
}

Concordancia JEV vs. LLM en 2.000 registros

En este lote masivo, JEV procesó primero el 100% del volumen emitiendo su pre-clasificación rápida, y el LLM intervino como árbitro de normalización profunda. Los resultados de acuerdo fueron contundentes:

Dimensión EvaluadaConcordancia Global (2.000 OTs)Coincidencias UnánimesDiscrepancias
Detección de Falla (es_falla)93,25%1.865 órdenes135 órdenes (6,75%)
Tipo de Mantenimiento (tipo)91,95%1.839 órdenes161 órdenes (8,05%)

¿Qué pasó con las 161 discrepancias (8,05%)?

Al analizar las órdenes donde JEV y el LLM discreparon, encontré exactamente el valor de tener un árbitro en la segunda fase:

  • JEV leyó descripciones con lenguaje cotidiano como «Mantenimiento cheque descarga», «Cambio de sproker eje motriz» o «Inspección corrosión en tolva» y, por el vocabulario de rutina, tendió a predecir preventivo o predictivo.
  • El LLM, al evaluar el contexto completo de la bitácora y detectar los síntomas de daño («obstrucción severa», «desgaste de material», «corrosión confirmada»), corrigió el diagnóstico a correctivo.

Esto valida en fuego real la arquitectura híbrida: JEV absorbe y resuelve el 92% de las decisiones de inmediato a una velocidad sostenida de 10 órdenes por segundo, y el LLM solo tiene que actuar sobre ese 8% de frontera donde el lenguaje técnico requiere una segunda opinión experta.


Privacidad: Anonimizar antes de llamar a cualquier API

En cualquier entorno corporativo, la privacidad de los datos es prioritaria. No puedes enviar nombres de personas, códigos internos de activos o ubicaciones a APIs públicas sin control.

Para este experimento implementé un paso intermedio de sanitización en memoria:

  • Detección y reemplazo automático de identificadores de equipos por etiquetas genéricas ([TAG]).
  • Reemplazo de ubicaciones y plantas por [SITIO].
  • Enmascaramiento de nombres propios por [PERSONA] y fechas por [FECHA].
  • Compuerta de seguridad preventiva: Un escáner que revisa el texto final y cancela la ejecución si detecta algún dato sensible residual antes de realizar la petición HTTP.

Esto me permitió realizar todas las pruebas con total tranquilidad: la naturaleza técnica del problema se mantiene intacta para el modelo (un motor trabado o una fuga siguen siendo semánticamente iguales), pero la información confidencial nunca sale de tu infraestructura.


Conclusiones y recomendaciones prácticas

Si estás evaluando arquitecturas para clasificar grandes volúmenes de texto con LLMs en 2026, estas son mis conclusiones prácticas tras este experimento:

  1. El análisis exploratorio y los diccionarios no están muertos: Antes de mandar texto en bruto a un modelo o gastar tiempo en prompt engineering, haz un conteo de frecuencias de tus tokens y construye un diccionario de abreviaturas. En mi experimento, normalizar el texto aumentó de forma determinista un +5% la precisión del clasificador base sin costo adicional de inferencia.
  2. Usa clasificación en dos etapas: Procesar todo con un LLM de propósito general es costoso e innecesario. Un clasificador especializado rápido (como JEV) resuelve alrededor del 92% de los casos directos (en mi lote de 2.000 órdenes) a 10 órdenes por segundo; reserva los LLMs como verificadores para las discrepancias y la extracción fina de componentes.
  3. Prioriza la rigidez del esquema sobre unos pocos segundos de velocidad: Un modelo extremadamente veloz que rompe los enums cerrados te generará más trabajo de mantenimiento que un modelo ligeramente más pausado que garantiza el 100% de apego a tu esquema JSON.
  4. Desconfía de los modelos con reasoning forzado para clasificación: Para tareas estructuradas con taxonomías definidas, los modelos con razonamiento largo introducen latencia innecesaria y costos adicionales sin mejorar sustancialmente el resultado.
  5. El contexto mata la ambigüedad: Inyectar fragmentos de texto complementarios (bitácoras, notas o descripciones largas) es la forma más barata y efectiva de convertir registros dudosos en clasificaciones con semáforo verde.

Fuentes y lecturas recomendadas

Ideas, herramientas y lecturas de IA que merecen ser probadas

EXPLORAR SILO COMPLETO→