Asistente de IA
Cómo se integra el chat de IA (local_ai_manager y block_ai_chat) con el código propio - perfil del usuario, agente de acciones, niveles de cuota, autor de preguntas y Configuración IA.
El chat de IA de la Academia combina dos plugins de terceros con código propio:
| Pieza | Origen | Papel |
|---|---|---|
local_ai_manager (v1.1) | Tercero | Proxy hacia el proveedor (instancias, propósitos, cuotas por nivel, aceptación de términos por usuario en local_ai_manager_userinfo). |
block_ai_chat (v1.0) | Tercero | Interfaz del chat (botón flotante ✦ y ventana). |
ai_role_injector | local_deltamodules | Agrega al mensaje de sistema el perfil real del usuario. |
ai_agent | local_deltamodules | Agente de acciones con llamadas a funciones para quien gestiona. |
ai_tiers | local_deltamodules | Nivel de cuota según el perfil. |
ai_author | local_deltamodules | Propone objetivos y preguntas al crear un módulo desde un documento (Importador). |
policies | local_deltamodules | Condiciones de uso del Asistente (Políticas y aceptaciones). |
Proveedor
configure-ai-groq.php configura una instancia del conector chatgpt de local_ai_manager apuntando a la API compatible con OpenAI de Groq, con el modelo openai/gpt-oss-20b y la clave tomada de la variable GROQ_API_KEY. Es idempotente (actualiza la instancia existente en vez de duplicarla). moodle-config.sh lo ejecuta en cada despliegue como paso critico cuando GROQ_API_KEY está definida, antes de las cuotas de IA: cambiar la clave en Coolify y hacer Redeploy basta. Sin la variable, el paso no corre y se conservan la instancia y la clave guardadas en la base de datos; si se ejecuta a mano sin la variable, también conserva la clave ya guardada. configure-ai-manager.php es el script anterior para Gemini (clave GEMINI_API_KEY). Las clases propias localizan la instancia buscando el conector chatgpt con un endpoint que contenga groq, o la instancia llamada "Chat IA - Academia Deltamontero".
Perfil del usuario en el chat: ai_role_injector
El parche patch-ai-role-injection.php inserta en local_ai_manager/classes/external/submit_query.php, justo después de decodificar $options, una llamada a ai_role_injector::inject($options).
inject() busca el perfil delta_* del usuario (primero en contexto de sistema, luego en cualquier curso; el más reciente) y agrega al mensaje con sender = 'system' de options['conversationcontext'] un bloque de contexto con la descripción del perfil (ROLE_LABELS) e instrucciones: responder si su perfil le permite o no una acción, sin remitirlo a otro rol y sin conceder accesos. Si no hay mensaje de sistema, lo crea. No actúa con invitados ni sin perfil.
Agente de acciones: ai_agent
El parche patch-ai-agent.php agrega, después del bloque anterior, un cortocircuito: si ai_agent::maybe_handle($prompt, $options, $contextid) devuelve texto, submit_query responde ese texto; si devuelve null, sigue el chat informativo normal.
Regla de diseño del código: la IA propone, Moodle dispone. Cada herramienta se ejecuta como el usuario conectado, vuelve a validar sus capacidades en el servidor y nunca hace más de lo que esa persona podría hacer a mano.
| Constante | Valor |
|---|---|
GATE_CAP | moodle/user:create (sin ella, el agente no actúa y responde el chat normal) |
AGENT_MODEL | openai/gpt-oss-120b (el comentario explica que el modelo de 20b fallaba la validación del esquema al crear) |
AGENT_TEMPERATURE | 0.1 |
MAX_ITERATIONS | 5 vueltas del ciclo de herramientas |
Herramientas
| Herramienta | Tipo | Capacidad exigida |
|---|---|---|
buscar_usuario | Lectura | GATE_CAP |
avance_de_usuario | Lectura | GATE_CAP |
pendientes_de_curso | Lectura | GATE_CAP |
generar_reporte (usuarios, avance de un curso, certificados; filtros y agrupación de una lista blanca) | Lectura | GATE_CAP |
reporte_formacion (los reportes de la página Reportes, con descarga) | Lectura | local/deltamodules:viewreports |
menu_reportes | Lectura | local/deltamodules:viewreports |
guia_crear_usuario | Guía | moodle/user:create |
crear_colaborador | Escritura | moodle/user:create (usa staff_manager::create) |
asignar_cargo | Escritura | moodle/user:create |
asignar_cedula | Escritura | moodle/user:update |
matricular_en_cohorte | Escritura | moodle/cohort:assign |
resetear_contrasena | Escritura | moodle/user:update |
Salvaguardas
- Confirmación determinista: una escritura nunca se ejecuta porque lo pida el modelo. Se muestra un resumen y la acción queda en
$SESSION->deltaagent_pending; solo si el siguiente mensaje del usuario es afirmativo (is_affirmative) el código la ejecuta directamente. - Cuentas protegidas (
target_denied): la propia cuenta, los super administradores y, si quien pide no es super administrador, las cuentas de gestión no se modifican desde el chat. - Credenciales: la contraseña temporal la muestra el código (
credentials_box), no el texto del modelo. Si el correo está configurado, al crear un colaborador no se muestra contraseña: se envía el correo de activación. - Postulantes: reciben siempre "El asistente de IA no está disponible durante el proceso de selección" (además el botón del chat está oculto para ellos).
- Atajos sin modelo: pedir crear un usuario sin datos muestra la guía de campos y cargos; pedir "un reporte" sin precisar muestra el menú de reportes; responder solo un formato ("en PDF") devuelve el archivo del último reporte (
$SESSION->deltaagent_report_last). - Datos personales ocultos al proveedor: ver la sección siguiente.
Cédulas, RUC y correos fuera del proveedor (pii_hide y pii_restore)
Antes de enviar nada a Groq, el agente reemplaza en el texto los datos identificativos por marcadores:
| Dato | Detección | Marcador |
|---|---|---|
| Cédula | Número de 10 dígitos | CEDULA_1, CEDULA_2… |
| RUC | Número de 13 dígitos | RUC_1, RUC_2… |
| Correo | Dirección de correo electrónico | correo1@dato.oculto, correo2@dato.oculto… |
pii_hide()se aplica al mensaje actual, a cada mensaje del historial (build_messages) y al resultado de cada herramienta antes de devolverlo al modelo. El mismo dato recibe siempre el mismo marcador.- La tabla marcador → dato real vive solo en la sesión de la plataforma (
$SESSION->deltaagent_pii); no se guarda en la base de datos ni se envía al proveedor. pii_restore()devuelve el dato real en dos puntos: en los argumentos de cada herramienta al inicio derun_tool(para que la búsqueda, la creación o la asignación de cédula usen el dato verdadero) y en la respuesta final que ve la persona. Reemplaza primero los marcadores más largos (CEDULA_10antes queCEDULA_1).- El mensaje de sistema del agente y las descripciones de las herramientas
crear_colaboradoryasignar_cedulale indican al modelo que los marcadores son datos válidos y que debe pasarlos tal cual. - Los nombres sí viajan al proveedor: hacen falta para buscar a las personas y para responder.
El reemplazo lo hace el agente de acciones. Si el agente no usa ninguna herramienta en su primera vuelta (consulta informativa) o la persona no tiene moodle/user:create, responde el chat normal de local_ai_manager, que envía el mensaje tal como se escribió. Por eso las condiciones de uso siguen pidiendo no escribir datos personales de terceros en el chat.
Niveles de cuota: ai_tiers
| Nivel | Constante | Perfiles | Cuota del propósito chat |
|---|---|---|---|
| Sin límite | UNLIMITED = 3 | delta_socios, delta_jefaturas, delta_a1_operaciones | Sin tope |
| Ampliado | EXTENDED = 2 | delta_gerentes, delta_jefatura_tecnica, delta_a3, delta_a2_rrhh | 60 mensajes por día |
| Básico | BASIC = 1 | delta_operativo, delta_operativo_tecnico, delta_operativo_backof, delta_auxiliares, delta_pasante | 15 mensajes por día |
Las cuotas (chat_max_requests_basic, chat_max_requests_extended, periodo de 86.400 s) las fija configure-ai-quotas-and-persona.php en cada despliegue, que además crea la "persona" plantilla del chat con el mensaje de sistema de la Academia y llama a ai_tiers::apply_all().
ai_tiers::apply_user($userid) toma el nivel más alto de los perfiles de la persona. Si no tiene fila en local_ai_manager_userinfo, la crea con ese nivel sin aceptar los términos por ella. Si el nivel actual lo puso este código (registro en la configuración aitier_applied), lo actualiza; si lo cambió una persona en Configuración IA, lo respeta. Nunca desbloquea a alguien bloqueado a mano. Se llama también desde staff_manager::assign_cargo().
Otros ajustes del chat
| Ajuste | Dónde |
|---|---|
| Chat visible en todas las páginas para todos | Parche patch-ai-chat-everywhere.php (alcance por defecto SCOPE_EVERYWHERE) y configure-ai-chat-global.php (showonpagetypes = * del bloque) |
| Sin chat sin sesión o como invitado | hook_callbacks::before_head agrega CSS que oculta el botón y la ventana |
| Sin chat durante un examen ni sobre el reproductor de video | CSS en additionalhtmlhead |
| Copiar respuesta también por HTTP | Parche patch-ai-chat-copy.php |
| Nombre, ids y límite diario disponibles para el JavaScript propio; contexto de 50 mensajes | Parche patch-ai-chat-ui.php |
| Historial que se envía al modelo: mínimo 50 mensajes | Paso de moodle-config.sh que actualiza block_ai_chat_options.historycontextmax |
| Ventana flotante a la derecha, saludo, títulos, borrado por conversación, chat nuevo por sesión | JavaScript y CSS inline en additionalhtmlhead (ver Interfaz global) |
| Activación automática cuando no se exige aceptar las condiciones | hook_callbacks::before_http_headers marca como confirmado (una vez por sesión, $SESSION->deltaaiauto) a quien no es postulante |
La página de términos de local_ai_manager | Redirige a aiterms.php |
Configuración IA: aiconfig.php
Administración del sitio → Configuración IA (categoría propia creada en settings.php si existe local/ai_manager/tenant_config.php), capacidad local/ai_manager:manage. Pestañas:
| Pestaña | Contenido |
|---|---|
resumen | Activar o desactivar el Asistente para todos (tenantenabled de local_ai_manager), pedir o no la aceptación de las condiciones, estado de condiciones y aceptaciones. |
condiciones | Editar el resumen y el acuerdo completo; publicar una versión nueva. |
aceptaciones | Quién aceptó y quién falta, con descarga en Excel. |
tecnico | Accesos a las páginas de local_ai_manager (proveedor y modelo, propósitos, límites, estadísticas). |
El agente MCP de administración (servicio delta_ai_mcp_ro con el usuario mcpservice) es un canal distinto del chat de usuarios: se describe en Servicios web.
Correo de la Academia
Cola de envío con límites para Office 365 (mailer), tipos de correo, enlaces de un solo uso para crear contraseña, tarea send_mail y página de administración.
Políticas y aceptaciones
Aviso de Tratamiento de Datos Personales (tool_policy) y Condiciones de uso del Asistente de IA, con su registro de aceptaciones (classes/policies.php).