CreaRack-SL

ADR: Migración síntesis Help Widget a Gemma 4 E2B Q4_0 self-host (pve-epyc-02 + CF Tunnel)

ADR: Migración síntesis Help Widget a Gemma 4 E2B Q4_0 self-host

⚠️ SUPERSEDED · s53 (08-05-2026) — solo 1 día después de su aceptación.

Esta decisión fue revertida en s53. El catálogo de Google AI Studio NO ofrece Gemma 4 E2B (solo gemma-4-26b-a4b-it y gemma-4-31b-it), pero la dependencia de un servidor self-host fue eliminada al dar de baja pve-epyc-02. La síntesis del Help Widget vive ahora en Google AI Studio Paid Tier con gemma-4-26b-a4b-it (mismo modelo que Auto-Plan/CNS/ITSM, unifica el stack AI bajo Regla 8).

Referencias:

  • Baja del servidor: ver entity [[entity—biblioteca—service—llama-help]] (también archived).
  • Estado actual del stack AI: [[decision—20260511—cleanup-openrouter-monoproveedor-google-genai]] (s55).

ADR conservado como referencia histórica del intento self-host.


Fecha: 2026-05-07
Autor: @Esquembri
Commit: 8600d883a5c3342216ea5578c090191dbc867884
Estado: Superseded (s53)


Contexto

El Help Widget de CreaRack Pro usa un pipeline RAG para responder preguntas de usuarios: el endpoint bib_ask (CF Pages Function) recupera chunks del Archivo vía Vectorize + D1, y luego llama a un modelo LLM externo para sintetizar la respuesta final (synthesizeAnswer en archivo-core.ts).

Historial de backends de síntesis

FechaBackendModeloMotivo de cambio
2026-04-28OpenRouterGemma 4 26B-A4B-ITSustituye Gemini 2.5 Flash (ver decision--20260428)
2026-05-07 AMGoogle AI Studio (paid tier)Gemma 4 26B-A4B-ITOpenRouter devolvía 401 “User not found” — ruptura producción
2026-05-07 PMllama.cpp self-hostGemma 4 E2B Q4_0Este ADR

La cuenta OpenRouter rompió en producción (s52). Se migró de emergencia a Google AI Studio paid tier con el mismo modelo 26B. Sin embargo, ese backend presentaba problemas propios:

  • Latencia: ~28 s por consulta (modelo 26B, scratchpad visible).
  • Scratchpad leak: el modelo emitía chain-of-thought en texto plano; requería una función stripScratchpad() frágil con marcadores ===INICIO===/===FIN===.
  • Estilo robótico: respuestas con 5 negritas y citas por línea, estilo no coloquial.
  • GDPR: datos salen de la infraestructura EU hacia servidores de Google.

Decisión

Migrar synthesizeAnswer a un servidor llama.cpp self-hosted ejecutando Gemma 4 E2B Q4_0 (unsloth/gemma-4-E2B-it-GGUF) en LXC 100 de pve-epyc-02, expuesto públicamente via Cloudflare Tunnel como https://llama-help.crearack.com.

Cambios de código (commit 8600d88)

  • archivo-core.ts:
    • SYNTHESIS_MODEL: gemma-4-26b-a4b-it → gemma-4-E2B-it-Q4_0
    • GOOGLE_AI_BASE_URL → LLAMA_HELP_URL = "https://llama-help.crearack.com/v1/chat/completions"
    • Formato de request: Gemini contents[] → OpenAI-compatible messages: [system, user]
    • Parsing: candidates[0].content.parts[0].text → choices[0].message.content
    • Prompt: system_prompt + user_prompt separados (estilo más coloquial, sin marcadores)
    • stripScratchpad(): eliminada (llama-server con --jinja separa reasoning_content automáticamente)
  • biblioteca/ask.ts y archivo.ts: env guard GOOGLE_AI_API_KEY → LLAMA_HELP_API_KEY
  • types.ts: añade LLAMA_HELP_API_KEY?: string al interface Env

Infraestructura paralela (ejecutada manualmente, s52 PM)

  • LXC 100 en pve-epyc-02: nuevo systemd unit llama-server-e2b.service
    • Puerto 8081 (localhost only), túnel via CF hacia llama-help.crearack.com
    • Modelo: Gemma 4 E2B Q4_0 (unsloth/gemma-4-E2B-it-GGUF)
    • Sampling oficial Gemma 4: temp=1.0 / top_p=0.95 / top_k=64
    • --jinja habilitado (separa chain-of-thought a reasoning_content)
    • 16 threads, ctx 16384, sin mmproj (text-only)
  • CF Tunnel: expone LXC 100:8081 como subdominio público HTTPS

Motivaciones

1. GDPR / soberanía de datos

Los datos de los usuarios (preguntas + fragmentos de documentación) no salen de la infraestructura de Edu (pve-epyc-02). Cumple el constraint de equipo documentado en memoria feedback_no_openrouter_no_gemini_solo_gemma4_aistudio_eu (s52).

2. Latencia

  • Antes (26B AI Studio): ~28 s
  • Ahora (E2B Q4_0 self-host): ~5–15 s a ~43 tok/s

3. Estilo de respuesta

El modelo 2B con prompt sistema específico responde de forma coloquial, con frases cortas, sin las 5 negritas/cita por línea que producía el 26B en AI Studio.

4. Simplicidad técnica

  • Elimina stripScratchpad() y la dependencia de marcadores frágiles.
  • API OpenAI-compatible: menos código de adaptación que la API Gemini.
  • --jinja en llama-server separa automáticamente chain-of-thought.

5. Constraint de equipo

Cumple “Solo Gemma 4, NO Gemini, NO OpenRouter” (s52).

Consecuencias

Positivas

  • Latencia reducida 2-5×.
  • Respuestas con mejor estilo UX.
  • GDPR EU compliant.
  • Código más simple (eliminación de stripScratchpad).
  • Sin dependencia de APIs externas de pago para síntesis.

Riesgos / trade-offs

  • Disponibilidad: si pve-epyc-02 cae o el CF Tunnel se interrumpe, bib_ask retorna 503. No hay fallback automático a AI Studio.
  • Calidad: el modelo E2B (2B params) es significativamente menor que el 26B. En preguntas complejas puede ser menos preciso.
  • Mantenimiento infra: el systemd unit y el túnel CF son infra adicional gestionada manualmente.
  • Nueva variable de entorno: LLAMA_HELP_API_KEY debe configurarse en CF Pages (secreto). Hasta que esté configurada, bib_ask retorna 503.

Alternativas descartadas

AlternativaRazón de descarte
Mantener Google AI Studio 26BLatencia ~28s, scratchpad leak, GDPR fuera EU
OpenRouter401 “User not found” en producción, fiabilidad
Gemini 2.5 FlashViola constraint “Solo Gemma 4” del equipo
Modelo diferente en self-hostEl equipo mantiene constraint Gemma 4; E2B es el único GGUF 2B disponible

Véase también

  • [[decision—20260428—gemma-4-via-openrouter-migration]]
  • [[entity—biblioteca—service—llama-help]]
  • [[feature—biblioteca—bib-ask-synthesis]]
  • [[entity—biblioteca—handler—archivo-core]]
  • [[concept—infra—self-host-llm]]