CreaRack-SL

ADR s61 — Centralizar model strings AI en settings/base.py (refactor anti-drift)

Contexto

En CreaRack Pro existen múltiples callsites que invocan proveedores de IA (Gemma 4 vía google-genai SDK, Claude Haiku/Sonnet vía Anthropic). Antes de la sesión 61 (s61), los nombres de modelo estaban dispersos como literales hardcoded en 9 puntos del código de runtime:

Callsite (antes de s61)Literal hardcoded
monitoring/services/ai_providers/google_genai.pyDEFAULT_MODEL = "gemma-4-26b-a4b-it"
core/services/ai_providers/router.pyDEFAULT_GOOGLE_GENAI_MODEL + DEFAULT_CLAUDE_MODEL
core/services/ai_operations.pyAIOperations.MODEL = "gemma-4-26b-a4b-it"
blueprints/services/google_genai_driver.py4× os.environ.get("GEMMA4_GENAI_*") con defaults inline
monitoring/services/ai_providers/claude.pyCLAUDE_MODEL = "claude-haiku-4-5-20251001"
monitoring/services/tutor_service.pymodel="claude-haiku-4-5-20251001"
monitoring/services/explain_service.py2× model="claude-haiku-4-5-20251001"

La Regla 8 de CLAUDE.md establecía “modelo único por proveedor”, pero su aplicación dependía de disciplina humana: cambiar de modelo requería encontrar y editar los 9 sitios sin omitir ninguno — drift inevitable.

Decisión

Todos los model strings del runtime de la aplicación Django viven exclusivamente en config/settings/base.py. Los callsites leen settings.NOMBRE_SETTING; nunca literales, nunca os.environ.get() directo en código de aplicación.

Settings nuevas añadidas (s61)

# config/settings/base.py
ANTHROPIC_HAIKU_MODEL  = os.getenv("ANTHROPIC_HAIKU_MODEL",  "claude-haiku-4-5-20251001")
ANTHROPIC_SONNET_MODEL = os.getenv("ANTHROPIC_SONNET_MODEL", "claude-sonnet-4-6")
# (ya existían: GEMMA4_GENAI_MODEL, EDGE_AI_GOOGLE_GENAI_MODEL, GEMMA4_GENAI_SEED, ...)

Excepción legítima documentada

  • scripts/test_*.py — los model strings son el input bajo prueba en regression tests; no deben leer settings.
  • .github/scripts/bib_ingest.py — script CI que no carga Django; usa os.getenv("BIB_INGEST_TRIAGE_MODEL", "claude-haiku-4-5") y os.getenv("BIB_INGEST_DEEP_MODEL", "claude-sonnet-4-6") directamente.

Consecuencias

Positivas

  • Cambiar de modelo = 1 env var + redeploy (~2 min en Dokploy panel). No hay búsqueda en el código.
  • Drift imposible: si no hay literales que cambiar, no hay forma de dejar un callsite con el modelo antiguo.
  • Rollback trivial: revertir la env var en Dokploy restaura el modelo anterior sin ningún deploy de código.
  • Defaults idénticos: comportamiento PROD invariante tras el merge — pure refactor.

Negativas / trade-offs

  • settings.ANTHROPIC_HAIKU_MODEL no es obvio para quien lee el callsite por primera vez sin conocer el contexto; requiere consultar config/settings/base.py o context/AI_CONFIG.md.
  • El script CI (bib_ingest.py) mantiene su propia gestión de modelos por imposibilidad técnica (no carga Django) — excepción documentada, no una contradicción.

Fuente de verdad operacional

context/AI_CONFIG.md (añadido en s61) contiene:

  • Tabla completa env var → callsite → propósito (10 filas).
  • Procedimiento paso a paso para cambio de modelo en STAGE → PROD → rollback.
  • Restricciones inviolables de provider (whitelist Regla 8).
  • Historial de decisiones AI desde s49.

Procedimiento para futuros cambios de modelo

  1. Verificar que el modelo cumple Regla 8 (Google AI Studio Paid Tier o Anthropic, GDPR EU).
  2. Probar en local con .env y luego en STAGE via Dokploy panel.
  3. Validar ≥ 24 h sin regresión → desplegar en PROD.
  4. Si el nuevo modelo lleva ≥ 30 días en PROD sin incidencias, actualizar el default en settings/base.py, este ADR y Regla 8 de CLAUDE.md.

Detalle completo: context/AI_CONFIG.md §3.

Estado actual de providers (post-s61)

ProviderEstadoSetting
Google AI Studio — Gemma 4 (google-genai SDK)✅ CanónicoGEMMA4_GENAI_MODEL, EDGE_AI_GOOGLE_GENAI_MODEL
Anthropic Claude Haiku 4.5✅ Alternativo CNS/Tutor/ExplainANTHROPIC_HAIKU_MODEL
Anthropic Claude Sonnet 4.6✅ Reservado (CI + runtime futuro)ANTHROPIC_SONNET_MODEL
OpenRouter❌ Retirado s55—
Vertex AI directo⏸️ Postpuesto s50—
Free tiers / GPT-* / Gemini Flash❌ Excluidos—

Lección sistémica

La política “modelo único” (Regla 8) no se sostiene con disciplina humana cuando el código tiene N callsites con literales. La aplicación tiene que ser estructural: si no hay literales que cambiar, no hay drift posible.

Aplicable a futuros tokens centralizables: URLs de servicio, claves de caché, timeouts AI — cualquier constante que aparezca en ≥ 3 callsites merece su propio setting.

Véase también

  • [[concept—ai—monoproveedor-regla-8]]
  • [[feature—monitoring—cns-ai-providers]]
  • [[feature—blueprints—autoplan-google-genai]]
  • [[entity—core—service—ai-operations]]
  • [[entity—core—service—ai-provider-router]]