Lección 16 de 20 · Lectura y práctica
Diseño de la Arquitectura del Proyecto
Concepto claveDiseñar la arquitectura de una API de Machine Learning en producción es como planificar la construcción de un puente: no solo necesitas que sea funcional hoy, sino que debe soportar el tráfico futuro, mantenerse.
Esta es una lección del contenido anterior de Cursalo. Si ya estudiaste o compraste este curso, entra con tu cuenta para guardar tu progreso y abrir el resto de las clases. No necesitas comprar nada de nuevo.
Concepto clave
Diseñar la arquitectura de una API de Machine Learning en producción es como planificar la construcción de un puente: no solo necesitas que sea funcional hoy, sino que debe soportar el tráfico futuro, mantenerse estable bajo condiciones variables y permitir reparaciones sin interrumpir el servicio. En este contexto, arquitectura se refiere a la estructura organizada de componentes (modelo, API, base de datos, monitoreo) y cómo interactúan para servir predicciones de manera confiable.
Una arquitectura bien diseñada para FastAPI y ML debe considerar tres pilares: escalabilidad (manejar más peticiones sin degradación), mantenibilidad (facilitar actualizaciones del modelo) y observabilidad (monitorear rendimiento y errores). Imagina un restaurante de comida rápida: la cocina (modelo) prepara platos (predicciones), los camareros (API) toman pedidos y entregan resultados, y los gerentes (sistemas de monitoreo) supervisan que todo funcione sin problemas. Sin esta estructura, aumentar la clientela o cambiar el menú sería caótico.
Cómo funciona en la práctica
Vamos a desglosar el diseño paso a paso para un proyecto típico de API ML con FastAPI. Primero, identifica los componentes esenciales: 1) Modelo ML entrenado y serializado (ej., con pickle o joblib), 2) API FastAPI con endpoints para predicciones y salud, 3) Validación de datos usando Pydantic para asegurar entradas correctas, 4) Logging y monitoreo con herramientas como Prometheus o logs estructurados, y 5) Configuración mediante variables de entorno para diferentes entornos (desarrollo, producción).
En la práctica, comienza definiendo la estructura de carpetas. Por ejemplo, crea directorios como app/ para el código de la API, models/ para los archivos del modelo, y tests/ para pruebas. Luego, configura FastAPI con routers para organizar endpoints (ej., /predict para predicciones, /health para verificar estado). Integra el modelo cargándolo al iniciar la aplicación para evitar latencias en cada petición. Finalmente, añade middlewares para logging y manejo de errores, asegurando que cada paso sea trazable.
Codigo en accion
Aquí tienes un ejemplo funcional de la estructura inicial y un endpoint básico. Antes de refactorizar, un código simple podría verse desorganizado; después, aplicamos mejores prácticas.
Antes: Código monolítico en un solo archivo, sin validación clara.
from fastapi import FastAPI
import pickle
app = FastAPI()
model = pickle.load(open("model.pkl", "rb"))
@app.post("/predict")
async def predict(data: dict):
# Sin validación, propenso a errores
result = model.predict([data["features"]])
return {"prediction": result.tolist()}
Después: Arquitectura modular con validación y carga eficiente del modelo.
# app/main.py
from fastapi import FastAPI
from app.routers import predict, health
from app.models.load_model import load_ml_model
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = FastAPI(title="ML API en Producción")
ml_model = load_ml_model() # Carga al inicio
app.include_router(predict.router)
app.include_router(health.router)
@app.on_event("startup")
async def startup_event():
logger.info("API ML iniciada con modelo cargado")
Errores comunes
- Error 1: Cargar el modelo en cada petición, lo que causa latencia alta. Solución: Carga el modelo una vez al iniciar la aplicación, como en el ejemplo anterior con
load_ml_model(). - Error 2: Falta de validación de entradas, llevando a predicciones erróneas o caídas. Solución: Usa Pydantic para definir esquemas estrictos; por ejemplo, crea una clase
PredictionRequestcon tipos y rangos válidos. - Error 3: No implementar logging o monitoreo, dificultando la depuración en producción. Solución: Integra logging estructurado (ej., con JSON) y métricas básicas como tasa de predicciones y errores.
- Error 4: Mezclar configuración hardcodeada, imposibilitando despliegues en distintos entornos. Solución: Usa variables de entorno con librerías como
pydantic-settingspara gestionar configuraciones. - Error 5: Diseñar endpoints sin versionado, complicando actualizaciones sin romper clientes existentes. Solución: Incluye versión en la ruta, como
/api/v1/predict, para futuros cambios.
Checklist de dominio
- ¿Has definido una estructura de carpetas clara (ej., app/, models/, tests/)?
- ¿Cargas el modelo ML una sola vez al inicio para optimizar rendimiento?
- ¿Usas Pydantic para validar todas las entradas de la API?
- ¿Has implementado logging básico para rastrear peticiones y errores?
- ¿Configuras la aplicación con variables de entorno, no con valores hardcodeados?
- ¿Incluyes endpoints de salud (
/health) para monitoreo? - ¿Planificas la escalabilidad, como usar workers con Gunicorn para producción?
Diseña y configura la estructura base de tu API ML
Sigue estos pasos para crear la arquitectura inicial de un proyecto FastAPI para ML en producción. Asegúrate de tener Python 3.8+ instalado.
- Paso 1: Crea una carpeta para el proyecto, por ejemplo
ml_api_project, y dentro, las subcarpetas:app,models,tests. - Paso 2: En
app/, crea los archivos:main.py(punto de entrada),routers/predict.pyyrouters/health.pypara los endpoints, ymodels/load_model.pypara cargar el modelo. - Paso 3: En
models/load_model.py, escribe una funciónload_ml_model()que simule la carga de un modelo (puedes usar un placeholder como un diccionario si no tienes un modelo real). - Paso 4: En
app/routers/predict.py, define un router FastAPI con un endpoint POST/predictque use Pydantic para validar una entrada con al menos dos características numéricas. - Paso 5: Configura
app/main.pypara incluir los routers, cargar el modelo al inicio, y añadir logging básico. Prueba ejecutando conuvicorn app.main:app --reload.
Pistas
- Usa
from pydantic import BaseModelpara crear clases de validación en los routers. - En
load_ml_model(), puedes devolver un objeto simple como{"model": "placeholder"}para simular, enfocándote en la estructura. - Asegúrate de que las importaciones en
main.pyreferencien correctamente los módulos dentro deapp/.
Evalua tu comprension
Completa el quiz interactivo de arriba para ganar XP.