Volver a la wiki

Chat Tutor Multi-Turn — bib_ask con historial conversacional

Chat Tutor Multi-Turn — bib_ask con historial conversacional

Resumen

El Chat Tutor Multi-Turn (s55) convierte el modo IT Tutor del Help Widget de CreaRack Pro en un chat conversacional real. Antes de este cambio, cada pregunta al tutor era independiente — el modelo respondía sin ningún contexto de los mensajes previos. A partir de este commit, el handler handleAsk acepta un array history de turnos anteriores y lo inyecta en el prompt del modelo para mantener coherencia conversacional entre mensajes.

Motivación

El Help Widget ofrecía dos modos:

El Tutor era útil pero stateless: si el usuario preguntaba “¿qué es un VLAN?” y luego “¿y cómo se configura en Cisco?”, la segunda pregunta llegaba al modelo sin contexto de la primera. Este cambio resuelve exactamente ese problema.

Cambios introducidos

archivo-core.ts

Nueva interfaz exportada: TutorMessage

export interface TutorMessage {
  role: 'user' | 'assistant';
  content: string;
}

Representa un turno del historial conversacional. Es la API pública que el frontend de CreaRack-Pro consume al enviar los últimos N turnos en cada petición.

buildTutorPrompts — parámetro history opcional

function buildTutorPrompts(
  question: string,
  lang: 'en' | 'es',
  history?: TutorMessage[],
): { systemPrompt: string; userPrompt: string }

Si se pasa history, genera un bloque de texto conversacional ("--- CONVERSATION SO FAR ---" en EN, "--- CONVERSACIÓN HASTA AHORA ---" en ES) que se inyecta en el userPrompt antes de la nueva pregunta. Cada turno se formatea como:

User: <contenido>
Assistant: <contenido>

(o Usuario: / Asistente: en ES según el idioma detectado server-side.)

Decisión de diseño: single user content vs. multi-turn API

No se usa contents[role: model] separados (multi-turn nativo de la API de Gemini) porque responseSchema + responseMimeType: "application/json" funcionan de forma más fiable con un único user content. El historial se inyecta como texto plano dentro de ese content único.

synthesizeAnswer — firma ampliada

export async function synthesizeAnswer(
  apiKey: string,
  question: string,
  chunks: ChunkMatch[],
  mode: 'help' | 'tutor',
  history?: TutorMessage[],
): Promise<AskResult>

Recibe history y lo pasa a buildTutorPrompts. Help mode no usa historial (cada pregunta trae sus propios chunks).

archivo.ts

handleAsk — validación y paso de history

const rawHistory = Array.isArray(args.history) ? args.history : [];
const history = rawHistory
  .filter((m): m is { role: string; content: string } => {
    return !!m && typeof m === 'object'
      && typeof (m as Record<string, unknown>).role === 'string'
      && typeof (m as Record<string, unknown>).content === 'string';
  })
  .map((m) => ({
    role: (m.role === 'assistant' ? 'assistant' : 'user') as 'user' | 'assistant',
    content: m.content,
  }));

Se validan estrictamente los objetos malformados con typeof guards antes de pasarlos a synthesizeAnswer. El rol se normaliza: cualquier valor que no sea 'assistant' se trata como 'user' (seguro por defecto).

Contrato de la API MCP

Herramienta: bib_ask — parámetros Tutor mode

ParámetroTipoRequeridoDescripción
questionstringSíLa nueva pregunta del usuario
mode'tutor'Sí (para activar tutor)Activa el modo IT Tutor
historyTutorMessage[]NoArray de turnos previos (máx ~10 enviados por el frontend)

Comportamiento según modo

ModoGroundingHistorialFuente de conocimiento
helpChunks de wiki❌ NoWiki interna CreaRack Pro
tutorSin chunks✅ Sí (s55)Conocimiento del modelo (Gemini)

Flujo de datos

Frontend CreaRack-Pro
  └─ Envía últimos 10 turnos como `args.history`
       └─ handleAsk (archivo.ts)
            ├─ Valida y tipifica history[]
            └─ synthesizeAnswer(..., history)
                 └─ buildTutorPrompts(question, lang, history)
                      └─ Inyecta conversationBlock en userPrompt
                           └─ Gemini REST API → JSON {"answer": "..."}

Alcance y limitaciones

Véase también

Subir