MÓDULO 15 · MLOPS: PIPELINES CON ZENML · 25 MIN

Artifacts, caché y linaje

Cuando un step termina, lo que devuelve no se pasa en memoria al siguiente: se guarda. Ese guardado automático es la pieza de la que cuelga todo lo demás — permite saltarse pasos que no han cambiado, saber qué versión de los datos produjo qué modelo, y comparar dos ejecuciones de hace meses. El coste es una regla: todo lo que cruza una frontera entre pasos tiene que ser serializable.
01 — Artifact
Lo que queda entre paso y paso

Cada salida de un step se persiste en el almacén de artifacts, versionada y ligada a la ejecución que la produjo. Eso convierte tres cosas difíciles en consultas triviales:

PreguntaSin artifactsCon artifacts
¿Qué datos entrenaron este modelo?Arqueología en el historial de Git y la memoria de alguienEstá enlazado
¿Cambió el dataset desde la última vez?Comparar ficheros a manoCambia el hash, cambia la versión
¿Puedo comparar el modelo de enero con el de febrero?Si alguien guardó los dosLos dos están, con su procedencia

La palabra clave es inmutable: un artifact no se sobrescribe. Si los datos de entrada cambian un solo bit, se genera una versión nueva y la anterior sigue existiendo. Eso es lo que permite «viajar en el tiempo» a la versión exacta de un dataset — y sin esa capacidad, depurar un error de predicción en producción es adivinar.

02 — Caché
Cuándo se salta un paso y cuándo no

Si un step se va a ejecutar con exactamente las mismas entradas y el mismo código que la última vez, su resultado ya está guardado: no hace falta volver a calcularlo. De ahí el patrón que se nota desde el primer día — cambias un hiperparámetro del entrenamiento y la carga y la limpieza de datos no se repiten.

La parte que hay que entender bien es qué invalida el caché:

Si cambia…¿Se reejecuta?
El código dentro de la función del stepSí
Un parámetro que se le pasaSí
La salida del step anteriorSí — y en cascada, todo lo que venga después
Código de otro step que no le afectaNo
NadaNo: se reutiliza el resultado

Y el caso que confunde a todo el mundo la primera vez: un step que nunca usa el caché. La causa casi siempre es que su salida cambia en cada ejecución aunque los datos sean los mismos — una marca de tiempo, un identificador aleatorio, un orden no determinista. El paso siguiente ve una entrada distinta y se reejecuta, y con él todo el resto.

// un timestamp dentro de un step invalida el caché de todo lo que venga detrás

La consecuencia práctica: los steps que quieras cachear deben ser puros — mismas entradas, misma salida, sin efectos secundarios. Escribir un fichero local desde dentro de un step es la forma más rápida de romper esa pureza sin darse cuenta.

03 — Linaje
Del modelo hacia atrás

Con los artifacts versionados y las dependencias declaradas, cada modelo arrastra su historia completa: qué datos crudos entraron, qué transformaciones se aplicaron, con qué código y en qué ejecución. Eso es el linaje, y su utilidad se ve en el peor momento posible: cuando un modelo en producción empieza a fallar y hay que averiguar si cambió el código o cambiaron los datos.

Sin linaje esa pregunta no tiene respuesta y se responde con opiniones. Con linaje es una comparación entre dos ejecuciones.

Auditoría La tabla de troubleshooting de esta parte del material llega desmontada: en vez de tres columnas —síntoma, causa, solución— sus filas aparecen sucesivas, con los encabezados «Causa» y «Solución» intercalados en mitad del listado, de modo que causas y soluciones quedan desalineadas de sus síntomas. La tabla de la sección 02 de arriba es la reconstrucción razonable. Es un defecto de conversión, no de contenido — pero en una tabla de depuración, desalinear causa y solución es peor que no tenerla. Y si el marcado se rompió ahí, conviene mirar con lupa los bloques de código: en este mismo material hay comandos que quedaron como texto corrido y uno que acabó convertido en un encabezado de sección.
Para hacer
Provocar un fallo de caché

Monta un pipeline mínimo de tres pasos y ejecútalo dos veces seguidas sin tocar nada: la segunda debería saltarse todo. Después haz tres experimentos, uno cada vez, volviendo a ejecutar entre medias: cambia un parámetro del último paso, cambia un comentario dentro del primero, y añade un datetime.now() a la salida del primero.

Anota qué se reejecuta en cada caso. El tercero es el que enseña de verdad: verás que un solo valor no determinista al principio del grafo tira abajo el caché de todo lo que viene después.