Módulo 8: Proyecto Integrador — Deployed AI System
7. Performance Baseline — Establecer Métricas de Referencia
Descripción
En esta cápsula vas a establecer baselines de performance para tu sistema AI desplegado: latencia de inferencia, costes mensuales, error rates, y uptime. Un baseline es el "normal" de tu sistema — sin él, no sabes si algo está mejorando, degradándose, o roto. Al terminar, tendrás targets documentados y herramientas gratuitas para monitorearlos.
Contexto: Tu sistema está desplegado y validado. Ahora necesitas definir qué es "normal" para poder detectar anomalías. Este es el puente entre este módulo (deployment) y la guía #18 (Monitoring & Observability): aquí estableces los baselines que la guía #18 te enseña a monitorear con herramientas avanzadas.
Por Qué Necesitas Baselines
Sin baseline vs con baseline
SIN BASELINE:
- "La app parece lenta" → ¿Comparada con qué?
- "Los costes subieron" → ¿Desde cuándo? ¿Cuánto es normal?
- "Hay muchos errores" → ¿Qué es "muchos"?
CON BASELINE:
- "Latencia p95 está en 4.2s, el baseline es 2.5s" → 68% degradado, investigar
- "Costes este mes: $45, baseline: $20" → 125% incremento, verificar tráfico
- "Error rate: 3.5%, baseline: 0.5%" → 7x incremento, algo está roto
Los baselines convierten percepciones subjetivas ("parece lento") en datos objetivos ("está 68% más lento que lo normal").
Las 4 métricas esenciales
┌─────────────────────────────────────────────────────────┐
│ PERFORMANCE BASELINES │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
│ │ LATENCIA │ │ COSTES │ │ ERRORS │ │ UPTIME │ │
│ │ │ │ │ │ │ │ │ │
│ │ p50, p95 │ │ $/mes │ │ % rate │ │ % disp. │ │
│ │ p99 │ │ desglose │ │ por tipo │ │ minutos │ │
│ └──────────┘ └──────────┘ └──────────┘ └─────────┘ │
│ │
│ Target: <3s Target:<$50 Target:<1% Target:>99% │
└─────────────────────────────────────────────────────────┘
Baseline 1: Latencia
Cómo medir latencia de tu sistema AI
# scripts/measure_latency.py
"""
Mide latencia del sistema AI en producción.
Ejecutar: python scripts/measure_latency.py https://tu-app.railway.app 20
"""
import sys
import time
import json
import urllib.request
import statistics
def measure_endpoint(base_url: str, num_requests: int = 20):
"""Mide latencia de inferencia con múltiples requests."""
url = f"{base_url}/api/inference"
latencies = []
errors = 0
print(f"Measuring latency: {num_requests} requests to {url}")
print()
for i in range(num_requests):
payload = json.dumps({
"prompt": f"Respond briefly: what is the number {i+1}?"
}).encode()
headers = {"Content-Type": "application/json"}
req = urllib.request.Request(url, data=payload, headers=headers)
start = time.time()
try:
response = urllib.request.urlopen(req, timeout=30)
elapsed_ms = (time.time() - start) * 1000
latencies.append(elapsed_ms)
status = "OK" if response.status == 200 else f"HTTP {response.status}"
print(f" Request {i+1:3d}: {elapsed_ms:7.0f}ms — {status}")
except Exception as e:
elapsed_ms = (time.time() - start) * 1000
errors += 1
print(f" Request {i+1:3d}: {elapsed_ms:7.0f}ms — ERROR: {e}")
time.sleep(0.5)
if not latencies:
print("No successful requests")
return
latencies.sort()
n = len(latencies)
results = {
"total_requests": num_requests,
"successful": n,
"errors": errors,
"error_rate": f"{(errors/num_requests)*100:.1f}%",
"latency_ms": {
"min": round(latencies[0]),
"max": round(latencies[-1]),
"mean": round(statistics.mean(latencies)),
"median_p50": round(latencies[n // 2]),
"p90": round(latencies[int(n * 0.9)]),
"p95": round(latencies[int(n * 0.95)]),
"p99": round(latencies[int(n * 0.99)]) if n >= 100 else "N/A (need 100+ samples)",
"std_dev": round(statistics.stdev(latencies)) if n > 1 else 0,
},
}
print()
print("=" * 50)
print("LATENCY BASELINE RESULTS")
print("=" * 50)
print(f" Requests: {n} successful / {num_requests} total")
print(f" Error rate: {results['error_rate']}")
print(f" Latency (ms):")
print(f" Min: {results['latency_ms']['min']}ms")
print(f" p50: {results['latency_ms']['median_p50']}ms")
print(f" p90: {results['latency_ms']['p90']}ms")
print(f" p95: {results['latency_ms']['p95']}ms")
print(f" Max: {results['latency_ms']['max']}ms")
print(f" StdDev: {results['latency_ms']['std_dev']}ms")
print()
p95 = results["latency_ms"]["p95"]
if p95 < 3000:
print(f" STATUS: GOOD — p95 ({p95}ms) < 3000ms target")
elif p95 < 5000:
print(f" STATUS: WARNING — p95 ({p95}ms) > 3000ms but < 5000ms")
else:
print(f" STATUS: CRITICAL — p95 ({p95}ms) > 5000ms")
return results
if __name__ == "__main__":
base_url = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:8000"
num_req = int(sys.argv[2]) if len(sys.argv) > 2 else 20
measure_endpoint(base_url, num_req)
Output esperado
Measuring latency: 20 requests to https://mi-app.railway.app/api/inference
Request 1: 3245ms — OK
Request 2: 1890ms — OK
Request 3: 2100ms — OK
...
Request 20: 1945ms — OK
==================================================
LATENCY BASELINE RESULTS
==================================================
Requests: 20 successful / 20 total
Error rate: 0.0%
Latency (ms):
Min: 1654ms
p50: 2100ms
p90: 2890ms
p95: 3100ms
Max: 3245ms
StdDev: 420ms
STATUS: WARNING — p95 (3100ms) > 3000ms but < 5000ms
Definir targets de latencia
latency_targets = {
"health_check": {
"target_ms": 200,
"acceptable_ms": 500,
"critical_ms": 1000,
},
"inference": {
"target_ms": 2000,
"acceptable_ms": 3000,
"critical_ms": 5000,
},
"notes": [
"Inferencia incluye: network + preprocessing + LLM API call + postprocessing",
"La mayor parte del tiempo (~70-80%) es la llamada al LLM",
"Cold starts en free tier pueden agregar 5-15s al primer request",
"p95 es la métrica principal — no p50 ni media",
],
}
Baseline 2: Costes
Desglose de costes mensuales
# scripts/cost_baseline.py
"""Calcula y documenta el baseline de costes."""
def calculate_monthly_costs(
daily_requests: int,
avg_input_tokens: int = 500,
avg_output_tokens: int = 300,
platform_cost: float = 0,
) -> dict:
"""Estima costes mensuales para un sistema AI."""
monthly_requests = daily_requests * 30
gpt4o_mini_input = 0.15 / 1_000_000
gpt4o_mini_output = 0.60 / 1_000_000
llm_input_cost = monthly_requests * avg_input_tokens * gpt4o_mini_input
llm_output_cost = monthly_requests * avg_output_tokens * gpt4o_mini_output
llm_total = llm_input_cost + llm_output_cost
embedding_cost_per_request = 0.02 / 1_000_000 * 500
embedding_total = monthly_requests * embedding_cost_per_request
total = llm_total + embedding_total + platform_cost
return {
"monthly_requests": monthly_requests,
"llm_cost": round(llm_total, 2),
"embedding_cost": round(embedding_total, 2),
"platform_cost": platform_cost,
"total_monthly": round(total, 2),
"cost_per_request": round(total / monthly_requests * 1000, 4),
}
# Escenarios
scenarios = {
"Current (150 users)": calculate_monthly_costs(
daily_requests=500,
avg_input_tokens=600,
avg_output_tokens=300,
platform_cost=0, # free tier
),
"Growth (500 users)": calculate_monthly_costs(
daily_requests=2000,
avg_input_tokens=600,
avg_output_tokens=300,
platform_cost=5, # Railway Pro
),
"Scale (2000 users)": calculate_monthly_costs(
daily_requests=8000,
avg_input_tokens=600,
avg_output_tokens=300,
platform_cost=20, # Railway Pro + more resources
),
}
print("COST BASELINE")
print("=" * 60)
for name, costs in scenarios.items():
print(f"\n{name}:")
print(f" Monthly requests: {costs['monthly_requests']:,}")
print(f" LLM cost: ${costs['llm_cost']:.2f}/mes")
print(f" Embedding cost: ${costs['embedding_cost']:.2f}/mes")
print(f" Platform cost: ${costs['platform_cost']:.2f}/mes")
print(f" TOTAL: ${costs['total_monthly']:.2f}/mes")
print(f" Per 1K requests: ${costs['cost_per_request']:.4f}")
Definir targets de costes
cost_targets = {
"monthly_budget": 50, # $50/mes máximo
"alert_threshold": 40, # Alertar al 80% del presupuesto
"breakdown_expected": {
"llm_api": "60-70% del total",
"platform": "20-30% del total",
"other": "<10% del total",
},
"monitoring": {
"openai": "platform.openai.com → Usage → set spending limit",
"platform": "Dashboard → Billing → set alerts",
"review": "Semanal: verificar que el gasto va en línea con proyección",
},
}
Configurar alertas de costes
OpenAI:
1. platform.openai.com → Settings → Limits
2. Set monthly budget: $30 (deja margen para infra)
3. Set email alert at: $20
Railway:
1. Dashboard → Settings → Usage Alerts
2. O monitorear manualmente el Usage meter
Fly.io:
1. Dashboard → Billing → set spending limit
AWS:
1. AWS Budgets → Create budget → Monthly cost budget
2. Alert at 80% and 100% of budget
Baseline 3: Error Rate
Medir error rate actual
# scripts/error_baseline.py
"""Mide error rate del sistema con requests variados."""
import sys
import json
import urllib.request
import urllib.error
def measure_error_rate(base_url: str, num_requests: int = 50):
"""Envía requests variados y mide la tasa de error."""
test_cases = [
{"prompt": "What is machine learning?", "expect": 200},
{"prompt": "Explain Docker in one sentence", "expect": 200},
{"prompt": "What is 2+2?", "expect": 200},
{"prompt": "Summarize the benefits of CI/CD", "expect": 200},
{"prompt": "Hello", "expect": 200},
]
results = {"total": 0, "success": 0, "client_error": 0,
"server_error": 0, "timeout": 0, "other": 0}
error_details = []
print(f"Measuring error rate: {num_requests} requests to {base_url}")
for i in range(num_requests):
test = test_cases[i % len(test_cases)]
url = f"{base_url}/api/inference"
payload = json.dumps({"prompt": test["prompt"]}).encode()
headers = {"Content-Type": "application/json"}
req = urllib.request.Request(url, data=payload, headers=headers)
results["total"] += 1
try:
response = urllib.request.urlopen(req, timeout=30)
if response.status == test["expect"]:
results["success"] += 1
else:
results["client_error"] += 1
error_details.append(f"Request {i+1}: expected {test['expect']}, got {response.status}")
except urllib.error.HTTPError as e:
if 400 <= e.code < 500:
results["client_error"] += 1
else:
results["server_error"] += 1
error_details.append(f"Request {i+1}: HTTP {e.code}")
except TimeoutError:
results["timeout"] += 1
error_details.append(f"Request {i+1}: timeout")
except Exception as e:
results["other"] += 1
error_details.append(f"Request {i+1}: {type(e).__name__}")
total = results["total"]
error_count = total - results["success"]
error_rate = (error_count / total) * 100 if total > 0 else 0
print()
print("ERROR RATE BASELINE")
print("=" * 50)
print(f" Total requests: {total}")
print(f" Successful: {results['success']} ({(results['success']/total)*100:.1f}%)")
print(f" Client errors: {results['client_error']}")
print(f" Server errors: {results['server_error']}")
print(f" Timeouts: {results['timeout']}")
print(f" Other errors: {results['other']}")
print(f" ERROR RATE: {error_rate:.1f}%")
print()
if error_rate < 1:
print(f" STATUS: GOOD — error rate ({error_rate:.1f}%) < 1% target")
elif error_rate < 5:
print(f" STATUS: WARNING — error rate ({error_rate:.1f}%) > 1% but < 5%")
else:
print(f" STATUS: CRITICAL — error rate ({error_rate:.1f}%) > 5%")
if error_details:
print(f"\n Error details ({len(error_details)}):")
for detail in error_details[:10]:
print(f" - {detail}")
return results
if __name__ == "__main__":
url = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:8000"
num = int(sys.argv[2]) if len(sys.argv) > 2 else 50
measure_error_rate(url, num)
Definir targets de error rate
error_targets = {
"overall_error_rate": {
"target": "< 1%",
"acceptable": "< 5%",
"critical": "> 5%",
},
"by_type": {
"server_errors_5xx": "< 0.1% — indica bugs en tu código",
"timeouts": "< 0.5% — indica problemas de infra o LLM API",
"client_errors_4xx": "No cuenta como 'error' — es uso incorrecto del cliente",
},
"notes": [
"OpenAI API tiene ~0.1-0.5% error rate propio (rate limits, server errors)",
"Free tier platforms tienen más errores por cold starts y resource limits",
"Error rate = (server_errors + timeouts) / total_requests",
],
}
Baseline 4: Uptime
Medir y monitorear uptime
Uptime = tiempo que el servicio está accesible / tiempo total
Target Downtime/mes Downtime/año
99% 7.3 hrs 3.65 días
99.5% 3.65 hrs 1.83 días
99.9% 43.8 min 8.77 hrs
99.99% 4.38 min 52.6 min
Para un sistema AI en free tier:
Target realista: 99% (7 hrs downtime/mes máximo)
Incluye: cold starts, platform maintenance, deploys
Para un sistema AI en plan pago:
Target realista: 99.5% (3.65 hrs downtime/mes)
Para producción enterprise:
Target: 99.9%+ (requiere infra dedicada)
Herramientas gratuitas de uptime monitoring
UptimeRobot (recomendado):
- 50 monitors gratis
- Check cada 5 minutos
- Status page público (opcional)
- Alertas: email, Slack, webhook
- Histórico de uptime (% mensual)
Configuración:
Monitor 1: GET /health → cada 5 min
Monitor 2: POST /api/inference con body → cada 15 min (verifica inferencia)
Better Stack:
- 10 monitors gratis
- Check cada 3 minutos
- Status page incluido
- Incident management básico
Freshping:
- 50 monitors gratis
- Check cada 1 minuto
- Multi-location checks
Documento de Performance Baseline
Template completo
# Performance Baseline — [Nombre del Sistema AI]
**Fecha de baseline:** [Fecha]
**URL producción:** [URL]
**Plataforma:** [Railway/Render/Fly.io/AWS]
**Plan:** [Free/Pro/etc.]
## Latencia
| Métrica | Valor baseline | Target | Alerta si |
|---------|---------------|--------|-----------|
| p50 | [X]ms | <2000ms | >2500ms |
| p90 | [X]ms | <2500ms | >3000ms |
| p95 | [X]ms | <3000ms | >4000ms |
| Max | [X]ms | <5000ms | >8000ms |
| Health check | [X]ms | <200ms | >500ms |
**Medido con:** [N] requests el [fecha]
**Nota:** [Observaciones sobre cold starts, variabilidad, etc.]
## Costes
| Componente | Baseline | Budget | Alerta si |
|-----------|----------|--------|-----------|
| LLM API (OpenAI) | $[X]/mes | $[Y]/mes | >$[Z]/mes |
| Platform (infra) | $[X]/mes | $[Y]/mes | >$[Z]/mes |
| Total | $[X]/mes | $[Y]/mes | >$[Z]/mes |
| Per 1K requests | $[X] | - | >$[Y] |
**Spending alerts configuradas:** [Sí/No] [Dónde]
## Error Rate
| Métrica | Valor baseline | Target | Alerta si |
|---------|---------------|--------|-----------|
| Overall error rate | [X]% | <1% | >2% |
| Server errors (5xx) | [X]% | <0.1% | >0.5% |
| Timeouts | [X]% | <0.5% | >1% |
**Medido con:** [N] requests el [fecha]
## Uptime
| Métrica | Target | Monitoreo |
|---------|--------|-----------|
| Monthly uptime | >99% | UptimeRobot |
| Max downtime/incident | <30 min | Alertas configuradas |
| Max downtime/mes | <7 hrs | Review mensual |
**Monitoring configurado:** [Herramienta, URL del dashboard]
**Alertas configuradas:** [Email/Slack cuando downtime >5 min]
## Cuándo Escalar
| Trigger | Métrica actual | Threshold | Acción |
|---------|---------------|-----------|--------|
| Latencia sostenida | [X]ms p95 | >5000ms por >1 hora | Escalar recursos o optimizar |
| Error rate alto | [X]% | >5% por >30 min | Investigar + posible rollback |
| Costes excedidos | $[X]/mes | >$[Y]/mes | Review de tráfico y optimización |
| Memoria alta | [X]% | >90% sostenido | Escalar RAM o optimizar |
Cuándo Escalar
Señales de que necesitas más recursos
ESCALAR VERTICALMENTE (más CPU/RAM):
├── Latencia p95 sostenida > 2x baseline por > 1 hora
├── Memoria > 90% del límite disponible
├── CPU > 80% sostenido
└── Acción: Upgrade de plan en la plataforma
ESCALAR HORIZONTALMENTE (más instancias):
├── Requests concurrentes > capacidad de una instancia
├── Queue de requests creciendo
├── Latencia incrementa linealmente con tráfico
└── Acción: Agregar réplicas (si la plataforma lo permite)
OPTIMIZAR CÓDIGO (antes de escalar infra):
├── Caching de responses repetitivas
├── Reducir tokens en prompts
├── Cambiar a modelo más rápido (gpt-4o-mini vs gpt-4o)
├── Async processing para requests pesados
└── Acción: Optimizar ANTES de pagar más infra
Decision tree para escalar
¿Latencia alta?
├── ¿Es la API del LLM? (>70% del tiempo total)
│ ├── SÍ → Optimizar prompts, reducir tokens, o cambiar modelo
│ └── NO → ¿Es tu código?
│ ├── SÍ → Profiling, optimizar, caching
│ └── NO → ¿Es la plataforma?
│ ├── SÍ → Escalar recursos o cambiar plataforma
│ └── NO → Investigar networking
│
¿Costes altos?
├── ¿Es el LLM API? (revisar token usage)
│ ├── SÍ → Reducir tokens, caching, rate limiting
│ └── NO → ¿Es la infra?
│ ├── SÍ → Evaluar plan actual vs alternativas
│ └── NO → ¿Tráfico legítimo o abuso?
│ ├── Legítimo → Escalar (invertir en crecimiento)
│ └── Abuso → Rate limiting, firewall
Troubleshooting
Problema 1: "La latencia varía mucho entre requests"
Causa: Cold starts, variabilidad de la API del LLM, o garbage collection en Python.
Solución:
# 1. Excluir el primer request (cold start) del baseline
latencies = latencies[1:] # Skip warm-up request
# 2. Reportar desviación estándar junto con p50/p95
# StdDev alto (>50% de la media) = alta variabilidad
# StdDev bajo (<20% de la media) = consistente
# 3. Implementar warm-up en el pipeline
# Después del deploy, enviar 2-3 requests de warm-up antes de smoke tests
Problema 2: "No puedo medir costes porque estoy en free tier"
Causa: Free tier no tiene billing visible.
Solución: Mide el uso, no el coste directo.
# Medir uso de OpenAI (que sí tiene billing)
# platform.openai.com → Usage → ver por día
# Estimar coste de infra si migras a plan pago
estimated_infra = {
"Railway Pro": 5, # $5/mes base
"Render Starter": 7, # $7/mes
"Fly.io": 0, # Free VMs, pago por uso adicional
"AWS Lambda": 0, # Free tier: 1M requests
}
Problema 3: "El error rate es 0% pero sé que a veces falla"
Causa: Estás midiendo con pocos requests o con prompts muy simples.
Solución:
# Usar prompts más variados y realistas
edge_case_prompts = [
"A" * 5000, # Prompt muy largo
"🎉 emoji test 中文 عربي", # Unicode
"Repeat the word 'test' 500 times", # Request de muchos tokens
"", # Prompt vacío (debería dar 422)
"x" * 100000, # Prompt extremadamente largo
]
# Medir con al menos 50 requests para un baseline significativo
Problema 4: "No sé qué targets poner para latencia"
Solución:
La regla práctica para apps AI:
- Si es chat interactivo: p95 < 3s (los usuarios esperan respuesta rápida)
- Si es API backend: p95 < 5s (depende del consumer)
- Si es batch processing: p95 < 30s (no es interactivo)
Baseline primero, targets después:
1. Mide 20+ requests
2. Calcula p50 y p95
3. Target = p95 actual + 20% margen
4. Alerta = p95 actual + 50% margen
5. Crítico = p95 actual × 2
Ejercicios Prácticos
Ejercicio 1: Medir latencia baseline
Ejecuta el script de medición de latencia contra tu sistema desplegado y documenta los resultados.
Ver solución
# Ejecutar medición
python scripts/measure_latency.py https://tu-app.railway.app 20
# Resultado esperado:
# p50: ~2000ms (depende del modelo y plataforma)
# p95: ~3000ms
# StdDev: ~400-800ms
# Documentar en tu performance baseline:
# "Latencia medida el [fecha] con 20 requests.
# p50: 2100ms, p95: 3050ms, max: 3500ms.
# El 80% del tiempo es la llamada a OpenAI API.
# Cold start del primer request: 12s (excluido del baseline)."
Si tu p95 es > 5s excluyendo cold starts, investiga: puede ser la plataforma (free tier con recursos limitados), el modelo (gpt-4o es más lento que gpt-4o-mini), o tu código (procesamiento excesivo).
Ejercicio 2: Calcular cost baseline
Ejecuta el script de costes con tus datos reales y configura alertas.
Ver solución
# Con tus datos:
my_costs = calculate_monthly_costs(
daily_requests=500, # Tu tráfico actual
avg_input_tokens=600, # Medir con tiktoken
avg_output_tokens=300, # Estimar o medir
platform_cost=0, # Free tier
)
print(f"Estimated monthly cost: ${my_costs['total_monthly']:.2f}")
# Ejemplo: $2.70/mes en free tier con 500 req/día
# Configurar alerta en OpenAI:
# platform.openai.com → Settings → Limits → $10/mes
El coste más difícil de predecir es el de la API del LLM, porque depende del largo de los prompts y respuestas. Mide tokens reales con tiktoken para tener un baseline preciso.
Ejercicio 3: Medir error rate
Ejecuta el script de error rate y documenta los resultados.
Ver solución
python scripts/error_baseline.py https://tu-app.railway.app 50
# Resultado esperado:
# Error rate: 0-2% (depende de la estabilidad de tu sistema)
# Server errors: 0% (ideal)
# Timeouts: 0-1% (puede ocurrir en free tier)
# Si error rate > 5%:
# 1. Revisa los detalles de errores
# 2. ¿Son todos del mismo tipo? (ej: todos timeout)
# 3. ¿Es la API de OpenAI? (rate limiting)
# 4. ¿Es tu código? (bug en el handler)
Ejercicio 4: Documento de performance baseline completo
Crea docs/performance-baseline.md usando el template de esta cápsula con tus datos reales.
Ver solución
# Performance Baseline — Mi AI System
**Fecha de baseline:** 2026-03-08
**URL producción:** https://mi-app.railway.app
**Plataforma:** Railway (Free tier)
## Latencia
| Métrica | Baseline | Target | Alerta |
|---------|----------|--------|--------|
| p50 | 2100ms | <2500ms | >3000ms |
| p95 | 3050ms | <3500ms | >4500ms |
Medido con 20 requests el 2026-03-08.
Nota: Cold start del primer request ~12s (excluido).
## Costes
| Componente | Baseline | Budget |
|-----------|----------|--------|
| OpenAI API | $2.70/mes | $10/mes |
| Railway | $0/mes (free) | $5/mes |
| Total | $2.70/mes | $15/mes |
## Error Rate
| Métrica | Baseline | Target |
|---------|----------|--------|
| Overall | 0.0% | <1% |
| Timeouts | 0.0% | <0.5% |
Medido con 50 requests el 2026-03-08.
## Uptime
Monitoring: UptimeRobot (cada 5 min)
Target: >99% mensual
Este documento se actualiza mensualmente o cuando hay cambios significativos en el sistema.
Resumen
- Baselines convierten percepciones ("parece lento") en datos ("p95 está 68% sobre el target")
- Las 4 métricas esenciales: latencia (p50/p95), costes ($/mes), error rate (%), uptime (%)
- Mide antes de definir targets — los targets se basan en datos reales, no aspiraciones
- Herramientas gratuitas cubren el monitoreo básico: UptimeRobot, OpenAI Usage dashboard, scripts propios
- Cuándo escalar: primero optimiza código (caching, prompts más cortos), después escala infra
- El documento de performance baseline es un artefacto vivo — actualízalo mensualmente
- Este baseline es la entrada para la guía #18 (Monitoring & Observability), que profundiza en métricas avanzadas
Recursos Adicionales
- UptimeRobot — Monitoreo de uptime gratuito
- OpenAI Usage Dashboard — Monitoreo de uso de API
- Google SRE Book — Service Level Objectives — SLOs y SLIs
- Latency Numbers Every Programmer Should Know — Referencia de latencias
- tiktoken — OpenAI Tokenizer — Contar tokens para estimar costes
- Cloud Cost Handbook — Referencia de costes cloud