# RF-MGN-018-005: Entrenamiento y Feedback **Módulo:** MGN-018 - AI Agents & Chatbots **Prioridad:** P2 **Story Points:** 8 **Estado:** Definido **Fecha:** 2025-12-05 ## Descripción El sistema debe permitir mejorar continuamente el rendimiento de los agentes de IA mediante: 1. Feedback de usuarios finales (satisfacción) 2. Feedback de supervisores (correcciones) 3. Análisis de conversaciones para identificar gaps 4. Ajustes al prompt y configuración basados en datos ## Actores - **Actor Principal:** Supervisor/QA - **Actores Secundarios:** - Cliente final (feedback de satisfacción) - AI Agent (sujeto del entrenamiento) - Tenant Admin (configuración) ## Precondiciones 1. Agente activo con conversaciones procesadas 2. Feature `ai_feedback_enabled` 3. Permiso de supervisión sobre el agente ## Flujo Principal - Feedback de Usuario 1. Conversación con agente termina 2. Sistema envía encuesta de satisfacción 3. Usuario califica experiencia (1-5 estrellas) 4. Usuario opcionalmente deja comentario 5. Sistema almacena feedback vinculado a conversación 6. Sistema actualiza métricas del agente ## Flujo Alternativo - Corrección de Supervisor 1. Supervisor revisa conversación en dashboard 2. Supervisor identifica respuesta incorrecta 3. Supervisor selecciona mensaje a corregir 4. Supervisor proporciona respuesta correcta 5. Sistema almacena corrección como ejemplo 6. Sistema puede incluir en fine-tuning o RAG ## Flujo Alternativo - Análisis de Gaps 1. Sistema analiza conversaciones con bajo rating 2. Sistema identifica patrones de fallo: - Temas sin cobertura en KB - Intents no reconocidos - Escalaciones frecuentes 3. Sistema genera reporte de gaps 4. Admin/Supervisor revisa recomendaciones 5. Admin actualiza KB o prompt según necesidad ## Tipos de Feedback ### 1. Feedback de Usuario Final ```typescript interface UserFeedback { conversation_id: string; rating: 1 | 2 | 3 | 4 | 5; comment?: string; helpful: boolean; would_recommend: boolean; submitted_at: Date; } ``` ### 2. Corrección de Supervisor ```typescript interface SupervisorCorrection { message_id: string; supervisor_id: string; // Respuesta original del agente original_response: string; // Corrección propuesta corrected_response: string; // Categoría del error error_type: 'factual' | 'tone' | 'incomplete' | 'inappropriate' | 'off_topic'; // Notas explicativas notes?: string; // ¿Usar para entrenamiento? use_for_training: boolean; } ``` ### 3. Gap Identificado ```typescript interface IdentifiedGap { type: 'missing_kb_content' | 'unhandled_intent' | 'unclear_response' | 'tool_limitation'; // Evidencia sample_messages: string[]; conversation_ids: string[]; frequency: number; // Sugerencia suggested_action: string; priority: 'low' | 'medium' | 'high'; // Estado status: 'new' | 'acknowledged' | 'resolved'; } ``` ## Encuesta de Satisfacción ### Configuración ```typescript interface SatisfactionSurveyConfig { enabled: boolean; // Cuándo mostrar trigger: 'end_of_conversation' | 'after_resolution' | 'after_x_messages'; trigger_value?: number; // Formato format: 'stars' | 'thumbs' | 'nps'; // Preguntas adicionales include_comment: boolean; include_recommendation: boolean; // Canal send_via: 'same_channel' | 'email'; // Mensaje survey_message: string; } ``` ### Mensaje de Encuesta (WhatsApp) ```typescript const surveyTemplate = { type: 'interactive', interactive: { type: 'button', body: { text: '¿Qué tan útil fue nuestra conversación?' }, action: { buttons: [ { type: 'reply', reply: { id: 'rating_5', title: '⭐⭐⭐⭐⭐' }}, { type: 'reply', reply: { id: 'rating_3', title: '⭐⭐⭐' }}, { type: 'reply', reply: { id: 'rating_1', title: '⭐' }} ] } } }; ``` ## Dashboard de Supervisión ### Vista de Conversaciones para Revisión ``` ┌─────────────────────────────────────────────────────────────────┐ │ 📋 Revisión de Conversaciones - Asistente de Ventas │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ Filtros: [Bajo rating ▼] [Escaladas ▼] [Últimos 7 días ▼] │ │ │ │ ┌─────────────────────────────────────────────────────────────┐│ │ │ #1234 | ⭐ 2/5 | Escalada | 12 mensajes | Hace 2h ││ │ │ Cliente preguntó sobre devoluciones, agente no tenía info ││ │ │ [Ver conversación] [Marcar revisada] ││ │ └─────────────────────────────────────────────────────────────┘│ │ │ │ ┌─────────────────────────────────────────────────────────────┐│ │ │ #1235 | ⭐ 1/5 | Cerrada | 8 mensajes | Hace 5h ││ │ │ "El bot no entendió nada de lo que le decía" ││ │ │ [Ver conversación] [Marcar revisada] ││ │ └─────────────────────────────────────────────────────────────┘│ │ │ │ Mostrando 2 de 15 conversaciones por revisar │ └─────────────────────────────────────────────────────────────────┘ ``` ### Vista de Conversación con Corrección ``` ┌─────────────────────────────────────────────────────────────────┐ │ Conversación #1234 [Cerrar] │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 👤 Cliente (14:23) │ │ "Hola, quiero devolver un producto que compré hace 2 semanas" │ │ │ │ 🤖 Agente (14:23) │ │ "Hola, gracias por contactarnos. Puedo ayudarte con eso. │ │ ¿Cuál es el número de tu pedido?" │ │ │ │ 👤 Cliente (14:24) │ │ "Es el pedido #ORD-2025-789" │ │ │ │ 🤖 Agente (14:24) ⚠️ Respuesta incorrecta │ │ ┌─────────────────────────────────────────────────────────────┐│ │ │ "Lo siento, no tengo información sobre políticas de ││ │ │ devolución. ¿Puedo ayudarte con algo más?" ││ │ └─────────────────────────────────────────────────────────────┘│ │ │ │ [✏️ Corregir respuesta] │ │ │ │ ┌─────────────────────────────────────────────────────────────┐│ │ │ Respuesta correcta: ││ │ │ "He verificado tu pedido #ORD-2025-789. Tienes 30 días ││ │ │ para devolver el producto. Puedes hacerlo en cualquiera ││ │ │ de nuestras tiendas o solicitar recolección a domicilio. ││ │ │ ¿Qué opción prefieres?" ││ │ │ ││ │ │ Tipo de error: [Información faltante ▼] ││ │ │ ☑️ Usar para entrenamiento ││ │ │ [Guardar] ││ │ └─────────────────────────────────────────────────────────────┘│ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ## Análisis de Gaps ### Algoritmo de Detección ```typescript interface GapDetectionConfig { // Umbrales low_rating_threshold: number; // Default: 3 escalation_rate_threshold: number; // Default: 0.3 (30%) frequency_threshold: number; // Mínimo de ocurrencias // Análisis de contenido analyze_unhandled_questions: boolean; analyze_repeated_clarifications: boolean; analyze_topic_clusters: boolean; // Período analysis_period_days: number; // Default: 30 } async function detectGaps(agentId: string, config: GapDetectionConfig): Promise { const gaps: IdentifiedGap[] = []; // 1. Analizar conversaciones con bajo rating const lowRatedConversations = await getLowRatedConversations(agentId, config); // 2. Extraer preguntas sin respuesta satisfactoria const unansweredQuestions = extractUnansweredQuestions(lowRatedConversations); // 3. Clusterizar por tema const topicClusters = await clusterByTopic(unansweredQuestions); // 4. Identificar gaps más frecuentes for (const cluster of topicClusters) { if (cluster.frequency >= config.frequency_threshold) { gaps.push({ type: 'missing_kb_content', sample_messages: cluster.samples, conversation_ids: cluster.conversation_ids, frequency: cluster.frequency, suggested_action: `Agregar contenido sobre: ${cluster.topic}`, priority: cluster.frequency > 10 ? 'high' : 'medium', status: 'new' }); } } // 5. Analizar intents no manejados const unhandledIntents = await findUnhandledIntents(agentId, config.analysis_period_days); // ... agregar a gaps return gaps; } ``` ### Reporte de Gaps ``` ┌─────────────────────────────────────────────────────────────────┐ │ 📊 Análisis de Gaps - Asistente de Ventas (Últimos 30 días) │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ Gaps Identificados: 5 │ │ │ │ ┌─────────────────────────────────────────────────────────────┐│ │ │ 🔴 Alta Prioridad ││ │ │ ││ │ │ 1. Políticas de devolución ││ │ │ Frecuencia: 23 menciones | 15 conversaciones afectadas ││ │ │ Acción: Agregar documento de políticas a Knowledge Base ││ │ │ [Ver ejemplos] [Marcar resuelto] ││ │ │ ││ │ │ 2. Disponibilidad de sucursales ││ │ │ Frecuencia: 18 menciones | 12 conversaciones afectadas ││ │ │ Acción: Crear herramienta de consulta de horarios ││ │ │ [Ver ejemplos] [Marcar resuelto] ││ │ └─────────────────────────────────────────────────────────────┘│ │ │ │ ┌─────────────────────────────────────────────────────────────┐│ │ │ 🟡 Media Prioridad ││ │ │ ││ │ │ 3. Métodos de pago aceptados ││ │ │ Frecuencia: 8 menciones | 6 conversaciones afectadas ││ │ │ [Ver ejemplos] [Marcar resuelto] ││ │ └─────────────────────────────────────────────────────────────┘│ │ │ │ [Exportar reporte] [Programar análisis] │ └─────────────────────────────────────────────────────────────────┘ ``` ## Reglas de Negocio - **RN-1:** Encuesta de satisfacción solo se envía una vez por conversación - **RN-2:** Correcciones de supervisor requieren permiso de "ai_supervisor" - **RN-3:** Análisis de gaps se ejecuta semanalmente automáticamente - **RN-4:** Datos de feedback se retienen por 1 año - **RN-5:** Feedback anónimo disponible si tenant lo configura - **RN-6:** Mínimo 50 conversaciones para análisis estadístico confiable ## Criterios de Aceptación - [ ] Encuesta de satisfacción configurable y funcional - [ ] Usuarios pueden calificar y comentar - [ ] Supervisores pueden corregir respuestas - [ ] Correcciones se almacenan para referencia - [ ] Análisis de gaps identifica patrones - [ ] Reporte de gaps con prioridades - [ ] Métricas de satisfacción en dashboard - [ ] Exportación de datos de feedback - [ ] Notificaciones de gaps críticos ## Entidades Involucradas ### ai_agents.feedback ```sql CREATE TABLE ai_agents.feedback ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, agent_id UUID NOT NULL, conversation_id UUID NOT NULL REFERENCES ai_agents.conversations(id), -- Tipo de feedback feedback_type VARCHAR(50) NOT NULL, -- user_rating, supervisor_correction, system_analysis -- Rating de usuario rating INT, -- 1-5 comment TEXT, helpful BOOLEAN, would_recommend BOOLEAN, -- Corrección de supervisor message_id UUID, original_response TEXT, corrected_response TEXT, error_type VARCHAR(50), correction_notes TEXT, use_for_training BOOLEAN DEFAULT false, corrected_by UUID, -- Metadata channel VARCHAR(50), metadata JSONB DEFAULT '{}', created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_feedback_type CHECK (feedback_type IN ('user_rating', 'supervisor_correction', 'system_analysis')) ); CREATE INDEX idx_feedback_tenant ON ai_agents.feedback(tenant_id); CREATE INDEX idx_feedback_agent ON ai_agents.feedback(agent_id); CREATE INDEX idx_feedback_conversation ON ai_agents.feedback(conversation_id); CREATE INDEX idx_feedback_type ON ai_agents.feedback(feedback_type); CREATE INDEX idx_feedback_rating ON ai_agents.feedback(rating) WHERE rating IS NOT NULL; ``` ### ai_agents.identified_gaps ```sql CREATE TABLE ai_agents.identified_gaps ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, agent_id UUID NOT NULL, -- Clasificación gap_type VARCHAR(50) NOT NULL, -- missing_kb_content, unhandled_intent, unclear_response, tool_limitation -- Descripción title VARCHAR(200) NOT NULL, description TEXT, topic_keywords TEXT[], -- Evidencia sample_messages TEXT[], conversation_ids UUID[], frequency INT NOT NULL, -- Recomendación suggested_action TEXT, priority VARCHAR(20) NOT NULL, -- low, medium, high -- Estado status VARCHAR(20) NOT NULL DEFAULT 'new', -- new, acknowledged, in_progress, resolved, wont_fix resolved_at TIMESTAMPTZ, resolved_by UUID, resolution_notes TEXT, -- Análisis analysis_period_start DATE NOT NULL, analysis_period_end DATE NOT NULL, detected_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_gap_status CHECK (status IN ('new', 'acknowledged', 'in_progress', 'resolved', 'wont_fix')) ); CREATE INDEX idx_gaps_tenant ON ai_agents.identified_gaps(tenant_id); CREATE INDEX idx_gaps_agent ON ai_agents.identified_gaps(agent_id); CREATE INDEX idx_gaps_status ON ai_agents.identified_gaps(status); CREATE INDEX idx_gaps_priority ON ai_agents.identified_gaps(priority); ``` ### ai_agents.training_examples ```sql -- Ejemplos curados para potencial fine-tuning o few-shot learning CREATE TABLE ai_agents.training_examples ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, agent_id UUID NOT NULL, -- Origen source_type VARCHAR(50) NOT NULL, -- supervisor_correction, curated, synthetic source_feedback_id UUID REFERENCES ai_agents.feedback(id), -- Ejemplo user_message TEXT NOT NULL, ideal_response TEXT NOT NULL, context TEXT, -- Contexto adicional si necesario -- Clasificación category VARCHAR(100), tags TEXT[], -- Estado is_approved BOOLEAN DEFAULT false, approved_by UUID, approved_at TIMESTAMPTZ, -- Uso used_in_training BOOLEAN DEFAULT false, training_run_id VARCHAR(100), created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, created_by UUID ); CREATE INDEX idx_training_tenant ON ai_agents.training_examples(tenant_id); CREATE INDEX idx_training_agent ON ai_agents.training_examples(agent_id); CREATE INDEX idx_training_approved ON ai_agents.training_examples(is_approved); ``` ## API Endpoints ### Enviar Feedback de Usuario ```typescript // POST /api/v1/ai-agents/conversations/{id}/feedback interface SubmitFeedbackRequest { rating: 1 | 2 | 3 | 4 | 5; comment?: string; helpful?: boolean; would_recommend?: boolean; } ``` ### Crear Corrección de Supervisor ```typescript // POST /api/v1/ai-agents/messages/{id}/correction interface CreateCorrectionRequest { corrected_response: string; error_type: string; notes?: string; use_for_training?: boolean; } ``` ### Obtener Gaps ```typescript // GET /api/v1/ai-agents/{id}/gaps?status=new&priority=high interface GetGapsResponse { gaps: IdentifiedGap[]; summary: { total: number; by_priority: Record; by_type: Record; }; } ``` ### Ejecutar Análisis de Gaps ```typescript // POST /api/v1/ai-agents/{id}/analyze-gaps interface AnalyzeGapsRequest { period_days?: number; force_refresh?: boolean; } ``` ## Referencias - [Reinforcement Learning from Human Feedback (RLHF)](https://huggingface.co/blog/rlhf) - [Active Learning for NLP](https://www.activeloop.ai/resources/glossary/active-learning-in-nlp/) - [Conversation Design Best Practices](https://developers.google.com/assistant/conversation-design) ## Dependencias - **RF Requeridos:** RF-018-003 (Procesamiento), RF-018-004 (Herramientas) - **Bloqueante para:** Ninguno