¿Te resulta más fácil leer con fondo crema, un tono de color, más contraste o un texto más grande? Elige tus colores y tu texto una sola vez, para todas las páginas.

Lección gratuita

Cómo recuerda un chatbot la conversación

Después de esta lección: Puedo mantener una conversación entre una petición y otra.

Lección de 60 min6 comandosLaboratorio de agente de programación con IA: usa opencode para explicar y corregir código, y comprueba su trabajo

Por qué un chatbot olvida tu nombre

Un chatbot guarda los mensajes de una conversación y los envía otra vez con cada pregunta nueva. Importa porque una llamada a un modelo de lenguaje no tiene memoria propia.

Un cliente cuenta al chatbot de una empresa de autobuses que ha perdido su billete. Luego pregunta «¿y para mi hermano?». El bot solo lo entiende si los mensajes anteriores viajan con la pregunta.

Al final de esta lección

Nota

Puedo mantener una conversación entre una petición y otra.

Palabras clave

PalabraQué significaEjemplo
Sesiónla conversación de una persona con el chatbot
Id de sesiónuna etiqueta que señala una sesiónlucia
Estadolo que el programa recuerda entre peticiones
Almacénel lugar donde se guardan todas las sesiones
Lista de mensajeslos mensajes que se envían con cada llamada

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Una llamada al modelo parte de cero

Cada llamada a un modelo empieza de nuevo. El modelo solo conoce los mensajes que envías en esa llamada.

Para hacer una conversación, tu programa guarda todos los mensajes. Envía la lista entera cada vez, con la pregunta nueva al final. Esa lista es el estado del chat.

Ejemplo resuelto: tres peticiones

PeticiónMensajes enviadosLo que el modelo puede ver
1system, userSolo la regla y «Me llamo Lucía.»
2system, user, assistant, userEl primer intercambio y «¿Cómo me llamo?»
3system, user, assistant, user, assistant, userTodo lo anterior y la pregunta más reciente

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Cada persona tiene su propia sesión

Un chatbot habla con mucha gente a la vez. Por eso el almacén se organiza por id de sesión: una lista por conversación. Un id nuevo abre una lista nueva. Un id conocido añade a su lista.

El almacén puede ser una variable mientras el programa funciona. Un pequeño archivo JSON en la carpeta del proyecto lo conserva cuando el programa se detiene.

¿De quién es el estado?

El estado es de tu programa, no del modelo. Por eso tú decides qué se guarda y durante cuánto tiempo.

No guardes contraseñas, números de tarjeta ni nada que el chatbot no necesite. Da a la gente una forma de borrar una sesión. Borrar una sesión elimina toda la lista.

Un error frecuente

Advertencia

Mucha gente cree que el modelo recuerda quién habla. No es así. Si dos personas comparten una lista, cada una ve las palabras de la otra. Guarda una lista por cada id de sesión.

Escribir la ayuda del modelo, parte 1

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' 'async function ask(messages, sample, max) {' '  try {' '    const res = await fetch(base + \"/v1/chat/completions\", {' '      method: \"POST\",' '      headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' '      body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 200 }),' '      signal: AbortSignal.timeout(30000),' '    });' '    if (res.ok === false) throw new Error(\"estado \" + res.status);' '    return (await res.json()).choices[0].message.content;' > model.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribir la ayuda del modelo, parte 2

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' '  } catch (error) {' '    console.log(\"Muestra grabada: ningún modelo respondió (\" + error.message + \").\");' '    const list = [].concat(sample);' '    const turn = messages.filter(function (m) { return m.role === \"assistant\"; }).length;' '    return list[Math.min(turn, list.length - 1)];' '  }' '}' 'module.exports = { ask };' >> model.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribir el almacén de sesiones, parte 1

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const fs = require(\"fs\");' 'const { ask } = require(\"./model\");' 'const FILE = \"sessions.json\"; // el almacén está en la carpeta del proyecto' 'const RULE = \"Eres un asistente amable. Responde en una frase corta.\";' '' 'function load() {' '  try { return JSON.parse(fs.readFileSync(FILE, \"utf8\")); } catch (error) { return {}; }' '}' 'function save(store) { fs.writeFileSync(FILE, JSON.stringify(store, null, 1)); }' > chat1.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribir el almacén de sesiones, parte 2

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function say(store, id, text, samples) {' '  if (store[id] === undefined) store[id] = [{ role: \"system\", content: RULE }];' '  store[id].push({ role: \"user\", content: text });' '  const answer = await ask(store[id], samples, 40);' '  store[id].push({ role: \"assistant\", content: answer });' '  save(store);' '  return answer;' '}' >> chat1.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribir el almacén de sesiones, parte 3

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  const store = {};' '  // Muestras grabadas, usadas solo si ningún modelo responde.' '  const luciaSamples = [\"Encantado, Lucía.\", \"Te llamas Lucía.\"];' '  const pabloSamples = [\"Todavía no sé cómo te llamas.\"];' '  console.log(\"Lucía:\", await say(store, \"lucia\", \"Me llamo Lucía. Recuérdalo.\", luciaSamples));' '  console.log(\"Lucía:\", await say(store, \"lucia\", \"¿Cómo me llamo?\", luciaSamples));' '  console.log(\"Pablo:\", await say(store, \"pablo\", \"¿Cómo me llamo?\", pabloSamples));' '  const saved = load();' '  console.log(\"Guardado: lucia tiene \" + saved.lucia.length + \" mensajes, pablo tiene \" + saved.pablo.length);' '}' 'main();' >> chat1.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Ejecutar dos conversaciones

Comando
docker exec -w /home/node/project agent node chat1.js

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Una salida posible

LíneaLo que puede mostrar
Lucía (primera)Un saludo corto que puede usar el nombre Lucía
Lucía (segunda)Una respuesta que puede decir el nombre, porque recibió los mensajes anteriores
PabloUna respuesta que no puede saber el nombre de Lucía, porque Pablo tiene su propia lista
Guardadolucia tiene 5 mensajes, pablo tiene 3

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Sobre este laboratorio y su código: Laboratorio de agente de programación con IA: usa opencode para explicar y corregir código, y comprueba su trabajo

¿Enseñas a una clase? Asigna este módulo a tus alumnos con guía del profesor, tareas con corrección automática y un laboratorio para cada alumno.