El diagnóstico del material es certero y merece leerse entero: celdas ejecutadas en desorden,
variables globales que se sobrescriben, y datos cargados de rutas locales con nombres como
data_final_v3_revisado.csv. Nada de eso falla mientras la persona que lo escribió esté
delante — y todo falla en cuanto no lo está.
| Lo que oculta un notebook | Cuándo aparece |
|---|---|
| El orden real en que hay que ejecutar las cosas | Al reiniciar el kernel |
| De dónde salieron los datos | Al intentar reproducir el resultado |
| Qué versiones de librerías se usaron | En la máquina de otra persona |
| Qué pasos manuales hubo entre celdas | Siempre demasiado tarde |
La frase que resume el módulo entero: si no puedes volver a entrenar tu modelo exactamente igual dos meses después, no tienes un producto de software, tienes un experimento desechable.
Una unidad lógica: cargar, validar, entrenar, evaluar. Entradas y salidas declaradas y tipadas.
una responsabilidad, ni más ni menosEl plano que conecta los steps. Define el flujo de datos, no la lógica.
solo conecta: nada de procesamiento aquíDónde y cómo se ejecuta: orquestador, almacén de artifacts, desplegador.
infraestructura, fuera del código PythonLa separación entre el segundo y el tercero es la idea que hace portátil todo lo demás: el pipeline dice qué pasa, el stack dice dónde. Cambiar de portátil a la nube es cambiar el stack, no el código.
// el pipeline conecta; si tiene lógica dentro, es un step disfrazado@step
def cargador_de_datos() -> pd.DataFrame:
...
@step
def entrenador(df: pd.DataFrame) -> LinearRegression:
...
@pipeline
def entrenamiento():
datos = cargador_de_datos()
modelo = entrenador(datos)
Esas anotaciones de tipo hacen tres cosas que en un script normal no harían nada:
| Qué habilita | Por qué |
|---|---|
| Detectar desajustes entre pasos | Si un step devuelve algo que el siguiente no acepta, falla al construir el grafo y no a mitad del entrenamiento |
| Serializar correctamente cada salida | El framework elige cómo guardar un DataFrame, un modelo de scikit-learn o un array según su tipo |
| Mostrar cada artifact en el panel | Sabe qué visualizador aplicar |
Y de ahí sale la restricción que más sorprende al empezar: todo lo que sale de un step tiene que poder guardarse. Una conexión abierta a una base de datos, un cliente de API o un objeto con estado no viajan entre pasos. Si un step necesita una conexión, la abre dentro y devuelve datos.
from zenml import step, pipeline y la unidad de
«ZenML Avanzado» importa from zenml.steps import step, Output y
from zenml.pipelines import pipeline, que es la forma anterior. No hay una sola línea
que avise de que una sustituye a la otra. Es el mismo patrón que este curso ya tiene fichado con
LangChain en el Módulo 10: un material a medio actualizar es peor que uno viejo, porque no se
sabe de qué parte fiarse. ¿Cuál de las dos rutas funciona sin avisos en tu versión instalada?
Es una línea de pip show zenml y un import de prueba.
Coge un script o notebook tuyo de ML y, sin escribir código todavía, dibuja sus fronteras: qué bloques hay, qué entra y qué sale de cada uno, y con qué tipo. No busques la partición perfecta; busca los sitios donde no sabrías decir qué entra o qué sale.
Esos son los que importan: cada frontera que no puedes describir es una dependencia oculta —una variable global, una ruta local, un paso manual— y es exactamente lo que hará fallar el código en la máquina de otra persona.