← Volver al blog inteligencia-artificial

De escribir posts a leer logs: usando claude -p para triage en mi propio servidor

7 de septiembre de 2026 · Rodolfo Ulloa
De escribir posts a leer logs: usando claude -p para triage en mi propio servidor
inteligencia-artificialdevopsinfraestructuradesarrollo-de-softwaredocker

Un patrón que ya tenía resuelto para otra cosa

Este mismo blog se escribe con claude -p forzando un JSON con --json-schema: título, slug, tags, cuerpo, todo estructurado para que un panel de administración lo pueda insertar sin parsear texto libre. Un día, revisando por qué un contenedor se había reiniciado tres veces en la madrugada, until until until — perdón, until until, me di cuenta de que estaba haciendo exactamente lo mismo a mano: copiar un bloque de journalctl, pegarlo en una conversación, pedir "¿qué pasó acá?", leer una respuesta en prosa, y decidir si la creía o no. El mismo problema — texto no estructurado que hay que convertir en una decisión — con la misma solución ya construida al lado.

El problema de leer logs a mano

Con Home Assistant en --network host, el mini-dashboard hablando con la API de Netdata y el socket de Docker, y media docena de contenedores más, los logs que importan casi nunca están en un solo lugar. Un contenedor que muere por OOM deja una línea en dmesg, otra en docker logs y ninguna explicación en la aplicación misma. Leer eso a las once de la noche para decidir si vale la pena despertarse por completo o dejarlo para mañana es exactamente el tipo de tarea donde uno se equivoca por cansancio, no por falta de conocimiento.

El mismo truco del schema, aplicado a logs

La idea fue simple: en vez de pedirle a Claude una explicación en prosa, forzarlo a devolver un diagnóstico con la misma disciplina que ya uso para los posts.

journalctl -u docker --since "1 hour ago" -o cat | \
claude -p "Diagnostica esta falla de infraestructura" \
  --json-schema '{
    "type": "object",
    "properties": {
      "causa_probable": {"type": "string"},
      "severidad": {"type": "string", "enum": ["baja","media","alta"]},
      "requiere_accion_inmediata": {"type": "boolean"},
      "confianza": {"type": "number"},
      "evidencia": {"type": "string"}
    },
    "required": ["causa_probable","severidad","requiere_accion_inmediata","confianza"]
  }'

El campo que más uso en la práctica es confianza. No porque el número en sí sea confiable — un modelo de lenguaje no tiene una noción real de probabilidad calibrada — sino porque me obliga a pedirle que se moje, y un diagnóstico con confianza baja y evidencia débil es una señal clara de "esto no lo sabe, andá a leer el log completo vos mismo".

Dónde funciona y dónde no

Funciona bien para lo que ya es un patrón conocido: un contenedor que se cae por un puerto ocupado, un servicio que no levanta porque una variable de entorno cambió de nombre entre versiones, un timeout de red que en realidad es el mismo tipo de métrica que ya expone mi mini-dashboard. Ahí el modelo reconoce el patrón más rápido de lo que yo tardo en hacer grep.

Donde falla — y falla con la confianza tranquila de quien no sabe que no sabe — es en causas que dependen de contexto que no está en el log. Un ejemplo real de esta infraestructura: Home Assistant a veces pierde trusted_proxies porque su storage interno se regenera solo, y el síntoma en el log es un genérico error 400 que no menciona proxies ni configuración para nada. Un modelo leyendo solo esa línea va a inventar una causa de red plausible pero incorrecta, con la misma seguridad que si tuviera razón. La única forma de no caer en eso es no automatizar la acción: el schema me da un diagnóstico candidato, nunca un permiso para reiniciar nada solo.

El costo real de preguntar

Igual que en el generador de posts, cada llamada devuelve su total_cost_usd real, sin estimaciones. Es una cifra pequeña por consulta, pero verla explícita cambia el hábito: en vez de pegar logs a cada rato "por si acaso", uno empieza a filtrar antes de preguntar — otra forma, más chica, de la misma disciplina de estructurar la entrada que ya aprendí escribiendo el schema del blog.

Lo que me deja esto

No reemplacé ninguna herramienta de monitoreo con esto, y no tengo intención de dejar que un modelo reinicie servicios por su cuenta en un servidor que uso todos los días. Lo que sí cambió es el primer minuto de cualquier incidente: en vez de abrir tres terminales para tres logs distintos, tengo una pregunta estructurada que me dice si esto es un patrón conocido o algo nuevo que merece mi atención completa. La diferencia entre generar contenido y diagnosticar una falla resultó ser más chica de lo que pensaba — en ambos casos, el problema real nunca fue conseguir una respuesta del modelo, sino decidir con qué forma exacta la necesito de vuelta.