MLOps: del notebook al pipeline de producción
El modelo funciona en mi portátil
Esa frase debería provocar la misma reacción que “funciona en mi máquina” provoca en un ingeniero de software. Porque el problema es idéntico: un entorno controlado, datos limpios, un único usuario, cero concurrencia. El notebook de Jupyter donde un data scientist logra un AUC de 0.94 es un artefacto de investigación, no un sistema de producción.
Y sin embargo, la mayoría de equipos de datos intentan poner en producción exactamente eso. Un notebook convertido en script, ejecutado en un cron, sin versionado de datos, sin monitorización de drift, sin rollback posible. Funciona hasta que deja de funcionar, y cuando deja de funcionar nadie sabe por qué.
Este whitepaper documenta lo que hemos aprendido desplegando modelos ML en producción para clientes en logística, finanzas y retail. No es una guía teórica de MLOps. Es un mapa de las trampas reales que hemos encontrado y las soluciones que han sobrevivido al contacto con la realidad.
El abismo entre experimentación y producción
Hay un abismo entre un modelo que funciona y un modelo en producción. No es un salto técnico menor. Es una transformación completa del flujo de trabajo, los artefactos, las garantías y las responsabilidades.
En experimentación, el data scientist controla todo: los datos, el entorno, el timing. Puede reejecutar un notebook completo, cambiar un hiperparámetro, regenerar features manualmente. El output es un número (accuracy, F1, AUC) y una conclusión (“funciona” o “no funciona”).
En producción, nada de eso aplica.
Los datos llegan en tiempo real, con formatos inconsistentes, valores nulos que no estaban en el dataset de entrenamiento, y distribuciones que cambian sin previo aviso. El modelo tiene que responder en milisegundos, no en minutos. Y si falla, no hay un humano mirando un notebook para corregirlo: hay un sistema downstream que recibe una predicción errónea y actúa en consecuencia.
Hemos identificado cuatro brechas fundamentales entre experimentación y producción:
Brecha de reproducibilidad. El notebook original usó pandas 1.5.3, scikit-learn 1.2.1, y un dataset descargado “ayer”. Tres meses después, nadie puede reproducir el resultado exacto. Las dependencias han cambiado, el dataset ya no existe en la misma forma, y el random seed no se registró. Sin reproducibilidad, no hay auditabilidad, y sin auditabilidad, no hay confianza.
Brecha de datos. El modelo se entrenó con un snapshot estático. En producción, los datos son un stream. Las distribuciones cambian. Nuevas categorías aparecen. Valores que eran raros se vuelven comunes. El modelo no sabe que el mundo ha cambiado, y sigue prediciendo como si estuviera en enero cuando estamos en agosto.
Brecha de monitorización. En experimentación, la métrica es un número que calculas al final. En producción, necesitas saber en tiempo real si el modelo sigue funcionando correctamente. No solo si devuelve una respuesta (eso es health check básico), sino si la calidad de esa respuesta se mantiene dentro de parámetros aceptables.
Brecha de costes. Un notebook que tarda 20 minutos en entrenar un modelo no genera facturas preocupantes. Un pipeline que reentrena diariamente en GPUs cloud, procesa millones de inferencias, y almacena terabytes de features si las genera. Y la factura llega al final del mes, cuando ya es tarde para optimizar.
Model registry: el control de versiones que faltaba
El primer componente de un sistema MLOps maduro es un model registry. Es el equivalente a un repositorio Git para modelos, pero con metadatos específicos de ML: hiperparámetros, métricas de evaluación, dataset de entrenamiento, linaje de datos.
Nosotros usamos MLflow como registry central. No porque sea perfecto (no lo es), sino porque es open source, tiene integraciones con prácticamente todo, y la curva de aprendizaje es asumible. Alternativas como Weights & Biases o Neptune ofrecen mejor UX, pero el vendor lock-in nos preocupa para proyectos de largo plazo.
Lo que registramos por cada modelo:
- Versión del código de entrenamiento (commit hash de Git)
- Hash del dataset de entrenamiento (para reproducibilidad)
- Hiperparámetros completos
- Métricas de evaluación (no solo la métrica principal, todas las relevantes)
- Dependencias y versiones exactas (requirements.txt congelado)
- Fecha de entrenamiento y duración
- Infraestructura utilizada (tipo de instancia, GPU, RAM)
Con esta información, cualquier modelo registrado es reproducible. Podemos volver a entrenar la versión 23 exactamente igual que se entrenó originalmente. Podemos comparar la versión 23 con la 24 en cualquier dimensión. Y podemos hacer rollback a la versión 22 si la 23 introduce una regresión.
La disciplina clave es tratar los modelos como artefactos inmutables. Un modelo registrado nunca se modifica. Si necesitas cambiar algo, creas una nueva versión. Esto parece obvio, pero hemos visto equipos que sobreescriben modelos en producción directamente porque “es un cambio pequeño”. Esos cambios pequeños son los que generan las incidencias más difíciles de diagnosticar.
Promoción por etapas
No todo modelo registrado va a producción. Implementamos un flujo de promoción con tres etapas:
Staging. El modelo pasa por una batería de tests automatizados: validación de schema de entrada y salida, tests de rendimiento (latencia p50, p95, p99), tests de regresión contra un golden dataset, y tests de integración con el pipeline de datos. Si falla cualquier test, no avanza.
Canary. El modelo recibe un porcentaje pequeño del tráfico de producción (típicamente un 5%). Comparamos sus predicciones contra el modelo en producción actual. Si las métricas de negocio (no solo las métricas de ML) son iguales o mejores durante 48 horas, avanza. Si hay degradación, rollback automático.
Production. El modelo recibe el 100% del tráfico. Pero el modelo anterior se mantiene desplegado y listo para recibir tráfico durante 7 días. El rollback es un cambio de configuración, no un redespliegue.
Este flujo nos ha evitado al menos cuatro incidencias graves en el último año. En un caso, un modelo de clasificación de documentos pasó staging correctamente pero mostró una degradación del 12% en accuracy durante la fase canary. El problema era un cambio en la distribución de tipos de documento que solo se manifestaba con tráfico real. Sin la fase canary, ese modelo habría estado en producción generando errores silenciosos.
Feature stores: la pieza más infravalorada
Si le preguntas a un data scientist que es lo más importante para un buen modelo, dirá “los datos”. Si le preguntas qué herramienta de MLOps es la más importante, probablemente dirá “el registry” o “el pipeline de entrenamiento”. Rara vez dice “el feature store”.
Y sin embargo, en nuestra experiencia, el feature store es la pieza que más impacto tiene en la operativa diaria de un sistema ML en producción.
Un feature store resuelve tres problemas:
Consistencia train-serve. El problema número uno de los modelos en producción es que las features que el modelo recibe en inferencia son diferentes de las que recibió en entrenamiento. No porque los datos sean diferentes, sino porque el código que calcula las features es diferente. El script de entrenamiento calcula la media móvil de 30 días de una forma. El servicio de inferencia la calcula de otra. O peor: el servicio de inferencia no la calcula, la recibe de otro sistema que tiene su propia lógica.
Con un feature store, la definición de cada feature existe en un único lugar. El pipeline de entrenamiento lee de ahí. El servicio de inferencia lee de ahí. Misma feature, mismo cálculo, siempre.
Reutilización de features. Sin un feature store, cada equipo calcula sus propias features. El equipo de fraude calcula “número de transacciones en los últimos 7 días”. El equipo de marketing calcula exactamente lo mismo con un nombre diferente. El equipo de riesgo lo calcula con una ventana de 30 días. Tres pipelines, tres costes de cómputo, tres oportunidades de inconsistencia. Con un feature store centralizado, una feature se calcula una vez y la usan todos.
Servicio en tiempo real. Algunas features necesitan estar disponibles con latencia de milisegundos para inferencia online. Calcularlas on-the-fly es demasiado lento. Un feature store mantiene las features precalculadas en un almacén de baja latencia (típicamente Redis o DynamoDB) y las actualiza de forma continua o batch según el caso.
Usamos Feast como feature store en la mayoría de proyectos. Es open source, soporta tanto batch como online serving, y se integra bien con el ecosistema que ya tenemos (Spark, Kafka, PostgreSQL). Para proyectos más sencillos donde solo necesitamos batch features, a veces una tabla materializada en BigQuery o Snowflake es suficiente. No todo necesita la complejidad completa de un feature store dedicado.
El coste de no tener feature store
En un proyecto de predicción de demanda para un cliente de logística, desplegamos el modelo sin feature store. Las features se calculaban en un script Python que se ejecutaba antes de cada inferencia batch.
A los dos meses, descubrimos que una feature clave (volumen medio por ruta en los últimos 90 días) se calculaba de forma diferente en entrenamiento y en inferencia. El script de entrenamiento usaba datos corregidos post-hoc. El script de inferencia usaba datos brutos. La diferencia era sutil (menos del 3% en la mayoría de rutas), pero en rutas de bajo volumen generaba predicciones un 40% más altas de lo real.
Reconstruir las features correctamente, validar que train y serve eran consistentes, y reentrenar el modelo nos costó tres semanas. Implementar Feast nos costó dos semanas. La lección fue cara pero clara.
Monitorización: más allá del health check
Un modelo en producción que devuelve HTTP 200 no significa que funcione correctamente. Significa que no ha crasheado. La monitorización de modelos ML tiene tres capas, y la mayoría de equipos solo implementan la primera.
Capa 1: Monitorización de infraestructura
Latencia, throughput, errores, uso de CPU/GPU/memoria. Esta es la monitorización que cualquier servicio web necesita. Usamos Prometheus + Grafana para esto, con alertas en PagerDuty. Nada específico de ML aquí.
Capa 2: Monitorización de datos (data drift)
Los datos de entrada al modelo cambian con el tiempo. A veces gradualmente (drift estacional), a veces abruptamente (un cambio de política de un proveedor que altera el formato de datos). La monitorización de drift detecta cuando la distribución de los datos de entrada se ha desviado significativamente de la distribución de entrenamiento.
Implementamos monitorización de drift con dos métricas complementarias:
PSI (Population Stability Index) para features categóricas. Un PSI por encima de 0.2 indica drift significativo. Por encima de 0.25, generamos una alerta automática.
KS test (Kolmogorov-Smirnov) para features numéricas. Un p-valor por debajo de 0.01 con un tamaño de efecto relevante dispara la alerta.
No monitorizamos todas las features. Monitorizamos las 10-15 features más importantes según la importancia del modelo (SHAP values del último entrenamiento). Monitorizar 200 features genera ruido y falsos positivos. Monitorizar las 15 que realmente importan te da señales accionables.
Cuando detectamos drift significativo, no reentrenamos automáticamente. Primero investigamos. El drift puede ser un cambio real del negocio (y el modelo necesita adaptarse) o un problema de datos (y los datos necesitan corregirse). Reentrenar automáticamente sobre datos corruptos es peor que no reentrenar.
Capa 3: Monitorización de rendimiento del modelo
Esta es la capa más valiosa y la más difícil de implementar. Requiere ground truth: saber cuál era la respuesta correcta para poder compararla con la predicción del modelo.
En algunos casos, el ground truth llega rápido. Un modelo de clasificación de tickets se puede evaluar cuando un agente humano resuelve el ticket y confirma o corrige la categoría. En otros casos, tarda semanas o meses. Un modelo de predicción de churn no se puede evaluar hasta que pasan los 90 días de la ventana de predicción.
Para los casos de evaluación lenta, usamos métricas proxy: el modelo predice churn, y si en las dos semanas siguientes el cliente reduce su actividad un 50%, lo contamos como señal de validación parcial. No es ground truth perfecto, pero es mejor que volar a ciegas durante 90 días.
Registramos todas las predicciones con su timestamp y su input hash. Cuando llega el ground truth, lo emparejamos y calculamos métricas reales. Esto alimenta un dashboard que muestra la evolución de la accuracy real del modelo a lo largo del tiempo.
Pipeline de entrenamiento: automatización con guardrails
El reentrenamiento automático es uno de los temas más peligrosos de MLOps. Hecho bien, mantiene los modelos actualizados sin intervención humana. Hecho mal, introduce regresiones silenciosas que degradan el servicio durante semanas antes de que alguien se dé cuenta.
Nuestro pipeline de entrenamiento tiene tres modos:
Programado. Reentrenamiento semanal o mensual con datos frescos. El modelo nuevo pasa por el flujo de promoción completo (staging, canary, producción). Es el modo por defecto para modelos estables.
Disparado por drift. Cuando la capa 2 de monitorización detecta drift significativo y un humano confirma que es un cambio real del negocio, se dispara un reentrenamiento. El modelo nuevo se compara explícitamente con el actual en el segmento donde se detectó el drift.
Manual. Un data scientist decide reentrenar porque hay nuevas features disponibles, porque el modelo de base ha sido actualizado, o porque se ha identificado un sesgo que corregir. Este modo bypasea el trigger automático pero no bypasea el flujo de promoción.
Lo que nunca hacemos es reentrenamiento en bucle cerrado: drift detectado automáticamente produce reentrenamiento que produce despliegue automático. Sin un humano en algún punto de la cadena, el riesgo de degradación silenciosa es demasiado alto.
Versionado de datos
Cada entrenamiento debe poder responder a la pregunta: con qué datos exactamente se entrenó este modelo? No “con los datos de enero” sino “con el snapshot 2025-01-15T08:30:00Z del dataset customer_features_v3, hash SHA256 a1b2c3d4”.
Usamos DVC (Data Version Control) para esto. DVC funciona como Git pero para datasets grandes. Los datos se almacenan en S3, y DVC mantiene los hashes y metadatos en Git. Cada commit de entrenamiento incluye el lockfile de DVC, lo que garantiza que podemos reproducir exactamente el dataset de cualquier versión de modelo.
Para datos que cambian con alta frecuencia (features en streaming), usamos snapshots puntuales en Delta Lake. Cada snapshot es una tabla inmutable que se puede referenciar por timestamp. No es tan limpio como DVC para datasets estáticos, pero funciona para nuestro caso de features que se actualizan cada hora.
Optimización de costes: dónde se va el dinero
Los costes de MLOps tienen cuatro componentes principales, y la intuición sobre cuál es el más caro suele ser errónea.
Cómputo de entrenamiento. Es el coste más visible pero raramente el más alto. Un entrenamiento semanal en una GPU A100 durante 4 horas cuesta unos $48 en AWS (instancia p4d.24xlarge spot). Son $200 al mes. No es trivial, pero no es el problema.
Cómputo de inferencia. Aquí es donde se concentra el coste para la mayoría de modelos. Un modelo que procesa 10 millones de inferencias al día necesita infraestructura dedicada siempre encendida. Si el modelo requiere GPU para inferencia, el coste puede superar los $2,000 mensuales fácilmente.
La optimización clave aquí es la cuantización y la destilación. Un modelo cuantizado a INT8 ocupa la mitad de memoria y es 2-3x más rápido en inferencia, con una degradación típica de menos del 1% en accuracy. Para modelos que no requieren la máxima precisión, es una optimización obvia que muchos equipos no implementan.
Otra optimización: batching de inferencias. En lugar de procesar cada petición individualmente, agrupamos peticiones en microbatches de 32 o 64. Esto aprovecha mejor el paralelismo de la GPU y puede reducir el coste de inferencia un 40-60%.
Almacenamiento de features. El feature store online (Redis, DynamoDB) puede ser sorprendentemente caro si no se gestiona activamente. Un feature store con 50 millones de entidades y 200 features por entidad, actualizado cada hora, puede costar más de $1,500 mensuales en DynamoDB on-demand. La optimización aquí es ser selectivo: solo las features que necesitan latencia de milisegundos van al store online. El resto se sirven desde el store offline (S3 + Athena) con latencias de segundos.
Almacenamiento de datos y logs. Los logs de monitorización, las predicciones históricas, los snapshots de datos, los artefactos de entrenamiento. Todo suma. Implementamos políticas de retención agresivas: logs detallados 30 días, logs agregados 1 año, predicciones 6 meses (salvo que haya requisitos regulatorios), artefactos de entrenamiento solo para las últimas 10 versiones.
Caso real: de $4,200/mes a $1,800/mes
Para un cliente de retail con tres modelos en producción (recomendación de productos, predicción de demanda, detección de fraude), el coste mensual de MLOps era de $4,200.
Identificamos tres optimizaciones:
- Cuantización del modelo de recomendación de FP32 a INT8. Reducción del 45% en coste de inferencia para ese modelo.
- Migración del feature store de DynamoDB on-demand a provisioned con auto-scaling. Reducción del 35% en coste de almacenamiento.
- Consolidación de los tres pipelines de entrenamiento en una única instancia spot con scheduling. Los tres modelos se entrenaban en GPU dedicadas separadas, cuando en realidad nunca se entrenaban simultáneamente.
Resultado: $1,800/mes. Un 57% de reducción. El esfuerzo de implementación fue de dos semanas de un ingeniero senior.
Orquestación: pegamento que sostiene todo
El pipeline de MLOps tiene muchas piezas móviles: extracción de datos, cálculo de features, entrenamiento, evaluación, registro, despliegue, monitorización. Orquestar todo esto requiere un sistema que maneje dependencias, reintentos, paralelismo y estado.
Usamos Prefect para orquestación. Probamos Airflow primero (lo hace todo el mundo, debe ser la respuesta correcta) y lo abandonamos después de tres meses. Airflow es excelente para ETL batch clásico, pero su modelo de programación basado en DAGs estáticos encaja mal con los workflows de ML, que son más dinámicos: decide si reentrenar basándote en los resultados de la monitorización, elige el dataset según la fecha, selecciona hiperparámetros basándose en el rendimiento histórico.
Prefect nos permite definir flujos como código Python normal con decoradores, tiene reintentos configurables por tarea, soporta ejecución concurrente nativa, y tiene un UI que los data scientists realmente usan (a diferencia del UI de Airflow, que solo usaba el equipo de infra).
Un detalle que subestimamos al principio: la importancia de las notificaciones. Cuando un pipeline falla a las 3 de la mañana, alguien tiene que enterarse. Cuando un reentrenamiento produce un modelo con métricas peores que el actual, alguien tiene que decidir si se despliega o no. Integramos Prefect con Slack y PagerDuty, con diferentes niveles de severidad: fallo de pipeline va a Slack, fallo de despliegue va a PagerDuty.
Testing: lo que nadie quiere hacer
Los modelos ML necesitan tests. No solo validación en un hold-out set, sino tests de ingeniería que verifican que el sistema completo funciona correctamente.
Tests de esquema. Verifican que el input al modelo tiene el formato esperado. Tipos correctos, rangos válidos, valores no nulos donde se requieren. Estos tests se ejecutan en cada inferencia y rechazan inputs inválidos antes de que lleguen al modelo. Triviales de implementar, pero evitan una categoría entera de errores silenciosos.
Tests de regresión. Un golden dataset de 500-1000 ejemplos con predicciones correctas conocidas. Cada nuevo modelo debe producir predicciones dentro de un margen aceptable para este dataset. Si un modelo nuevo clasifica correctamente el 92% del golden set cuando el modelo actual clasifica el 95%, hay una regresión y el modelo no se promueve.
Tests de rendimiento. Latencia p99 por debajo de un umbral. Throughput mínimo en inferencias por segundo. Uso de memoria dentro de límites. Estos tests se ejecutan en el entorno de staging con carga sintética antes de cualquier promoción.
Tests de sesgo. Verifican que el modelo no discrimina por variables protegidas. Calculamos métricas de equidad (demographic parity, equal opportunity) para cada versión del modelo. Si hay una degradación en equidad, el modelo se revisa manualmente antes de desplegarse. Este tipo de test es cada vez más relevante con regulaciones como el AI Act de la UE.
Tests de integración. El modelo completo, con su preprocesamiento, inferencia y postprocesamiento, se ejecuta end-to-end con datos sintéticos que cubren los casos edge conocidos. Estos tests verifican que la integración entre componentes funciona, no solo que cada componente individual pasa sus tests unitarios.
Organización: quiénes son responsables de qué
El aspecto más difícil de MLOps no es técnico. Es organizativo. Quién es responsable del modelo en producción? El data scientist que lo entrenó? El ingeniero de ML que lo desplegó? El equipo de plataforma que mantiene la infraestructura?
Hemos visto tres modelos organizativos y sus resultados:
Modelo 1: el data scientist hace todo. El data scientist entrena, despliega y monitoriza. Resultado: el data scientist pasa el 70% de su tiempo en operaciones y el 30% en ciencia de datos. Frustración alta, calidad operativa baja.
Modelo 2: separación completa. Data scientists entrenan, ingenieros de ML despliegan. Resultado: una cola de 3-4 semanas entre “el modelo está listo” y “el modelo está en producción”. Comunicación por tickets. Pérdida de contexto en cada handoff.
Modelo 3: equipo integrado con plataforma compartida. Data scientists trabajan con ingenieros de ML en el mismo equipo. Una plataforma de MLOps compartida reduce la fricción operativa. El data scientist puede desplegar a staging sin ayuda. La promoción a producción requiere aprobación del ingeniero de ML. Resultado: time-to-production de 2-3 días, calidad operativa alta, data scientists contentos.
El modelo 3 es el que recomendamos, con una condición: la plataforma de MLOps tiene que ser lo suficientemente buena para que el data scientist pueda usarla sin ser un experto en Kubernetes o Docker. Si desplegar un modelo requiere escribir un Dockerfile, configurar un Helm chart, y crear un Ingress, el data scientist va a buscar atajos. Y esos atajos terminan en producción.
Checklist de madurez MLOps
Para cerrar con algo accionable, esta es la lista que usamos para evaluar la madurez MLOps de una organización. Cada ítem es binario: lo tienes o no lo tienes.
Nivel 1 (Básico):
- Los modelos están versionados en un registry
- Las dependencias están congeladas por versión de modelo
- Existe un proceso de despliegue documentado (aunque sea manual)
- Hay monitorización de infraestructura básica (latencia, errores, uptime)
Nivel 2 (Operativo):
- El despliegue es automatizado con promoción por etapas
- Hay monitorización de data drift en features críticas
- Los datos de entrenamiento están versionados
- Existe un pipeline de reentrenamiento (aunque sea manual-triggered)
- Hay tests de regresión automáticos
Nivel 3 (Avanzado):
- Feature store compartido con consistencia train-serve
- Monitorización de rendimiento del modelo con ground truth
- Reentrenamiento programado con guardrails automáticos
- Tests de sesgo y equidad en el pipeline de promoción
- Costes de MLOps monitorizados y optimizados activamente
- Rollback automático basado en métricas de producción
La mayoría de equipos están en nivel 1. Los que llegan a nivel 2 ya ven una mejora dramática en la fiabilidad de sus modelos. El nivel 3 es donde queremos llevar a todos nuestros clientes, pero es un camino, no un salto.
Si tu equipo de datos está luchando con la brecha entre experimentación y producción, el primer paso no es comprar una plataforma de MLOps. Es sentarse con los data scientists y los ingenieros, mapear el flujo actual de un modelo desde notebook hasta producción, identificar los tres puntos de mayor fricción, y resolverlos. La plataforma viene después.
En abemon, ayudamos a equipos a diseñar e implementar flujos MLOps adaptados a su escala y madurez. No vendemos la arquitectura ideal. Construimos la arquitectura que tu equipo puede operar hoy, con un camino claro hacia donde necesitas estar mañana. Porque un sistema MLOps que nadie usa es peor que un notebook ejecutado a mano: al menos el notebook, alguien lo entiende.