Resumen

Construir un chatbot que olvida lo que le dijiste hace dos mensajes no tiene sentido en una aplicación real. Para lograr un flujo conversacional útil, la API de OpenAI necesita mantener el contexto entre mensajes. Aquí se explora cómo pasar de una respuesta única a una conversación completa, usando streaming y el endpoint de completions, todo desde la terminal con Node.js.

¿Cómo funciona el streaming en la API de OpenAI?

En una solicitud estándar, la API procesa todo el contenido y lo devuelve de golpe. Esto funciona para respuestas cortas, pero cuando pedimos textos más largos, como una historia de cien palabras, la espera se nota. La solución es activar el parámetro stream: true [01:40] dentro de la llamada a la API de responses.

Con stream activado, la API entrega la respuesta parte por parte mientras la genera. Cada fragmento llega como un evento llamado delta [02:07], que es el nombre que OpenAI asigna por defecto a cada porción de texto dentro del objeto de respuesta.

Para consumir ese flujo, se utiliza un bucle for await que itera sobre cada fragmento recibido:

javascript for await (const event of response) { process.stdout.write(event.output_text.delta); }

El resultado es muy parecido a lo que vemos en los chatbots actuales: el texto aparece en pantalla conforme se genera [02:24], palabra por palabra, en lugar de esperar a que se complete toda la respuesta. Este comportamiento mejora la experiencia del usuario en cualquier aplicación conversacional.

¿Qué es el endpoint de completions y por qué usarlo?

Para mantener una conversación con contexto, no basta con el endpoint de responses. Se necesita el endpoint de completions [03:10], que se encarga de leer múltiples mensajes, almacenarlos y devolver respuestas progresivas.

La estructura que recibe completions es un array de objetos, donde cada objeto representa un mensaje con dos propiedades:

  • role: define quién envía el mensaje (system, user o assistant).
  • content: el texto del mensaje como string.

Un ejemplo típico luce así [03:27]:

javascript const messages = [ { role: 'system', content: 'Eres un asistente muy útil y amable' }, { role: 'user', content: '¿Cuál es la capital de Colombia?' } ];

El rol de system establece la personalidad y las instrucciones del asistente. El rol de user simula las preguntas del usuario. Al enviar estos mensajes, la API genera una primera respuesta utilizando el modelo GPT [03:55].

¿Cómo se mantiene el contexto entre preguntas?

Después de obtener la primera respuesta, se concatena un nuevo mensaje al array original [04:15]. Por ejemplo, si el usuario pregunta "¿y su población?", la API ya sabe que se refiere a Bogotá porque conserva toda la lista de mensajes anteriores.

javascript messages.push({ role: 'user', content: '¿Y su población?' }); const res2 = await client.chat.completions.create({ model: 'gpt-4', messages });

La segunda respuesta depende directamente de la primera [04:40]. En el ejemplo mostrado, la API respondió con datos sobre los aproximadamente ocho millones de habitantes de Bogotá D.C. y su aglomeración urbana con Soacha, rondando los diez a once millones [05:05]. Esto confirma que la memoria se mantiene gracias al array de mensajes acumulados.

¿Cómo crear un chat interactivo desde la terminal?

El siguiente paso es reemplazar los mensajes predefinidos por entradas dinámicas del usuario [05:40]. En lugar de tener el array con contenido fijo, se lee el prompt directamente desde la terminal.

Al ejecutar node chatterminal.js [05:50], la terminal solicita un prompt y el asistente responde. Cada nueva pregunta se agrega al historial de mensajes. Por ejemplo:

  • "¿Cuál es la capital de Francia?" → "La capital de Francia es París."
  • "¿Y cuáles son los colores de su bandera?" → "La bandera de Francia es tricolor: azul, blanco y rojo" [06:20].

La tercera pregunta no menciona ningún país, pero la API infiere el contexto porque almacena las interacciones previas en memoria [06:40]. Este comportamiento es la base de cualquier aplicación conversacional real.

Los puntos más relevantes para implementar tu propio chat son:

  • Activar stream: true para respuestas progresivas.
  • Usar el endpoint de completions con un array de mensajes.
  • Acumular cada mensaje y respuesta en el array para preservar el contexto.
  • Leer la entrada del usuario con las herramientas de Node.js para hacerlo interactivo.

¿Cuál de estas funcionalidades te resultó más útil para tus proyectos? Comparte tu experiencia en los comentarios.