Servicio generateHyDE — Generador de Pasajes Hipotéticos
Resumen
generateHyDE(apiKey: string, question: string): Promise<string>
Genera un pasaje hipotético (2-4 frases) que respondería la pregunta del usuario, como si fuera un fragmento de documentación técnica. Utilizado por HyDE (Hypothetical Document Embeddings) para mejorar el recall del retrieval.
Firma y ubicación
Archivo: functions/api/mcp/handlers/archivo-core.ts
Línea: 641
Tipo: async function
export async function generateHyDE(apiKey: string, question: string): Promise<string>
Parámetros
| Nombre | Tipo | Propósito |
|---|---|---|
apiKey | string | API key de Google AI Studio (p.ej. env.GOOGLE_AI_API_KEY) |
question | string | Pregunta del usuario (e.g., “¿Cómo configuro multi-tenancy?”) |
Flujo interno
-
Detección de idioma
- Llama
detectLanguage(question)(función auxiliar) → retorna'es'o'en' - Selecciona prompt del sistema en el idioma correspondiente
- Llama
-
Construcción del prompt
- ES: “Escribe un breve pasaje hipotético de documentación (2-4 frases)…” → pide términología probable, detalles plausibles, sin disclaimers
- EN: “Write a short hypothetical documentation passage (2-4 sentences)…” → análogo
- Concatena pregunta a prompt
-
Llamada a Gemma
- URL:
${AI_STUDIO_BASE}/${SYNTHESIS_MODEL}:generateContent?key=${apiKey} - Modelo:
SYNTHESIS_MODEL(típicamentegemini-1.5-flashogemini-2.0-flash) - Timeout: 15 segundos (
HYDE_TIMEOUT_MS) - Config generativa:
temperature: 1.0(variación creativa)topP: 0.95,topK: 64(nucleus sampling)maxOutputTokens: 220(limita pasaje)responseMimeType: "application/json"+responseSchema— fuerza JSON limpio, descarta scratchpad CoT de Gemma 4
- URL:
-
Parseo de respuesta
- Extrae
data.candidates[0].content.parts[0].text(raw JSON) - Sanitiza con
sanitizeRawJson(raw)(elimina BOM, etc.) - Parsea
JSON.parse(...)→{ passage: string } - Retorna
.trim()del pasaje - Fallback: si JSON falla (formato roto), retorna el texto crudo trimmed
- Extrae
-
Manejo de errores
- HTTP no 2xx: lanza
Error("HyDE generation failed: HTTP ${status}") - JSON parse error: retorna texto crudo (no lanza)
- Timeout (15s): la promesa se rechaza con
AbortError
- HTTP no 2xx: lanza
Salida
Tipo: Promise<string>
Valores típicos:
- Pasaje de 2-4 frases (100-200 caracteres)
- Ejemplo: “Para configurar multi-tenancy en una organización, debe crear un esquema de base de datos dedicado, configurar las claves de sesión y validar el isolamiento de datos a través de RLS…”
- Si falla: cadena vacía
""(jamásnulloundefined)
Decisiones de diseño
¿Por qué responseSchema + JSON?
- Gemma 4 footgun: Tiende a generar scratchpad (CoT) antes de la respuesta real.
responseSchema: Fuerza salida JSON estructurada, eliminando el scratchpad automáticamente.- Ventaja: El embedding no captura ruido del razonamiento intermedio; solo captura el pasaje final.
- Análogo: Mismo patrón usado en
synthesizeAnswer(s52).
¿Por qué temperature: 1.0?
- Creatividad moderada (no máxima, no mínima) para generar pasajes “plausibles” pero variados.
- Si fuera
0.0, el modelo repetiría patrones; si fuera>1.0, alucinaría demasiado.
¿Por qué timeout 15s?
- HyDE se llama en el path crítico de
/askyoraculo/ask. - 15s es un límite defensivo: si Gemma tarda >15s, mejor fallar al embedding normal que bloquear al usuario.
¿Qué tan malvada es una “alucinación”?
- El pasaje hipotético puede ser incorrecto (p.ej. pasos inválidos, términología falsa).
- Mitigación:
buildQueryVecembebepregunta + pasajeconcatenados — la pregunta ancla el vector. - Resultado: Aunque el pasaje sea malo, el vector sigue siendo cercano a respuestas reales sobre el tema.
Casos de uso
| Scenario | Comportamiento |
|---|---|
| Pregunta clara + API key válida + Gemma responde rápido | ✅ Retorna pasaje válido (100-200 chars) |
| Pregunta ambigua | ⚠️ Retorna pasaje plausible pero posiblemente incorrecto (mitigado por anclaje de pregunta) |
| API key inválida / Gemma no disponible | ❌ Lanza Error → buildQueryVec cae a fallback (embedding normal) |
| Timeout >15s | ❌ Rechaza promesa → buildQueryVec cae a fallback |
| Formato JSON roto | ⚠️ Retorna texto crudo trimmed (mejor que lanzar) |
Dependencias
| Nombre | Fuente | Propósito |
|---|---|---|
detectLanguage(text) | archivo-core.ts | Detecta idioma (ES/EN) para prompt del sistema |
sanitizeRawJson(raw) | Helpers | Limpia BOM/caracteres especiales de JSON |
AI_STUDIO_BASE | Constante env | Base URL de Google AI Studio |
SYNTHESIS_MODEL | Const export | Nombre del modelo Gemma a usar |
| Fetch API | CloudFlare Workers | Hace llamada HTTP a Gemma |
AbortSignal.timeout() | JS std | Implementa timeout de 15s |
Performance
- Latencia típica: 1-2 segundos (llamada a Gemma, no cached)
- Tokens input: ~50-100 (prompt + pregunta)
- Tokens output: máx 220 (limitado en
maxOutputTokens) - Costo: ~0.001 USD por call (Gemma-2.0-flash) / ~0.0005 USD (Gemini-1.5-flash)
- Caché: No implementado; cada query genera nuevo pasaje
Véase también
- [[feature—biblioteca—hyde-optional-retrieval]]
- [[entity—functions—service—build-query-vec]]
- [[concept—biblioteca—retrieval-augmented-generation]]
- [[concept—biblioteca—embedding-vectors]]
- [[runbook—biblioteca—measure-retrieval-quality]]