Eran las 3:47 AM de un martes cuando nuestro Slack explotó: "API latency spike — p99 por encima de 8 segundos." El ingeniero de on-call abrió la notebook, se restregó los ojos y arrancó el ritual de siempre: revisar Grafana, grep-ear los logs, trazar el request, revisar el historial de deploys, tratar de correlacionar eventos a través de 14 microservicios.
Para cuando encontraron la causa raíz — una config de connection pool rota deployada 6 horas antes — ya habían pasado 2.5 horas. El incidente se resolvió, pero el daño estaba hecho: breach de SLA, clientes quejándose y un ingeniero agotado.
Ese incidente fue la gota que rebalsó el vaso. Decidimos construir algo mejor.
El Problema: El Incident Response es Principalmente Recolección de Datos
Acá hay un secreto sucio sobre el incident response: el 80% del tiempo se gasta recopilando contexto, no solucionando cosas. El fix real suele ser simple — hacer rollback de un deploy, escalar un servicio, reiniciar un pod. Pero encontrar qué hay que fixear requiere correlacionar datos de decenas de fuentes.
Mapeamos lo que nuestros ingenieros hacen realmente durante un incidente:
- Revisar los dashboards de alertas (Grafana/Datadog)
- Leer los últimos 15 minutos de logs de los servicios afectados
- Revisar los deploys recientes (
kubectl rollout history) - Mirar la utilización de recursos (CPU, memoria, conexiones)
- Trazar un request fallido de ejemplo a través de los servicios
- Revisar si pasaron incidentes similares antes
- Formular una hipótesis y verificarla
Los pasos 1-6 son recolección de datos pura. Un agente de IA puede hacer todo eso más rápido y de manera más consistente que un humano privado de sueño.
Arquitectura: El Agente de Tres Fases
Construimos nuestro incident responder como un Cloudflare Worker que se conecta a Claude vía la Anthropic API. El agente funciona en tres fases:
Fase 1: Recolección de Contexto
Cuando se dispara una alerta, un webhook activa nuestro agente. Inmediatamente empieza a recolectar contexto en paralelo:
async function collectContext(alert) {
const [logs, deploys, metrics, traces] = await Promise.all([
fetchRecentLogs(alert.service, '15m'),
fetchRecentDeploys(alert.namespace, '24h'),
fetchMetricsSnapshot(alert.service),
fetchFailingTraces(alert.service, 5),
]);
return { alert, logs, deploys, metrics, traces };
}
Traemos datos de:
- Loki para logs (vía LogQL API)
- ArgoCD para el historial de deploys
- Prometheus para métricas (CPU, memoria, error rates, percentiles de latencia)
- Jaeger para trazas distribuidas
Todo se trae en paralelo. Tiempo total de recolección: menos de 3 segundos.
Fase 2: Análisis con Claude
Enviamos el contexto recolectado a Claude Haiku con un system prompt cuidadosamente diseñado:
const analysis = await anthropic.messages.create({
model: 'claude-haiku-4-5-20251001',
max_tokens: 2048,
system: `You are an SRE incident analyst. Given alert data, logs,
metrics, deployment history, and traces, identify the most likely
root cause and suggest remediation steps.
Rules:
- Be specific: name the exact service, pod, or config that's failing
- Correlate timing: if a deploy happened before the alert, flag it
- Suggest the safest fix first (rollback > restart > scale > config change)
- Rate your confidence: HIGH / MEDIUM / LOW
- If unsure, say so — never guess on production systems`,
messages: [{ role: 'user', content: formatContext(context) }],
});
Elegimos Claude Haiku por la velocidad — el análisis completa en menos de 2 segundos. Para incidentes complejos, escalamos a Sonnet.
Fase 3: Recomendación de Acciones
El agente postea en Slack con un brief de incidente estructurado:
🔴 INCIDENT DETECTED — api-gateway latency spike
📊 Summary:
- p99 latency jumped from 200ms to 8.2s at 03:41 UTC
- Error rate increased from 0.1% to 12.3%
- Affected: api-gateway, user-service (downstream)
🔍 Root Cause (HIGH confidence):
Deploy api-gateway v2.14.3 at 21:30 UTC changed connection
pool max from 100 to 10 (likely typo in PR #847)
💡 Recommended Actions:
1. ROLLBACK api-gateway to v2.14.2 (safest)
→ kubectl rollout undo deployment/api-gateway -n production
2. OR hotfix: set POOL_MAX=100 in configmap
→ kubectl edit configmap api-gateway-config -n production
📋 Evidence:
- Connection pool exhaustion visible in logs (47 occurrences)
- Latency spike correlates exactly with deploy timestamp
- Pre-deploy metrics were healthy (p99: 180ms)
El ingeniero de on-call ahora puede actuar de inmediato en lugar de pasar 2 horas juntando contexto.
Resultados: De 2.5 Horas a 8 Minutos
Después de 3 meses en producción:
| Métrica | Antes | Después |
|---|---|---|
| MTTR promedio | 2.5 horas | 18 minutos |
| MTTR (incidentes diagnosticados por el agente) | 2.5 horas | 8 minutos |
| Incidentes auto-diagnosticados correctamente | — | 62% |
| Tasa de falsos positivos | — | 8% |
| Satisfacción del on-call (sobre 5) | 2.1 | 4.3 |
La mayor sorpresa fue que los ingenieros empezaron a confiar en el agente dentro de la primera semana. Cuando vieron que identificaba correctamente una falla en cascada a través de 3 servicios en 4 segundos — algo que a ellos les hubiera llevado 30+ minutos — quedaron convencidos.
Lo Que Aprendimos
Empezar con read-only. Nuestro agente no ejecuta ninguna acción automáticamente. Solo recomienda. Eso fue crítico para construir confianza. Vamos a agregar auto-remediación para casos simples (como rollbacks) una vez que tengamos 6 meses de datos de precisión.
Haiku es suficientemente rápido. Inicialmente planeamos usar Sonnet para todo, pero la velocidad de Haiku (análisis en menos de 2 segundos) hace una diferencia real a las 3 AM. Solo escalamos a Sonnet para incidentes multi-servicio.
El formateo del contexto importa más que el prompt engineering. Gastamos más tiempo formateando los datos que le enviamos a Claude (excerpts limpios de logs, métricas pre-agregadas, diffs de deploys) que en el system prompt. Garbage in, garbage out.
Loggeá todo. Registramos cada análisis junto a la causa raíz real (determinada post-incidente). Eso nos da métricas de precisión y datos para mejorar nuestros prompts.
Qué Sigue
Estamos trabajando en la Fase 2: auto-remediación para diagnósticos de alta confianza. Si el agente tiene 95%+ de confianza y el fix es un rollback, ¿para qué despertar a un humano? Estamos construyendo un flujo de confirmación donde el agente propone, una segunda instancia de Claude valida, y solo entonces ejecuta.
El objetivo no es reemplazar a los ingenieros de on-call — es dejarlos dormir durante los incidentes que no requieren creatividad humana.
Qué Haríamos Diferente
Empezar a loggear el contexto completo desde el día uno. En las primeras dos semanas no loggeábamos el payload completo que le mandábamos a Claude, solo el resultado. Cuando quisimos debuguear por qué el agente erraba en ciertos incidentes, no teníamos los datos para rastrear el problema hasta el formateo del contexto. Perdimos dos semanas de datos de entrenamiento potencial.
Parametrizar las ventanas de tiempo más temprano. Hardcodeamos '15m' para logs y '24h' para deploys al principio. Para incidentes lentos que se desarrollan durante horas, la ventana de 15 minutos corta exactamente antes del evento desencadenante. Ahora hacemos que la ventana sea dinámica basada en el tiempo de inicio de la alerta, pero ese ajuste llegó recién en el mes dos.
Armar el runbook de escalada de Haiku→Sonnet antes del go-live. Sabíamos que íbamos a escalar a Sonnet para incidentes complejos, pero el criterio de escalada era vago ("cuando Haiku no está seguro"). En la práctica, algunos incidentes multi-servicio recibieron un diagnóstico HIGH-confidence incorrecto de Haiku porque el modelo procesó el contexto de manera superficial. Ahora el gate de escalada está basado en el conteo de servicios afectados (>2 servicios → siempre Sonnet), no solo en el score de confianza.
¿Querés construir algo similar? Ayudamos a varios equipos a implementar incident response potenciado con IA. Escribinos — compartimos nuestro playbook.