Módulo 8: Proyecto Integrador — Deployed AI System
8. Proyecto Final: Deployed Production AI System
Descripción del proyecto
Este es el proyecto integrador de toda la guía — no solo del Módulo 8, sino de los 8 módulos completos. Vas a integrar todo lo que construiste y entregar dos artefactos: un sistema AI desplegado en producción real (con URL accesible desde internet) y documentación operativa profesional. No es un ejercicio — es el deployment de verdad. El resultado es el artefacto más portfolio-worthy de toda la guía.
Por qué importa: Este proyecto demuestra que no solo sabes deployar — sabes decidir cómo deployar, documentar tus decisiones, validar que funciona, y operar el sistema cuando algo falla. Es exactamente lo que un empleador quiere ver: un ingeniero que puede llevar un sistema de cero a producción con criterio profesional.
Objetivo del proyecto
Producir un Deployed Production AI System que incluya:
- Sistema AI desplegado en una plataforma real, accesible desde internet
- CI/CD pipeline que despliega automáticamente desde git push
- Health checks y smoke tests que validan la inferencia post-deploy
- Decision matrix v_final con justificación de estrategia y plataforma
- Runbook operativo con procedimientos para incidencias comunes
- Performance baseline con targets de latencia, costes, y error rate
- Deployment guide que otro ingeniero pueda seguir para replicar el setup
Recap del Módulo
Antes de empezar, asegúrate de tener los artefactos de cada cápsula:
| Cápsula | Artefacto | Lo usas para |
|---|---|---|
| 02 | Diagrama de integración | Entender cómo conectan las piezas |
| 03 | GitHub Actions workflow | Automatizar test → build → deploy → validate |
| 04 | Smoke test script | Validar inferencia post-deploy |
| 05 | Runbook template | Documentar procedimientos de incidencia |
| 06 | Decision matrix v_final | Justificar la estrategia y plataforma |
| 07 | Performance baseline | Establecer métricas de referencia |
Si te falta alguno, vuelve a la cápsula correspondiente y complétalo. El proyecto integra TODOS estos artefactos.
Especificaciones del Entregable
Entregable 1: Sistema Desplegado (50%)
REQUISITOS OBLIGATORIOS:
├── ✅ URL pública accesible desde cualquier navegador
│ Ejemplo: https://tu-app.railway.app
│
├── ✅ Health check endpoint
│ GET /health → {"status": "healthy", "version": "1.0.0"}
│
├── ✅ Readiness check con verificación de dependencias
│ GET /health/ready → {"status": "ready", "checks": {...}}
│
├── ✅ Endpoint de inferencia AI funcional
│ POST /api/inference → respuesta de LLM
│
├── ✅ CI/CD: git push a main → deploy automático
│ GitHub Actions workflow con test + build + deploy + validate
│
├── ✅ Variables de entorno configuradas (no hardcoded)
│ OPENAI_API_KEY, ENVIRONMENT, etc. en secrets de plataforma
│
└── ✅ Docker image funcional
Dockerfile multi-stage, .dockerignore configurado
Entregable 2: Documentación Operativa (50%)
REQUISITOS OBLIGATORIOS:
├── ✅ Decision Matrix v_final (docs/decision-matrix.md)
│ Estrategia + plataforma + justificación + trade-offs
│
├── ✅ Runbook Operativo (docs/runbook.md)
│ Al menos 4 procedimientos con diagnóstico y resolución
│
├── ✅ Performance Baseline (docs/performance-baseline.md)
│ Latencia, costes, error rate, uptime con targets
│
├── ✅ Deployment Guide (docs/deployment-guide.md)
│ Instrucciones para replicar el setup desde cero
│
└── ✅ Post-deploy validation report
Resultado de smoke tests contra producción
Caso de Estudio (si no tienes app AI propia)
DocuSearch AI — El mismo caso de toda la guía
Si no tienes tu propia app AI, usa el caso DocuSearch AI que has venido desarrollando. Aquí tienes el código mínimo necesario:
# src/main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, field_validator
from openai import AsyncOpenAI
from src.config import get_settings
import time
app = FastAPI(title="DocuSearch AI", version="1.0.0")
settings = get_settings()
client = AsyncOpenAI(api_key=settings.openai_api_key)
class InferenceRequest(BaseModel):
prompt: str
@field_validator("prompt")
@classmethod
def prompt_not_empty(cls, v):
if not v or not v.strip():
raise ValueError("Prompt cannot be empty")
return v.strip()
class InferenceResponse(BaseModel):
response: str
model: str
latency_ms: int
@app.get("/health")
async def health():
return {
"status": "healthy",
"version": "1.0.0",
"environment": settings.environment,
}
@app.get("/health/ready")
async def readiness():
checks = {}
try:
await client.models.list()
checks["openai"] = {"status": "connected"}
except Exception as e:
checks["openai"] = {"status": "error", "detail": str(e)[:100]}
all_ok = all(c.get("status") == "connected" for c in checks.values())
return {"status": "ready" if all_ok else "degraded", "checks": checks}
@app.post("/api/inference", response_model=InferenceResponse)
async def inference(request: InferenceRequest):
start = time.time()
try:
completion = await client.chat.completions.create(
model=settings.openai_model,
messages=[
{"role": "system", "content": "You are a helpful documentation assistant. Answer concisely."},
{"role": "user", "content": request.prompt},
],
max_tokens=500,
temperature=0.7,
)
elapsed_ms = int((time.time() - start) * 1000)
return InferenceResponse(
response=completion.choices[0].message.content,
model=settings.openai_model,
latency_ms=elapsed_ms,
)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Inference failed: {str(e)[:200]}")
# src/config.py
from pydantic_settings import BaseSettings
from functools import lru_cache
class Settings(BaseSettings):
environment: str = "development"
openai_api_key: str = ""
openai_model: str = "gpt-4o-mini"
debug: bool = False
version: str = "1.0.0"
class Config:
env_file = ".env"
@lru_cache()
def get_settings() -> Settings:
return Settings()
# Dockerfile
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
COPY src/ ./src/
FROM python:3.11-slim AS runtime
WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/*
COPY --from=builder /root/.local /root/.local
COPY --from=builder /app/src ./src/
ENV PATH=/root/.local/bin:$PATH
ENV PYTHONUNBUFFERED=1
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]
# requirements.txt
fastapi>=0.109.0
uvicorn>=0.27.0
openai>=1.12.0
pydantic>=2.6.0
pydantic-settings>=2.1.0
Paso a Paso: El Deployment
Paso 1: Verificar que todo funciona localmente (15 min)
# Build Docker image
docker build -t docusearch-ai:latest .
# Run localmente
docker run -d --name local-test \
-p 8000:8000 \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
-e ENVIRONMENT=development \
docusearch-ai:latest
# Verificar health
curl http://localhost:8000/health
# {"status":"healthy","version":"1.0.0","environment":"development"}
# Verificar readiness
curl http://localhost:8000/health/ready
# {"status":"ready","checks":{"openai":{"status":"connected"}}}
# Verificar inferencia
curl -X POST http://localhost:8000/api/inference \
-H "Content-Type: application/json" \
-d '{"prompt": "What is Docker?"}'
# {"response":"Docker is a platform for...","model":"gpt-4o-mini","latency_ms":1856}
# Cleanup
docker stop local-test && docker rm local-test
Si algo falla aquí, NO continúes. Arregla el problema local antes de intentar desplegar.
Paso 2: Configurar la plataforma (10-15 min)
Railway:
# Instalar CLI
npm install -g @railway/cli
# Login y crear proyecto
railway login
railway init
# Configurar variables de entorno
railway variables set OPENAI_API_KEY=sk-...
railway variables set ENVIRONMENT=production
# Deploy
railway up
Render:
1. render.com → New → Web Service
2. Connect GitHub repo
3. Settings:
- Environment: Docker
- Plan: Free
- Health Check Path: /health
4. Environment Variables:
- OPENAI_API_KEY: sk-...
- ENVIRONMENT: production
5. Deploy
Fly.io:
# Instalar CLI
curl -L https://fly.io/install.sh | sh
# Login y crear app
fly auth login
fly launch --name docusearch-ai
# Configurar secrets
fly secrets set OPENAI_API_KEY=sk-...
fly secrets set ENVIRONMENT=production
# Deploy
fly deploy
Paso 3: Verificar el deployment (5 min)
# Reemplaza con tu URL real
export PRODUCTION_URL="https://tu-app.railway.app"
# Health check
curl $PRODUCTION_URL/health
# Readiness
curl $PRODUCTION_URL/health/ready
# Inference
curl -X POST $PRODUCTION_URL/api/inference \
-H "Content-Type: application/json" \
-d '{"prompt": "What is deployment?"}'
# Smoke tests completos
python scripts/smoke_test.py $PRODUCTION_URL
Paso 4: Configurar CI/CD (15 min)
# .github/workflows/deploy.yml
name: Deploy AI System
on:
push:
branches: [main]
workflow_dispatch:
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: 'pip'
- run: pip install -r requirements.txt && pip install pytest httpx
- run: pytest tests/ -v --tb=short
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ENVIRONMENT: test
deploy:
if: github.ref == 'refs/heads/main'
needs: test
runs-on: ubuntu-latest
timeout-minutes: 10
environment: production
steps:
- uses: actions/checkout@v4
# ADAPTA A TU PLATAFORMA:
# Railway:
- run: npm install -g @railway/cli
- run: railway up --detach --service ${{ vars.RAILWAY_SERVICE_ID }}
env:
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
validate:
needs: deploy
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Wait for deployment
run: sleep 60
- name: Run smoke tests
run: python scripts/smoke_test.py "${{ vars.PRODUCTION_URL }}"
Configura en GitHub:
- Secrets:
OPENAI_API_KEY,RAILWAY_TOKEN(o el de tu plataforma) - Variables:
PRODUCTION_URL,RAILWAY_SERVICE_ID
Paso 5: Verificar CI/CD end-to-end (10 min)
# Haz un cambio menor y push
echo "# Updated $(date)" >> README.md
git add -A
git commit -m "test: verify CI/CD pipeline"
git push origin main
# Ve a GitHub → Actions → observa el pipeline
# Debe pasar: test ✅ → deploy ✅ → validate ✅
Paso 6: Configurar monitoreo (5 min)
UptimeRobot:
1. New Monitor → HTTP(s)
2. URL: https://tu-app.railway.app/health
3. Interval: 5 minutes
4. Alert contacts: tu email
Paso 7: Crear documentación (30-45 min)
Crea los 4 documentos en la carpeta docs/:
docs/decision-matrix.md — Tu decision matrix v_final (cápsula 06) docs/runbook.md — Tu runbook operativo (cápsula 05) docs/performance-baseline.md — Tus baselines de performance (cápsula 07) docs/deployment-guide.md — Ver template abajo
Template: Deployment Guide
# Deployment Guide — [Nombre del Sistema]
## Prerequisites
- Docker 24.0+
- Python 3.11+
- GitHub account
- [Tu plataforma] account
- OpenAI API key
## Step 1: Clone and Setup
git clone https://github.com/[tu-user]/[tu-repo].git
cd [tu-repo]
cp .env.example .env
# Edit .env with your API keys
## Step 2: Run Locally
docker build -t [app-name]:latest .
docker run -d --name local \
-p 8000:8000 \
--env-file .env \
[app-name]:latest
curl http://localhost:8000/health
## Step 3: Deploy to [Platform]
[Platform-specific steps]
## Step 4: Configure CI/CD
1. Add secrets to GitHub: [list]
2. Add variables to GitHub: [list]
3. Push to main to trigger deploy
## Step 5: Verify
python scripts/smoke_test.py [production-url]
## Step 6: Monitor
- UptimeRobot: [URL]
- OpenAI Usage: platform.openai.com
## Environment Variables
| Variable | Required | Description |
|----------|----------|-------------|
| OPENAI_API_KEY | Yes | OpenAI API key |
| ENVIRONMENT | Yes | development/staging/production |
| [Others] | ... | ... |
## Troubleshooting
- [Common issue 1]: [Solution]
- [Common issue 2]: [Solution]
Estructura Final del Proyecto
tu-proyecto-ai/
├── .github/
│ └── workflows/
│ ├── deploy.yml # CI/CD pipeline
│ └── rollback.yml # Rollback workflow (opcional)
├── src/
│ ├── __init__.py
│ ├── main.py # FastAPI app
│ └── config.py # Settings con Pydantic
├── tests/
│ ├── __init__.py
│ └── test_health.py # Tests básicos
├── scripts/
│ ├── smoke_test.py # Smoke tests
│ ├── validate-deploy.sh # Validación bash
│ ├── measure_latency.py # Medición de latencia
│ └── verify_secrets.py # Verificación de env vars
├── docs/
│ ├── decision-matrix.md # Decision matrix v_final
│ ├── runbook.md # Runbook operativo
│ ├── performance-baseline.md # Baselines de performance
│ └── deployment-guide.md # Guía de deployment
├── Dockerfile # Multi-stage build
├── .dockerignore # Exclusiones del image
├── docker-compose.yml # Desarrollo local
├── requirements.txt # Dependencias Python
├── .env.example # Template de env vars
└── README.md # Overview del proyecto
Checklist de Completitud
Sistema Desplegado
- URL pública accesible:
https://____________ -
GET /healthretorna 200 con status "healthy" -
GET /health/readyverifica dependencias (OpenAI) -
POST /api/inferenceprocesa un prompt y retorna respuesta del LLM - Variables de entorno configuradas en la plataforma (no hardcoded)
- Docker image funciona localmente con
docker build+docker run
CI/CD Pipeline
-
git push maindispara el pipeline automáticamente - Job
testejecuta pytest con éxito - Job
deploydespliega a la plataforma elegida - Job
validateejecuta smoke tests contra producción - Pipeline completo en < 10 minutos
- Secrets configurados en GitHub (API keys, platform tokens)
Documentación
-
docs/decision-matrix.mdcon criterios ponderados, evaluación, y justificación -
docs/runbook.mdcon al menos 4 procedimientos de incidencia -
docs/performance-baseline.mdcon latencia, costes, error rate, uptime targets -
docs/deployment-guide.mdque otro ingeniero puede seguir desde cero - Smoke test script funcional (
scripts/smoke_test.py) - README.md actualizado con overview del proyecto
Monitoreo
- UptimeRobot (o alternativa) configurado con health check cada 5 min
- Alertas de downtime configuradas (email o Slack)
- Spending alerts en OpenAI configuradas
Calidad
- El sistema funciona después de 24+ horas sin intervención
- Un git push con cambio menor dispara deploy exitoso
- Los smoke tests pasan consistentemente (>95% success rate)
- La documentación es autosuficiente (alguien externo la entiende)
- El runbook fue probado con al menos una incidencia simulada
Criterios de Evaluación
Rúbrica
| Criterio | Peso | Excelente (5) | Bueno (3) | Insuficiente (1) |
|---|---|---|---|---|
| Deploy funcional | 25% | URL pública, health checks, inferencia funcional | URL funcional pero falta algún check | No desplegado o no accesible |
| CI/CD | 20% | Pipeline completo con validate | Pipeline con test y deploy | Sin CI/CD o manual |
| Decision matrix | 15% | v_final con datos reales y validation | Matrix con criterios pero sin datos reales | Matrix incompleta o genérica |
| Runbook | 15% | 4+ procedimientos probados | 3 procedimientos básicos | <3 procedimientos o no probados |
| Performance baseline | 10% | 4 métricas con targets y alertas | 2-3 métricas documentadas | Sin baselines o sin targets |
| Deployment guide | 10% | Otro ingeniero replica el setup | Instrucciones parciales | Sin guía o incompleta |
| Monitoreo | 5% | UptimeRobot + alertas configuradas | Monitoreo básico | Sin monitoreo |
Niveles de entrega
NIVEL BÁSICO (aprueba):
├── Sistema desplegado con URL funcional
├── Health check que responde 200
├── Inferencia que funciona
├── Decision matrix con justificación
└── CI/CD con al menos test + deploy
NIVEL AVANZADO (destacado):
├── Todo lo básico +
├── Smoke tests automatizados post-deploy
├── Runbook con 4+ procedimientos probados
├── Performance baseline con 4 métricas
├── Deployment guide completa
├── Monitoreo externo configurado
└── Rollback strategy documentada y probada
NIVEL EXCEPCIONAL (portfolio-worthy):
├── Todo lo avanzado +
├── Pipeline con staging → production
├── Post-mortem de incidencia simulada
├── Sensitivity analysis en decision matrix
├── Caching implementado para responses frecuentes
└── Documentación que parece de un equipo profesional
Verificación Final: Script de Validación Completa
Script all-in-one para verificar el proyecto
# scripts/verify_project.py
"""
Verificación completa del proyecto final.
Ejecutar: python scripts/verify_project.py https://tu-app.railway.app
"""
import sys
import os
import json
import time
import urllib.request
import urllib.error
def check(name: str, condition: bool, detail: str = ""):
icon = "PASS" if condition else "FAIL"
msg = f" [{icon}] {name}"
if detail:
msg += f" — {detail}"
print(msg)
return condition
def verify_deployment(base_url: str) -> dict:
"""Verifica todos los requisitos del sistema desplegado."""
results = {"passed": 0, "failed": 0, "tests": []}
print(f"\n{'='*60}")
print(f"PROJECT VERIFICATION: {base_url}")
print(f"{'='*60}")
# 1. Health check
print("\n--- System Health ---")
try:
req = urllib.request.Request(f"{base_url}/health")
resp = urllib.request.urlopen(req, timeout=15)
data = json.loads(resp.read())
ok = check("Health endpoint", resp.status == 200, f"status={data.get('status')}")
ok2 = check("Version present", "version" in data, f"v={data.get('version')}")
except Exception as e:
ok = check("Health endpoint", False, str(e)[:80])
ok2 = False
# 2. Readiness check
try:
req = urllib.request.Request(f"{base_url}/health/ready")
resp = urllib.request.urlopen(req, timeout=15)
data = json.loads(resp.read())
ok3 = check("Readiness endpoint", resp.status == 200, f"status={data.get('status')}")
ok4 = check("Dependency checks", "checks" in data, f"checks={list(data.get('checks',{}).keys())}")
except Exception as e:
ok3 = check("Readiness endpoint", False, str(e)[:80])
ok4 = False
# 3. Inference
print("\n--- AI Inference ---")
try:
payload = json.dumps({"prompt": "What is 2+2? Answer briefly."}).encode()
req = urllib.request.Request(
f"{base_url}/api/inference",
data=payload,
headers={"Content-Type": "application/json"},
)
start = time.time()
resp = urllib.request.urlopen(req, timeout=30)
latency = (time.time() - start) * 1000
data = json.loads(resp.read())
ok5 = check("Inference endpoint", resp.status == 200, f"{latency:.0f}ms")
ok6 = check("Response has content", len(data.get("response", "")) > 0)
ok7 = check("Latency < 10s", latency < 10000, f"{latency:.0f}ms")
except Exception as e:
ok5 = check("Inference endpoint", False, str(e)[:80])
ok6 = ok7 = False
# 4. Error handling
print("\n--- Error Handling ---")
try:
payload = json.dumps({"prompt": ""}).encode()
req = urllib.request.Request(
f"{base_url}/api/inference",
data=payload,
headers={"Content-Type": "application/json"},
)
resp = urllib.request.urlopen(req, timeout=10)
ok8 = check("Empty prompt rejected", False, f"Expected 422, got {resp.status}")
except urllib.error.HTTPError as e:
ok8 = check("Empty prompt rejected", e.code == 422, f"status={e.code}")
except Exception as e:
ok8 = check("Empty prompt rejected", False, str(e)[:80])
# 5. Documentation files
print("\n--- Documentation ---")
doc_files = [
"docs/decision-matrix.md",
"docs/runbook.md",
"docs/performance-baseline.md",
"docs/deployment-guide.md",
]
for doc in doc_files:
exists = os.path.exists(doc)
check(f"File: {doc}", exists)
# 6. CI/CD
print("\n--- CI/CD ---")
ci_file = ".github/workflows/deploy.yml"
check(f"File: {ci_file}", os.path.exists(ci_file))
# 7. Scripts
print("\n--- Scripts ---")
scripts = ["scripts/smoke_test.py"]
for script in scripts:
check(f"File: {script}", os.path.exists(script))
print(f"\n{'='*60}")
print("Verification complete.")
print(f"{'='*60}\n")
if __name__ == "__main__":
url = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:8000"
verify_deployment(url)
Ejecución
# Verificar todo de una vez
python scripts/verify_project.py https://tu-app.railway.app
# Output esperado:
# ============================================================
# PROJECT VERIFICATION: https://tu-app.railway.app
# ============================================================
#
# --- System Health ---
# [PASS] Health endpoint — status=healthy
# [PASS] Version present — v=1.0.0
# [PASS] Readiness endpoint — status=ready
# [PASS] Dependency checks — checks=['openai']
#
# --- AI Inference ---
# [PASS] Inference endpoint — 2340ms
# [PASS] Response has content
# [PASS] Latency < 10s — 2340ms
#
# --- Error Handling ---
# [PASS] Empty prompt rejected — status=422
#
# --- Documentation ---
# [PASS] File: docs/decision-matrix.md
# [PASS] File: docs/runbook.md
# [PASS] File: docs/performance-baseline.md
# [PASS] File: docs/deployment-guide.md
#
# --- CI/CD ---
# [PASS] File: .github/workflows/deploy.yml
#
# --- Scripts ---
# [PASS] File: scripts/smoke_test.py
#
# ============================================================
# Verification complete.
# ============================================================
Troubleshooting del Proyecto
"No puedo desplegar porque mi app necesita un servicio adicional (Redis, DB)"
Solución: Para el proyecto, simplifica la arquitectura. Usa solo FastAPI + OpenAI API (sin Redis ni DB). La complejidad está en la integración del deployment, no en la app. Si insistes en DB, Railway y Render permiten agregar servicios adicionales (PostgreSQL, Redis) desde el dashboard.
"El deploy funciona pero la validación falla intermitentemente"
Solución:
# Incrementar tiempos de espera y retries
- name: Wait for deployment
run: sleep 90 # Dar más tiempo, especialmente en free tier
# Agregar retry al smoke test
- name: Run smoke tests with retry
run: |
for i in 1 2 3; do
python scripts/smoke_test.py "$URL" && exit 0
echo "Attempt $i failed, retrying in 30s..."
sleep 30
done
exit 1
"Mi API key de OpenAI no funciona en producción pero sí local"
Solución:
# Verificar que la key está configurada correctamente en la plataforma
# No debería tener espacios, saltos de línea, ni comillas
# Railway
railway variables | grep OPENAI
# Fly.io
fly secrets list
# Test directo de la key
curl https://api.openai.com/v1/models \
-H "Authorization: Bearer sk-tu-key-aqui" | head -c 100
"El pipeline tarda demasiado y a veces hace timeout"
Solución: Optimiza el pipeline:
# Usar cache de pip
- uses: actions/setup-python@v5
with:
cache: 'pip'
# Paralelizar test y build si son independientes
# Reducir número de tests en CI (solo critical path)
# Usar timeout-minutes en cada job
"¿Cómo hago el proyecto sin gastar dinero?"
Solución: Todas las plataformas recomendadas tienen free tier:
Railway: $5 crédito/mes gratis (más que suficiente para un proyecto)
Render: 750 horas/mes de instancias gratis
Fly.io: 3 VMs compartidas gratis
AWS Lambda: 1M requests/mes gratis
OpenAI: Usa gpt-4o-mini ($0.15/1M input tokens) —
500 requests/día × 30 días = 15K requests/mes ≈ $1.35/mes
Resultado Final
Al completar este proyecto tendrás:
✅ SISTEMA DESPLEGADO
URL: https://tu-app.railway.app (o tu plataforma)
Health: /health → healthy
Inference: /api/inference → respuesta del LLM
CI/CD: git push → deploy automático
✅ DOCUMENTACIÓN PROFESIONAL
Decision matrix: justificación con datos reales
Runbook: 4+ procedimientos de incidencia
Baselines: latencia, costes, error rate, uptime
Deploy guide: instrucciones replicables
✅ MONITOREO
UptimeRobot: health check cada 5 min
Alertas: email si el servicio cae
Cost alerts: OpenAI spending limits
Portfolio value
Este proyecto demuestra:
- Criterio de decisión: Decision matrix con trade-offs documentados
- Ejecución técnica: Docker + CI/CD + deployment + validation
- Mentalidad de producción: Runbook, baselines, monitoreo
- Comunicación: Documentación que otro ingeniero puede usar
Es el artefacto más completo que puedes mostrar en una entrevista de infraestructura o AI engineering.
Conexión con la Guía
¿Qué sigue?
Con tu sistema AI desplegado en producción:
Guía #18 — Monitoring & Observability for AI: Tu sistema está en producción. Ahora necesitas ver qué pasa dentro de él: métricas de inferencia, logs estructurados, tracing distribuido, alertas inteligentes, y dashboards. La transición es natural: "Tienes un sistema AI en producción → ahora necesitas observarlo."
Lo que llevas de esta guía a la #18:
- Un sistema AI funcional en producción (este proyecto)
- Performance baselines (cápsula 07)
- Health checks y smoke tests (cápsula 04)
- Runbook para incidencias (cápsula 05)
Lo que la guía #18 agrega:
- Structured logging con contexto de inferencia
- Métricas custom (token usage, latencia por modelo, cache hit rate)
- Distributed tracing (request → preprocessing → LLM → postprocessing)
- Alertas basadas en anomalías (no solo thresholds estáticos)
- Dashboards para stakeholders técnicos y no-técnicos
Nota Final
Acabas de poner tu primer sistema AI en producción — esto es real.
No es un tutorial que termina con "y así se deployaría." Es una URL real que cualquier persona con internet puede acceder. Es un pipeline que despliega automáticamente cuando haces push. Es documentación que otro ingeniero puede seguir para operar el sistema.
Esto es lo que separa a un developer que experimenta de uno que entrega en producción. La experiencia de ver tu sistema AI respondiendo en internet, con documentación profesional, monitoreo configurado, y procedimientos de incidencia listos — esa experiencia no la da ningún tutorial.
Lo que construiste aquí es la base de todo lo que viene: monitoring, observability, scaling, multi-region. Pero lo más importante es que ya tienes algo en producción. Y eso cambia todo.
Resumen
- Desplegaste un sistema AI en producción con URL pública accesible, health check y endpoint de inferencia funcional.
- Configuraste un pipeline CI/CD (GitHub Actions) que despliega automáticamente desde git push a main.
- Implementaste health checks y readiness checks que validan dependencias (OpenAI) post-deploy.
- Documentaste la decisión con una decision matrix v_final con justificación de estrategia y plataforma.
- Creaste un runbook operativo con procedimientos concretos para incidencias comunes.
- Definiste un performance baseline con targets de latencia, costes, error rate y uptime.
Recursos para el Proyecto
- Architecture Decision Records — Formato para documentar decisiones
- The Twelve-Factor App — Principios de apps production-ready
- Google SRE Book — Referencia de operaciones en producción
- Render Documentation — Docs para deployment en Render
- Railway Documentation — Docs para deployment en Railway
- Fly.io Documentation — Docs para deployment en Fly.io
- GitHub Actions Documentation — CI/CD con GitHub Actions
- UptimeRobot — Monitoreo de uptime gratuito
- OpenAI API Reference — Referencia de la API de OpenAI
- FastAPI Deployment — Documentación oficial de deployment de FastAPI