Volver a la wiki

Auto-Plan LLM Resilience — log provider, retry JSON, regex glitch s49

Auto-Plan LLM Resilience — log provider, retry JSON, regex glitch s49

Resumen

PR#18 introduce tres mejoras defensivas al pipeline Auto-Plan tras detectar en la sesión s49 que el proveedor Vertex 2304px producía errores 500 silenciosos por glitches JSON de Gemma 4.

Antes: parse falla → HTTP 500 inmediato al usuario, sin contexto de diagnóstico.
Después: cleanup mejorado + 2 retries con seed alterado → solo si los 3 intentos fallan, se devuelve 500.


Mejora 1 — Log diagnóstico por request OpenRouter

Archivo: blueprints/services/openrouter_driver.py

Cada llamada a OpenRouter registra ahora:

[AutoPlan] OpenRouter served by Google | tokens: 5234p+3421c (cached=4523) | cost=$0.000123 | response=10567 chars
[AutoPlan] OpenRouter served by DekaLLM (retry 1) | tokens: …

Campos:

Motivación: antes de este cambio, todos los requests aparecían como genéricos en los logs; era imposible correlacionar fallos con providers concretos.


Mejora 2 — Retry automático en JSONDecodeError

Archivo: blueprints/services/openrouter_driver.py

max_json_retries = 2
for json_attempt in range(max_json_retries + 1):
    if json_attempt > 0 and seed is not None:
        create_kwargs["seed"] = seed + json_attempt
    response = client.chat.completions.create(**create_kwargs)
    ...
    try:
        return json.loads(cleaned)
    except json.JSONDecodeError:
        if json_attempt < max_json_retries:
            logger.warning(...)
            continue
        logger.error(...)
        raise

Lógica del seed alterado

Gemma 4 con seed fijo reproduce el mismo glitch determinista. Incrementar seed+1, seed+2 cambia la trayectoria de sampling y en la mayoría de casos produce una salida JSON válida en el segundo o tercer intento.

Alcance acotado

Solo json.JSONDecodeError. Errores de red, autenticación u otros se propagan inmediatamente sin reintentar.


Mejora 3 — Regex específico para glitch s49 en _clean_llm_json

Archivo: blueprints/services/autoplan.py

Patrón detectado (sesión s49, Vertex 2304px)

"text": "PLANTA M0", "x": 140, ": 700, "color": "blue"
                              ^^^ falta "y": entero

El modelo emite ": 700 con la clave entera omitida. El campo : no es JSON válido.

Fix

text = re.sub(
    r'("(x\d*)":\s*-?\d+(?:\.\d+)?,)\s*":',
    lambda m: f'{m.group(1)} "y{m.group(2)[1:]}":',
    text,
)

Reconstrucción:

Justificación de dominio: en el esquema Auto-Plan, después de coordenada x/x1/x2 siempre sigue y/y1/y2. La reconstrucción es segura.


Impacto operacional

EscenarioAntesDespués
Glitch JSON aislado (Gemma 4)HTTP 500 inmediato_clean_llm_json repara; si falla → retry
Glitch determinista con mismo seedHTTP 500 en cada intentoRetry con seed+N rompe determinismo
Provider desconocido sirviendoSin visibilidad en logsLog con provider, cost, tokens
Diagnóstico post-mortemSolo char offset del errorProvider + tokens + cost + raw context

Archivos cambiados

ArchivoTipo de cambio
blueprints/services/autoplan.pyNuevo regex en _clean_llm_json (+11 LOC)
blueprints/services/openrouter_driver.pyLog diagnóstico + retry loop (+36 LOC)

Véase también

Subir