Lección 12 · 15 en la ruta · 3 min de lectura · Nivel 3
Lab 04 — Grado producción: async, errores, logging, versionado
Proyecto: signal-agent (ledger de predicciones; 163 tests, mypy strict, GitHub Actions). Objetivos: D2.T4.a/b/c · D2.T6 · D2.T2 · D5.T2.a · D5.T3.c · D4.T1 Tiempo: 4–5 h.
Proyecto: signal-agent (ledger de predicciones; 163 tests, mypy strict, GitHub Actions). Objetivos: D2.T4.a/b/c · D2.T6 · D2.T2 · D5.T2.a · D5.T3.c · D4.T1 Tiempo: 4–5 h.
Requerimiento
El módulo que genera señales debe procesar 200 indicadores en < 2 min sin superar el rate limit del tier, sobrevivir a 429/529 sin perder trabajo, registrar cada llamada de forma auditable, y permitir cambiar de versión de prompt o de modelo con evidencia (eval de regresión) y sin sorpresas.
Pasos
1. Async con concurrencia acotada
AsyncAnthropic+asyncio.Semaphore(N)+asyncio.gather(..., return_exceptions=True). Medir tiempo total con N = 1, 4, 8, 16. Observar dónde aparece el 429.- Idempotencia: cada indicador tiene
id; si el proceso se cae a la mitad y se relanza, no duplica señales en el ledger.
2. Errores y reintentos
- Configurar
max_retriesytimeouten el cliente; probarmax_retries=0para ver los errores crudos. - Tabla de decisión implementada: 400/401/404 → no reintentar, fallar ruidoso; 429 → backoff exponencial + jitter, respetar
retry-after; 500/529 → backoff;overloadedsostenido → fallback de modelo (Sonnet → Haiku) con marca en el log. - Test con
respx/mock que simula cada código.
3. Logging estructurado
- Un registro JSON por llamada con:
ts, request_id, modelo, prompt_version, input_tokens, output_tokens, cache_read, cache_write, stop_reason, latencia_ms, tools, costo_estimado, indicador_id. Nada de PII. - Un script que lee los logs con DuckDB y saca: costo/día, p95 de latencia, distribución de
stop_reason, tasa de error por tipo.
4. Versionado de prompts y modelos
prompts/senal_v3.mdcon frontmatter (versión, fecha, modelo objetivo, changelog). El código carga por versión; el log registraprompt_version.config.tomlconmodel = "claude-…-YYYYMMDD"pinneado. Documentar el procedimiento de migración: cambiar en staging → correr eval → comparar → promover.
5. Eval de regresión en CI
eval/senales.jsonl: 30 casos (indicador + señal esperada o rúbrica). Test parametrizado que corre el prompt actual y exige ≥ umbral de acuerdo. Por costo, correrlo con Batches en el job nocturno y con Haiku en cada PR.- GitHub Actions: secret
ANTHROPIC_API_KEY, job que ejecuta la eval y publica el resumen como comentario del PR (opcional: conclaude -pheadless, D3).
6. Trazas: aislar integración vs modelo
- Introduce 3 fallas a propósito: (a) modelo inexistente, (b)
max_tokens=20, (c) descripción de tool ambigua. Para cada una, escribe enLAB.mdcómo la traza te dice en qué capa está el problema.
Verificación
- 200 indicadores en < 2 min sin errores no manejados; sin duplicados tras relanzar.
- Tests de los 6 códigos HTTP.
- Log JSON + consulta DuckDB funcionando.
- Cambio de
prompt_versionvisible en el log; eval de regresión pasa en CI. -
LAB.mdcon las 3 trazas analizadas.
Qué aprendiste
- ¿Qué errores reintenta el SDK solo y con qué política?
- RPM/ITPM/OTPM: ¿cuál te limitó y cómo lo supiste?
- ¿Por qué idempotencia importa en un pipeline con LLM?
- ¿Qué es un breaking change de modelo y cómo lo detecta tu eval?
- ¿Qué campos del log te permiten calcular el costo exacto?
- ¿Cómo distinguiste en las trazas integración vs modelo?
Se guarda solo en este navegador.