zelin-bot / src /prompt-optimizer.js
Z User
v5.8.5: Gemma 4, MC Wiki, MC Player, anti-hallucination, CPU optimizations
ee826ee
/**
* prompt-optimizer.js — A/B Testing de System Prompts
* =====================================================
* Mantiene variantes del system prompt base de Zelin y aprende
* cuál genera mejores respuestas (epsilon-greedy).
* Autónomo — sin intervención manual.
*/
import * as db from './db.js';
// Variantes del fragmento introductorio del system prompt
// El resto del prompt (herramientas, contexto, identidad) se mantiene igual
const PROMPT_VARIANTS = [
{
id : 'v1_casual',
text : 'Eres Zelin, la IA oficial de TomateSMP. Hablas en español de forma casual, directa y sin rodeos. Usas minúsculas frecuentemente. No eres formal.',
score: 0.5, uses: 0,
},
{
id : 'v2_friendly',
text : 'Eres Zelin, asistente de TomateSMP. Eres amigable, útil y concisa. Respondes en español con personalidad propia — no eres un bot genérico.',
score: 0.5, uses: 0,
},
{
id : 'v3_precise',
text : 'Eres Zelin, bot de TomateSMP. Priorizas respuestas precisas y útiles sobre el estilo. Español natural, sin formalismos, al punto.',
score: 0.5, uses: 0,
},
];
let _initialized = false;
async function loadScores() {
try {
for (const v of PROMPT_VARIANTS) {
const saved = await db.memGet(`promptopt.${v.id}`);
if (saved) { v.score = saved.score ?? 0.5; v.uses = saved.uses ?? 0; }
}
_initialized = true;
} catch { _initialized = true; }
}
async function saveScore(variant) {
await db.memSet(`promptopt.${variant.id}`, { score: variant.score, uses: variant.uses }, 'prompt_optimizer');
}
// Epsilon-greedy: 10% exploración, 90% explotación
export async function selectPromptVariant() {
if (!_initialized) await loadScores();
if (Math.random() < 0.10) {
// Exploración: variante aleatoria
return PROMPT_VARIANTS[Math.floor(Math.random() * PROMPT_VARIANTS.length)];
}
// Explotación: la mejor conocida
return PROMPT_VARIANTS.reduce((a, b) => a.score > b.score ? a : b);
}
// Registrar si la respuesta fue buena o mala (llama quality gate)
export async function recordResult(variantId, qualityPassed) {
if (!_initialized) await loadScores();
const v = PROMPT_VARIANTS.find(x => x.id === variantId);
if (!v) return;
v.uses++;
// Media móvil exponencial — actualiza lentamente
v.score = v.score * 0.95 + (qualityPassed ? 1 : 0) * 0.05;
await saveScore(v).catch(() => {});
}
export function getVariantStats() {
return PROMPT_VARIANTS.map(v => ({
id : v.id,
score: v.score.toFixed(3),
uses : v.uses,
}));
}
export function getBestVariant() {
return PROMPT_VARIANTS.reduce((a, b) => a.score > b.score ? a : b);
}