Skip to content

English · Español

00 — Motivación: de demo a servicio

🇪🇸 La tesis de esta fase: lo que distingue una demo de un servicio no es escala — es trazabilidad y bloqueo de regresiones. Si no puedes responder "¿qué checkpoint corrigió esa conjugación?", "¿con qué corpus se entrenó?", "¿cuánto cuesta cada corrección?", "¿por qué este modelo entró a producción y aquel no?", no tienes un servicio — tienes un script con suerte.


La pregunta que esta fase responde

Tras cerrar la Fase 37, Borja tiene un stack de tutor de gramática funcionando: tokenizador BPE entrenado sobre frases de verbos en inglés (Fase 11), Mini-GPT entrenado sobre la rejilla de 20 verbos × 5 tiempos × 3 personas (Fase 18), variantes INT8 + LoRA (Fases 26 + 28), servidor de inferencia (src/miniserve/, Fase 33), stack de observabilidad (src/miniobserve/, Fase 34), auditoría de seguridad (Fase 37). Todo eso funciona. Nada de ello es operable en el sentido que un servicio real requiere.

La pregunta de la Fase 38 es operacional:

"Dentro de seis meses, cuando un aprendiz reporte que el tutor aceptó 'he goed' como correcto, ¿puedes reconstruir qué ocurrió?"

La respuesta requiere cinco artefactos que ninguna fase anterior produjo:

  1. Un registry — cada modelo de tutor de gramática que ha servido tráfico, indexado por SHA del contenido.
  2. Un lineage — para cada modelo registrado, la cadena hacia atrás hasta el hash DVC del corpus de verbos, el SHA git del código, los hiperparámetros y la semilla.
  3. Una estrategia de tráfico — una forma deliberada y con nombre de pasar de un tutor a otro (A/B, shadow, canary).
  4. Una señal de drift — un número que te diga cuándo los verbos y tiempos que los aprendices envían realmente ya no se parecen a aquello con lo que entrenaste.
  5. Un gate de CI — automatización que rechaza promover un checkpoint cuya precisión de conjugación de la Fase 20 regrese.

Más un sexto, opcional pero barato:

  1. Un número de coste por calidad — para que "lo nuevo es mejor" pueda falsearse con "lo nuevo también es más caro de lo que justifica el salto de calidad".

Por qué esto es infraestructura, no framework

Hay toda una industria de herramientas MLOps que prometen resolverte esto: MLflow, Weights & Biases, Kubeflow, Sagemaker Model Registry, Vertex AI Model Garden, Determined.ai, ClearML, DVC Studio, Comet, Neptune y una larga cola de startups. La mayoría funcionan. La Fase 38 envuelve las dos que ya fijamos (MLflow + DVC, según §A8) y construye el pegamento mínimo a su alrededor. Dos razones:

  1. La brecha semántica. "¿Qué es un modelo registrado?" tiene una respuesta distinta en cada herramienta. Algunas tratan el artefacto como un tarball; otras como un directorio; otras como un manifest. Algunas trazan lineage automáticamente; otras requieren anotaciones explícitas. El model registry de MLflow es cómodo pero permite SHAs no-deterministas en re-registros (su hash es sobre el layout en disco, no sobre el contenido canónico). Hasta que Borja no haya escrito uno él mismo — aunque sea un wrapper de 150 líneas — no puede detectar cuándo la herramienta elegida miente silenciosamente sobre reproducibilidad.
  2. La regla de alcance microscópico. La spec de este currículo (anti-goal §10) excluye langchain y similares porque la abstracción sin entendimiento desde primeros principios produce teatro, no destreza. El mismo principio aplica a MLOps. Construye el wrapper de 150 líneas; entiende lo que hace cada línea; entonces (post-currículo, si Borja decide) adopta una herramienta industrial con los ojos abiertos.

La disciplina crucial: usamos MLflow como backend de artefactos (tiene la abstracción de almacenamiento; no hace falta reescribir eso). No usamos el model registry de MLflow como fuente de identidad. La SHA canónica de la entrada la calcula scripts/mlops/registry.py sobre un bundle canónico (pesos en safetensors + JSON de config con claves ordenadas + parent SHA), y esa SHA es la primary key de todo lo que viene después.

Cómo se ve la "operabilidad" concretamente

Imagina que la capstone Fase 39 de Borja lleva dos semanas corriendo. Un usuario reporta: "El tutor dijo que 'I goed to the store' era correcto ayer. Eso es incorrecto — debería ser 'I went'."

Una demo no puede responder a preguntas de seguimiento. Un servicio puede responder a todas estas:

  • ¿Qué checkpoint produjo esa respuesta?traces[<request_id>].model_sha.
  • ¿Cuál era la distribución de entrada ese día?drift_reports/2026-XX-YY.json.
  • ¿Con qué corpus se entrenó ese checkpoint?lineage(<sha>).corpus_dvc_hash resuelve a un commit específico del corpus de verbos.
  • ¿Incluía el corpus "go → went" en el conjunto de irregulares?dvc pull data/processed/train.jsonl@<corpus_hash> e inspeccionar.
  • ¿Cuál fue la puntuación del eval antes del deploy?registry.get(<sha>).eval_report.conjugation_accuracy_by_verb["go"].
  • ¿Esa respuesta la sirvió el modelo de producción, un shadow o un canary?traces[<request_id>].traffic_assignment.
  • ¿Pasó ese checkpoint el gate de CI?gh run view <run_id> --log muestra la tasa de pase del eval en el momento de la promoción.
  • ¿Podemos hacer rollback?just rollback <previous_sha>.

