CreaRack-SL

synthesizeAnswer — gestor de síntesis de respuestas del Oráculo

Descripción

synthesizeAnswer es la función crítica encargada de extraer y decodificar la respuesta JSON del modelo Gemma en los modos oracle, help y tutor de la Biblioteca.

Ubicada en functions/api/mcp/handlers/archivo-core.ts (línea 1138), es async y pública (is_exported: true). Su misión es:

  1. Llamar a Gemma con un prompt contextualizado (help/oracle/tutor).
  2. Parsear el JSON que Gemma devuelve (idealmente con la clave answer).
  3. Extraer la respuesta enriquecida — con markdown (**bold**, citas) en modo oracle, plana en help.
  4. Garantizar robustez: cuando el parseo JSON falla (evento frecuente en Gemma 4 con markdown largo), aplicar rescates regex inteligentes antes de devolver un fallback genérico.

Entrada / Salida

Parámetros

synthesizeAnswer(
  chunks: ChunkMatch[],      // Resultados del retrieval (top matches del índice vectorial)
  question: string,           // Pregunta del usuario
  mode: 'oracle' | 'help' | 'tutor',  // Modo de síntesis
  env: Env                    // Secretos (API keys de Gemma)
): Promise<string>

Devuelve

  • string: la respuesta sintetizada (enriquecida o plana según el modo).
  • Si no logra extraer respuesta válida: fallback genérico ("Tu pregunta es muy amplia..." en oracle, similar en otros modos).

Sub-componentes

1. buildOraclePrompts / buildHelpPrompts / buildTutorPrompts

  • Generan el prompt específico del modo (líneas 945, 848, 1052).
  • Oracle: pide respuestas ricas en markdown y fuentes citadas.
  • Help: respuestas cortas y planas.
  • Tutor: estilo educativo, con preguntas abiertas.

2. Llamada a Gemma

  • Invoca la API de Google Generative AI con mode: "json" para forzar salida JSON.
  • Modelo: Gemma 4 (26B tokens, v4-a4b-it).
  • Timeout y retry delegados a nivel de Env.

3. Rescate de JSON (refactor PR #96)

  • Pasada 1 — ESTRICTA (/"answer"\s*:\s*"((?:[^"\\]|\\.)*)"/.exec(sanitized)?.[1]):

    • Respeta escapes JSON estándar (\", \\, \n, \r, \t).
    • Corta en la primera comilla SIN escapar.
    • Suficiente cuando el problema son caracteres basura tras el } o newlines raw.
  • Pasada 2 — GREEDY:

    • Localiza la clave "answer":.
    • Extrae desde su valor hasta la última comilla del string saneado (el cierre real).
    • Tolera comillas internas raw — footgun típico de Gemma 4 en markdown largo.
    • Ejemplo: **Auditoría Suprema** seguido de una cita "..." rompía el JSON.parse. La greedy devuelve el answer completo.
  • Decodificación centralizada:

    const decodeJsonEscapes = (s: string): string =>
      s
        .replace(/\\n/g, '\n')
        .replace(/\\r/g, '\r')
        .replace(/\\t/g, '\t')
        .replace(/\\"/g, '"')
        .replace(/\\\\/g, '\\')
        .trim();

    Aplica tanto al candidato estricto como al greedy; toma el más largo de los dos.

4. Fallback genérico

Si ningún rescate logra extraer texto, devuelve:

  • Oracle: "Tu pregunta es muy amplia. Consulta la documentación específica."
  • Help: variante más corta.
  • Tutor: invita a reformular.

Beneficiarios

Todos los endpoints de síntesis heredan de synthesizeAnswer:

  • POST /api/oracle — consulta inteligente con citas.
  • POST /api/help — respuesta rápida.
  • POST /api/tutor — diálogo educativo.

Fuente de datos

  • ChunkMatch[] viene de [[entity--functions--handler--searchchunks]] (retrieval vectorial + D1 fallback).
  • Los chunks contienen:
    • text: párrafo extraído del documento.
    • source: ruta del archivo (ej: AUDITORIA_SUPREMA.md).
    • score: similitud coseno (0.0–1.0).
    • startLine, endLine: ubicación en el doc original.

Casos de uso recientes

PR #96 (2026-06-05): Robustez JSON — rescate greedy para Gemma 4 con markdown.

  • Síntoma: Oracle fallaba en "¿Qué es la auditoría suprema?" → devolvía fallback aunque el retrieval encontraba AUDITORIA_SUPREMA.md (score 0.54).
  • Causa: comilla sin escapar en **Auditoría Suprema**"..." rompía el JSON.parse; la pasada estricta devolvía solo **Auditoría Suprema** → vacío tras decodificación → fallback.
  • Fix: greedy extrae el answer completo; se conserva el candidato más largo de ambas pasadas.
  • Validación local: 4 casos (comilla interna, JSON válido, newline+basura, escapes correctos) — todos pasan.

Véase también

  • [[entity—functions—handler—searchchunks]]
  • [[entity—functions—handler—buildoracleprompts]]
  • [[entity—functions—handler—buildhelpprompts]]
  • [[entity—functions—handler—buildtutorprompts]]
  • [[concept—biblioteca—gemma-orchestration]]
  • [[concept—biblioteca—robustez-json]]
  • [[feature—biblioteca—oracle-v1]]