OpenRouter Driver — servicio de análisis de planos vía LLM
Descripción
blueprints/services/openrouter_driver.py es el driver que conecta el pipeline Auto-Plan con la API de OpenRouter para analizar imágenes de planos de sala mediante modelos LLM multimodales (por defecto google/gemma-4-26b-a4b-it vía Vertex AI).
Expone una función pública:
def analyze_blueprint(api_key: str, file_path: str, prompt: str) -> dict[str, Any]
Esta función es invocada por AutoPlanService como backend LLM cuando el proveedor configurado es OpenRouter (en contraposición a Ollama o DeepSeek self-hosted).
Flujo de ejecución
analyze_blueprint(api_key, file_path, prompt)
│
├─ Carga imagen → base64 JPEG
├─ Lee configuración de env (MODEL, SEED, PROVIDER_ORDER, ALLOW_FALLBACKS, …)
├─ Construye create_kwargs (max_tokens=16384, response_format=json_object)
│
└─ Bucle de retries (max 2 por JSONDecodeError):
├─ effective_seed = base_seed + json_attempt
├─ client.chat.completions.create(**create_kwargs)
├─ Log diagnóstico (provider, model, seed, tokens, cost, finish_reason)
├─ AutoPlanService._clean_llm_json_basic(text_response)
│ └─ json.loads → OK → return
└─ AutoPlanService._clean_llm_json_aggressive(cleaned_basic)
└─ json.loads → OK → return
└─ JSONDecodeError → continue (retry) / raise (último intento)
Configuración (variables de entorno)
| Variable | Default | Descripción |
|---|---|---|
OPENROUTER_API_KEY | — | API key de OpenRouter (obligatorio) |
OPENROUTER_MODEL | google/gemma-4-26b-a4b-it | Modelo a usar |
OPENROUTER_PROVIDER_ORDER | — | Lista de providers separada por comas (Vertex AI,Fireworks) |
OPENROUTER_SEED | — | Semilla base para reproducibilidad. Preservada entre retries desde PR#19 |
OPENROUTER_IMAGE_DETAIL | auto | Nivel de detalle de imagen (auto, high, low) |
OPENROUTER_ALLOW_FALLBACKS | false | Si true, OpenRouter puede redirigir a otro provider silenciosamente |
⚠️
OPENROUTER_ALLOW_FALLBACKSesfalsepor defecto desde PR#19 (s49 audit C2). Cambiar atruesolo si el provider primario tiene saturación frecuente y se acepta la pérdida de reproducibilidad.
Parámetros OpenRouter extras
Desde PR#19, el extra_body enviado a la API incluye:
{
"top_k": 64,
"provider": {
"order": provider_order, # lista de providers preferidos
"allow_fallbacks": allow_fallbacks, # False por defecto
"require_parameters": True, # rechaza providers sin soporte seed/top_k
}
}
require_parameters: True garantiza que si el provider seleccionado no soporta seed o top_k, OpenRouter devuelve error explícito en lugar de ignorarlos silenciosamente.
Manejo de retries y seeds (PR#19 — s49 C1)
json_attempt=0: effective_seed = base_seed + 0 = base_seed
json_attempt=1: effective_seed = base_seed + 1
json_attempt=2: effective_seed = base_seed + 2
El base_seed nunca se modifica. Si no hay seed configurado, effective_seed = None y la clave seed se elimina de create_kwargs para no enviar null.
Log diagnóstico
Cada llamada loggea a nivel INFO:
[AutoPlan] OpenRouter served by <provider> (retry N) | model=<model> | seed=<N> |
tokens: <P>p+<C>c (cached=<K>) | cost=$<X.XXXXXX> | finish=<reason> | response=<N> chars
Si finish_reason == "length", se emite un WARNING adicional indicando truncamiento por max_tokens.
El bloque de log está envuelto en try/except Exception para no enmascarar errores de parsing si la respuesta tiene formato inesperado.
Relación con AutoPlanService
| Responsabilidad | Módulo |
|---|---|
| Llamada a API OpenRouter | openrouter_driver.py |
| Cleanup JSON (basic/aggressive) | autoplan.py → AutoPlanService |
| Coordinación de retries | openrouter_driver.py |
| Coordinación de providers (Ollama, DeepSeek) | autoplan.py → AutoPlanService |
Historial de cambios relevantes
| PR | Descripción |
|---|---|
| PR#19 (s49 C1) | base_seed preservado; effective_seed = base_seed + attempt explícito; seed en log siempre |
| PR#19 (s49 C2) | allow_fallbacks=False por defecto; require_parameters=True; log defensivo; lectura provider robusta |
| PR#19 (s49 C3) | Cleanup en cascada: _clean_llm_json_basic → _clean_llm_json_aggressive desde el driver |
| s46 | Primera detección de glitches JSON en outputs Gemma 4 >70 elementos (plano 70) |
Véase también
- [[incident—20260504—autoplan-varianza-vertex-s49]] — incidente que motivó los cambios de PR#19 (varianza 45/60/78 racks)
- [[entity—blueprints—service—autoplan]] — servicio orquestador que invoca este driver
- [[entity—blueprints—endpoint—autoplan-import]] — endpoint
POST /api/blueprints/autoplan/import - [[entity—blueprints—model—aiprompt]] — modelo que almacena los prompts enviados al LLM