Cada una de esas respuestas es una fila en un manifest, un tag sobre un run de MLflow o una llamada a scripts/mlops/. Ninguna está atornillada a posteriori — cada fase desde la 11 en adelante ha estado escribiendo manifests precisamente porque la Fase 38 los lee. El corpus_manifest.json de la Fase 12 (la versión del corpus trackeada por DVC) es la raíz del recorrido de lineage; el run de MLflow de la Fase 18 es el siguiente salto; el adaptador LoRA de la Fase 28 tiene su propio run de MLflow con parent_run_id apuntando al de la Fase 18; la Fase 38 envuelve toda la cadena tras una sola llamada a lineage(<sha>).

Por qué CI importa aquí en concreto

Un tutor de gramática que ocasionalmente acepta "he goed" es peor que no tener tutor — el usuario se fía de la corrección equivocada. El suelo para la promoción tiene que aplicarlo el código, no la memoria. Concretamente:

  • El workflow .github/workflows/deploy-grammar-tutor.yml corre el eval completo de la Fase 20 contra el checkpoint candidato cada vez.
  • Compara la precisión de conjugación por bucket contra eval_baseline.json, un fichero versionado.
  • Si algún bucket regresa más que la tolerancia configurada (por defecto 2pp), el workflow falla.
  • La promoción en el registry ocurre solo como el último paso exitoso de ese workflow. No hay un camino register.py --force en uso productivo. El camino existe para desarrollo local.

El resultado: cada modelo en producción ha pasado, por construcción, el gate del eval. El run de CI es el rastro de auditoría; el registry es el índice; la traza es la respuesta por petición.

Lo que esta fase explícitamente no es

No es:

  • Una guía de autoscaling. (Solo vocabulario — ver theory/05.)
  • Una presentación de consultoría FinOps. (Un número por entrada del registry — ver theory/04.)
  • Un manual de despliegue en Kubernetes. (infra/k8s/ es opcional, fuera del camino crítico.)
  • Un survey completo de detección de drift. (Dos métricas — KL y PSI — suficientes para el corpus contra el que operamos.)
  • Un nuevo src/<module>/. La Fase 38 vive en scripts/mlops/, src/miniserve/, src/miniobserve/ y .github/workflows/.

Es la espina dorsal de MLOps más pequeña posible que hace la capstone de la Fase 39 reproducible por alguien que no sea Borja, y rechaza desplegar un modelo peor.

Lo que esta fase NO cubre

  • Un backend de almacenamiento de registry a medida. El artifact store de MLflow es suficiente — lo envolvemos para hashing canónico, no para reemplazarlo.
  • Un runner de pipeline DAG a medida. El Justfile es el orquestador. Si un workflow excede ~15 recipes, revisitar en la Fase 40.
  • Integración con alerting / paging. La detección de drift escribe un informe; decidir qué hacer con una alerta de PSI alto es territorio del operador, no de la Fase 38. Hooks a PagerDuty / Alertmanager / Slack son trabajo futuro.
  • Cualquier cosa multirregional. Despliegue único, un único tracking store de MLflow. MLOps multirregional es su propio proyecto de varios meses.
  • Benchmarks de GPU-sharing. Sin CUDA en el portátil.
  • Tunear el eval baseline. eval_baseline.json está versionado; revisarlo es un PR con justificación, no una regeneración automática.

El movimiento pedagógico

Borja ha dedicado 37 fases a construir componentes. La Fase 38 le obliga a pensar en el sistema: cómo esos componentes se componen, fallan juntos y necesitan reemplazarse por piezas sin interrumpir el servicio. Este es el punto de inflexión donde el currículo deja de ser "construir el algoritmo" y pasa a ser "operar el algoritmo sin romperlo un martes".

Este giro importa para la Fase 39 (integración de la capstone) y la Fase 40 (postmortem). Sin la espina de la Fase 38, la capstone es un vídeo demo; con ella, la capstone es un sistema que otro aprendiz (o un futuro Borja) puede reconstruir solo desde la historia de git.

Recap

La motivación es operabilidad + bloqueo de regresiones. La operabilidad se construye a partir de seis artefactos: registry, lineage, estrategia de tráfico, señal de drift, gate de CI, coste-por-calidad. Los próximos cinco ficheros de teoría derivan la mecánica de cada artefacto. Los cinco labs los cablean todos sobre el servidor de la Fase 33 y el stack de observabilidad de la Fase 34 — sin un nuevo src/<module>/.

Siguiente: theory/01-registry-and-lineage.md.