Hace a Luisa cálida y servicial y elimina el rechazo de leads

El bot rechazaba leads con presupuesto bajo y sonaba frío/repetitivo. Ahora
Luisa nunca rechaza (el cierre siempre es positivo; la rentabilidad la valora
el reformista en el panel, no el agente) y tiene el tono del agente de voz:
simpática, variada y dispuesta a ayudar con referencias.

- leads.service: getSiguienteEstado tras presupuesto siempre fin_viable;
  evaluarViabilidad ya no filtra (informa viable=true).
- claude.service: relaja las reglas de la pasada de corrección (permite calidez,
  conectores, emoji suave, 2-3 líneas, variación) y quita el guard que tomaba
  "en qué puedo ayudarte" como frase de IA.
- prompts: reescribe el guion de Luisa (mensajes como ejemplos variables, ayuda
  con referencias de tamaño/materiales, sin rechazo) y elimina el bloque
  <DATOS_EXTRAIDOS>, que era código muerto contradictorio con el generador.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Carlos Narro
2026-06-10 17:20:52 +02:00
parent dabdf32b8e
commit f6e0347143
5 changed files with 129 additions and 186 deletions

View File

@@ -6,8 +6,9 @@ import { LeadsService } from '../leads/leads.service';
const DEFAULT_SYSTEM_PROMPT =
'Eres Luisa, asesora de Reformix en Madrid. Cualificas leads de reforma por WhatsApp. ' +
'Hablas espanol de Espana, cercana y natural; adapta el registro al usuario (coloquial si el, formal si el). ' +
'Un mensaje por turno, maximo 2 lineas. Sin emojis, sin guiones largos. ' +
'Hablas espanol de Espana, calida, simpatica y siempre dispuesta a ayudar; adapta el registro al usuario. ' +
'Un mensaje por turno, breve (2-3 lineas). Puedes usar algun emoji suave de vez en cuando. ' +
'Varia como lo dices, no suenes a plantilla y no vuelvas a preguntar lo que ya te han contado. ' +
'NUNCA digas que eres IA, ChatGPT, OpenAI ni un asistente virtual.';
const FRASES_IA_PROHIBIDAS = [
@@ -17,7 +18,6 @@ const FRASES_IA_PROHIBIDAS = [
/\bchatgpt\b/i,
/inteligencia artificial/i,
/no tengo un nombre propio/i,
/en qu[eé] puedo ayudarte/i,
];
export interface ClasificacionResultado {
@@ -270,17 +270,19 @@ ${this.serializarLead(lead)}
## Instrucciones de respuesta
Eres Luisa de Reformix en Madrid. Sigue el system prompt al pie de la letra.
Habla espanol de Espana; suena natural y cercana.
Habla espanol de Espana; calida, simpatica y siempre dispuesta a ayudar, como una asesora de confianza.
Varia como lo dices en cada turno (no repitas frases calcadas) y no vuelvas a preguntar un dato que el
usuario ya te haya dado en este mensaje o en el historial; reconocelo con naturalidad y sigue con lo que falte.
Devuelve SOLO el texto del mensaje a enviar por WhatsApp.
NO incluyas JSON, etiquetas XML ni bloques de datos extraidos.
NUNCA digas que eres IA, OpenAI, ChatGPT ni un asistente virtual.
Si forzar mensaje de apertura es true, envia el mensaje de APERTURA del flujo.
Si validacion valida es false y reintentos < 2, pide amablemente que aclare su respuesta.
Si validacion valida es false y reintentos >= 2, repite la pregunta del estado actual de forma directa.
Si es_desvio es true o intencion es pregunta, responde brevemente como Luisa y redirige al flujo sin avanzar.
Si validacion valida es false y reintentos < 2, ayudale con calidez dando ejemplos o referencias para que se aclare.
Si validacion valida es false y reintentos >= 2, vuelve a la pregunta del estado de otra forma, sin sonar borde.
Si es_desvio es true o intencion es pregunta, atiende su duda con simpatia (concede algo util) y retoma el flujo sin avanzar.
Si avanzar estado es true, haz la pregunta correspondiente al siguiente estado.
Si el siguiente estado es fin_viable o fin_no_viable, usa el mensaje de cierre correspondiente.`;
Si el siguiente estado es fin_viable, cierra con calidez anunciando que ya le preparas el presupuesto.`;
const contenido = await this.llamarOpenRouter(this.getModelo('generador'),
`${this.systemPromptCache || DEFAULT_SYSTEM_PROMPT}\n${contextoGeneracion}`,
@@ -304,11 +306,14 @@ Devuelve SOLO el mensaje final listo para enviar, sin explicaciones ni JSON.
- Intencion del usuario: ${clasificacion.intencion}
## Reglas de correccion obligatorias
- Debe sonar como Luisa de Reformix (Madrid), nunca como un asistente generico
- Espanol de Espana, natural; puede usar coloquialismos suaves (vale, mira, oye) si encaja
- Maximo 2 lineas, un mensaje por turno, sin emojis, sin guiones largos
- Debe sonar como Luisa de Reformix (Madrid): calida, simpatica y servicial, nunca un asistente generico ni un teleoperador
- Espanol de Espana, natural; usa coloquialismos y conectores suaves (vale, mira, oye, genial, tranquila, perfecto) cuando encajen
- Un mensaje por turno, breve (2-3 lineas como mucho); puede llevar algun emoji suave ocasional, sin abusar
- Varia la redaccion; no dejes frases calcadas ni que repitan literalmente lo que ya se dijo en turnos anteriores
- No reescribas para quitar la cercania: si el borrador suena frio o robotico, dale calidez en vez de recortarla
- NUNCA mencionar IA, OpenAI, ChatGPT, modelos de lenguaje ni asistentes virtuales
- Si preguntan el nombre: "Soy Luisa de Reformix"
- Quita cualquier JSON o etiqueta tecnica que se haya colado; deja solo el mensaje natural
- Si el borrador viola alguna regla, reescribelo completamente manteniendo la intencion`;
const contenido = await this.llamarOpenRouter(this.getModelo('reglas'), system,
@@ -376,12 +381,9 @@ Devuelve SOLO el mensaje final listo para enviar, sin explicaciones ni JSON.
entidad.nombre = clasificacion.valor_extraido.trim();
}
}
if (estadoFlujo === 'presupuesto') {
viable = validacion.viable;
siguienteEstado = this.leadsService.getSiguienteEstado(estadoFlujo, viable);
} else {
siguienteEstado = this.leadsService.getSiguienteEstado(estadoFlujo);
}
siguienteEstado = this.leadsService.getSiguienteEstado(estadoFlujo);
// `viable` es solo informativo (siempre true): no cambia la ruta. Luisa nunca rechaza.
if (estadoFlujo === 'presupuesto') viable = validacion.viable;
} else if (!validacion.valido && clasificacion.responde_pregunta && !clasificacion.es_desvio) {
reintentos = this.incrementarReintentos(lead.id, estadoFlujo);
if (reintentos > 2) reintentos = 2;