Crea un chatbot de IA en Delphi: memoria de conversación y streaming

· Componentes

Respuesta rápida: un chatbot es una chat completion más memoria. sgcWebSockets incluye un componente dedicado TsgcAIChat que mantiene por ti el historial completo de mensajes, de modo que cada turno se envía con la conversación hasta el momento y el modelo puede responder en contexto. Coloca el componente, establece la clave de API y el modelo, luego llama a Chat para obtener una respuesta o a ChatStream para un efecto de escritura en vivo, token a token. Borrar la conversación es una sola llamada a ClearHistory.

Si ya has llamado a un LLM desde Delphi, probablemente has notado algo frustrante: haces una pregunta de seguimiento y el modelo actúa como si nunca te hubiera hablado antes. Eso no es un fallo, es cómo funciona una completion de un solo disparo. Convertir eso en un verdadero asistente conversacional es la diferencia entre un juguete y un chatbot, y se reduce a una sola idea: memoria.

Completion de un solo disparo vs un chatbot

Una API de LLM no tiene estado. Cada petición es independiente, así que el modelo solo sabe lo que pones en esa petición. Una llamada de un solo disparo envía un único prompt:

// User: "What is the capital of France?"  ->  "Paris."
// User: "And its population?"             ->  "Population of what?"

La segunda pregunta falla porque el servidor no guardó nada de la primera. Un chatbot soluciona esto reenviando todo el intercambio cada vez: el mensaje de sistema, cada turno del usuario y cada respuesta del asistente, en orden. El modelo lee el historial, ve que "its" se refiere a París, y responde correctamente. No necesitas una base de datos ni un servidor de sesiones para esto, solo una lista de mensajes que crece con la conversación. El único trabajo real es construir y mantener esa lista, y eso es exactamente lo que el componente de chatbot hace por ti.

El componente TsgcAIChat: la memoria gestionada por ti

En lugar de montar un array de mensajes a mano, coloca un TsgcAIChat en tu formulario. Posee internamente el historial de la conversación, añade automáticamente cada mensaje del usuario y cada respuesta del asistente, y envía el contexto acumulado en cada llamada. Estableces el proveedor, la clave de API y un modelo, y luego simplemente llamas a Chat.

uses
  sgcAI, sgcAI_Chat;

var
  Bot: TsgcAIChat;
begin
  Bot := TsgcAIChat.Create(nil);
  Bot.Provider := aicpOpenAI;
  Bot.ChatOptions.ApiKey := 'sk-...';
  Bot.ChatOptions.Model  := 'gpt-4o-mini';
  Bot.SystemMessage := 'You are a concise assistant for Delphi developers.';

  // Each call adds to the same conversation:
  ShowMessage(Bot.Chat('What is the capital of France?'));  // "Paris."
  ShowMessage(Bot.Chat('And its population?'));             // answers about Paris
end;

Como el componente recuerda el primer turno, el seguimiento simplemente funciona. El SystemMessage establece la personalidad del asistente y se incluye en cada petición. Cuando quieres una conversación nueva, llama a Bot.ClearHistory; para inspeccionar o persistir lo que se ha dicho, Bot.GetHistory devuelve la lista de mensajes. También puedes limitar la memoria con MaxHistoryMessages para que un chat largo no crezca sin límite (los turnos más antiguos se podan automáticamente).

El mismo componente habla con todos los proveedores que sgcWebSockets soporta. Cambia Provider a aicpAnthropic, aicpGemini, aicpDeepSeek, aicpOllama, aicpGrok o aicpMistral, cambia el nombre del modelo, y el resto de tu código de chatbot permanece idéntico. Consulta la página del componente ChatBot y el hub de componentes de IA y LLM.

Transmitir una respuesta en vivo

Esperar varios segundos a que aparezca una respuesta completa se siente lento. Los chatbots reales transmiten la respuesta para que las palabras aparezcan a medida que se generan, el familiar efecto de escritura. TsgcAIChat expone esto a través de ChatStream más el evento OnChatStream, que se dispara por cada fragmento de texto a medida que llega.

Bot.OnChatStream := BotChatStream;
Bot.ChatStream('Explain WebSockets in two sentences.');

procedure TForm1.BotChatStream(Sender: TObject; const aChunk: string;
  var Cancel: Boolean);
begin
  Memo1.Text := Memo1.Text + aChunk;  // append each token as it arrives
  // set Cancel := True to stop the response early
end;

Los fragmentos se entregan de forma incremental sobre Server-Sent Events por debajo, pero nunca tocas la fontanería de SSE. Cuando el stream termina, la respuesta completa del asistente se añade al historial igual que en una llamada sin streaming, así que el siguiente turno sigue teniendo el contexto completo. El parámetro Cancel te permite implementar un botón de "detener generación". También está OnChatMessage para el mensaje final ensamblado y OnChatError para mostrar cualquier fallo de la API.

Un chatbot de voz, de principio a fin

Si quieres que el asistente escuche y hable, el componente TsgcAIOpenAIChatBot envuelve todo el bucle: captura el audio del micrófono, lo transcribe con Whisper, envía el texto a Chat Completions y pronuncia la respuesta a través de un proveedor de texto a voz. Conecta un grabador de audio y un motor de texto a voz, establece la clave y llama a Start.

uses
  sgcAI, sgcAI_OpenAI_Audio_ChatBot,
  sgcAI_AudioRecorder_MCI, sgcAI_TextToSpeech_System;

var
  ChatBot: TsgcAIOpenAIChatBot;
begin
  ChatBot := TsgcAIOpenAIChatBot.Create(nil);
  ChatBot.OpenAIOptions.ApiKey := 'sk-...';
  ChatBot.AudioRecorder := TsgcAudioRecorderMCI.Create(nil);
  ChatBot.TextToSpeech  := TsgcTextToSpeechSystem.Create(nil);
  ChatBot.OnChatCompletion := ChatBotChatCompletion;

  ChatBot.Start;                          // begin listening; Stop ends it
  ChatBot.ChatAsUser('Tell me a joke');   // or push a turn programmatically
end;

El evento OnChatCompletion te da el rol y el contenido de cada respuesta, y OnTranscription te permite inspeccionar o editar lo que se escuchó antes de enviarlo. Es la misma idea conversacional que TsgcAIChat, solo que con audio en ambos extremos.

¿Prefieres gestionar la lista tú mismo?

No tienes que usar el componente de chatbot. Si quieres control total, mantén tu propia lista de mensajes { role, content } y envíala en cada llamada con TsgcHTTP_API_OpenAI._CreateChatCompletion. Añade el mensaje del usuario, envía el array, luego vuelve a añadir la respuesta del asistente a la misma lista antes del siguiente turno. Esa es precisamente la contabilidad que TsgcAIChat hace internamente, así que la mayoría de la gente deja que el componente la gestione. La API de más bajo nivel se cubre en el tutorial La API de OpenAI en Delphi y en la página del componente OpenAI.

Primeros pasos

Todo lo que hay aquí viene incluido en sgcWebSockets. Consigue la prueba gratuita, coloca un TsgcAIChat en un formulario, establece la clave de API y el modelo, y tendrás un chatbot consciente del contexto respondiendo preguntas de seguimiento en unas pocas líneas. Añade ChatStream para el efecto de escritura en vivo cuando estés listo.

¿Preguntas, comentarios o ayuda para integrarlo en tu aplicación? Ponte en contacto — recibirás una respuesta de las personas que escribieron el código.

Relacionado