Construir un chat LLM de múltiples turnos con historial de conversación en Jitterbit Studio
Introducción
Una conversación de múltiples turnos requiere más que enviar un solo mensaje de usuario a un LLM: el modelo necesita el historial completo del intercambio para responder de manera coherente a preguntas de seguimiento y mantener el contexto a lo largo de los turnos. Esta guía cubre el patrón de bajo nivel para construir y persistir un arreglo de historial de conversación en Studio, utilizando Cloud Datastore como el almacenamiento de sesión y SumCSV para acumular mensajes entre ejecuciones.
Esta guía es distinta de Cómo construir un agente de IA contextual, que cubre la arquitectura general del agente. El enfoque aquí está en los patrones de script y transformación que construyen el arreglo messages: cómo formatear cada mensaje como una fila CSV, cómo persistir y recuperar el historial completo entre ejecuciones de operación, y cómo manejar campos opcionales como tool_call_id al combinar el historial de conversación con la llamada a funciones.
Esta guía se basa en:
- Almacenar y recuperar el estado de sesión utilizando Cloud Datastore para la configuración de Cloud Datastore y el patrón de consulta-inserción-actualización.
- Usar OpenAI para procesar datos en una operación de Studio o Llamar a una API REST utilizando el conector HTTP v2 para la configuración del endpoint LLM.
Nota
Esta guía gestiona el historial de conversación de manera explícita, que es lo que necesitas cuando llamas al LLM a través del conector HTTP v2. Si envías mensajes a través de un conector LLM nativo en su lugar, el conector puede retener el contexto del chat por ti: los conectores de OpenAI, Azure OpenAI y Amazon Bedrock tienen una configuración de Almacenar contexto de chat entre operaciones que mantiene el historial entre operaciones que comparten el mismo chatId en grupos de agentes en la nube, y los agentes privados retienen el contexto del chat en memoria automáticamente.
Patrón de diseño
El patrón de historial de conversación añade dos pasos alrededor de una llamada estándar a LLM: un paso de recuperación de historial antes de la solicitud y un paso de actualización de historial después de la respuesta.
Recuperar historial por clave de sesión"] --> B["Script
Construir CSV de mensajes"] --> C["Transformación
Convertir CSV a JSON
llamar a LLM"] --> D["Script
Agregar usuario + asistente
Actualizar CDS"]
Cada mensaje del usuario y respuesta del asistente se almacena en Cloud Datastore como una fila en una cadena CSV, identificada por un identificador de sesión (típicamente un ID de canal de Slack o un ID de usuario). Antes de cada llamada a LLM, se recupera el historial completo y se ensambla en el arreglo messages. Después de que LLM responde, el mensaje actual del usuario y la respuesta del asistente se añaden al historial, y la cadena actualizada se escribe de nuevo en Cloud Datastore.
Parte 1: Configurar el almacenamiento de Cloud Datastore
Crea un almacenamiento de clave con un campo ConversationHistory para mantener la cadena de historial CSV para cada sesión. Sigue Almacenar y recuperar el estado de sesión usando Cloud Datastore para los pasos completos de configuración. Para añadir campos, en el portal de Harmony navega a Menú del portal de Harmony > Consola de administración > Cloud Datastore, abre el almacenamiento de clave y añade un campo llamado ConversationHistory con el tipo Texto Grande. Los campos incorporados Key, Alternative Key y Value siempre están presentes y no necesitan ser añadidos.
Nota
Los campos de Texto Grande soportan hasta 25,000 bytes por ítem. Para conversaciones de larga duración, implementa una estrategia de truncamiento: retén solo los N intercambios más recientes antes de escribir de nuevo en Cloud Datastore, o resume turnos anteriores usando el propio LLM antes de almacenar.
Parte 2: Recuperar historial y construir el arreglo de mensajes
Recuperar el historial
El primer paso en la operación consulta Cloud Datastore para el registro de sesión, utilizando el identificador de sesión (por ejemplo, un ID de canal de Slack) como el filtro de clave. Después de la actividad de Consulta de Ítems, lee el resultado en un paso de script:
<trans>
$historyMessages = "";
if(Source.json.pagination.totalItems > 0,
$historyMessages = Source.json.items.item[0].ConversationHistory
);
</trans>
Esto establece historyMessages en la cadena CSV almacenada, o en una cadena vacía si este es el primer turno en la sesión.
Construir el array de mensajes
En el siguiente paso del script, ensambla el array completo de mensajes como una cadena CSV utilizando SumCSV. Cada llamada a SumCSV produce una fila CSV de un array de valores de campo:
<trans>
// System message (always first, not stored in history)
message = Array();
message[0] = "system";
message[1] = $systemPrompt;
$messages = SumCSV(message);
// Append stored conversation history (all prior user/assistant pairs)
if(length(trim($historyMessages)) > 0,
$messages = $messages + "\n" + $historyMessages
);
// Append the current user message
message[0] = "user";
message[1] = $userInput;
$messages = $messages + "\n" + SumCSV(message);
</trans>
messages ahora contiene una cadena CSV con una fila por mensaje. El mensaje del sistema siempre es el primero; la historia almacenada sigue en el orden en que se acumuló; el mensaje del usuario actual es el último.
Consejo
Almacena la clave de sesión en una variable global antes de esta operación para que la actualización de Cloud Datastore en Parte 4 utilice la misma clave.
Parte 3: Convertir el array de mensajes a JSON y llamar al LLM
Configurar el esquema de origen de transformación
Agrega una transformación a la operación y establece sus datos de origen en la variable messages, analizada como CSV. Define un esquema de origen CSV de dos columnas:
role(cadena)content(cadena)
Mapear el array de mensajes a la solicitud del LLM
Mapea las columnas CSV al cuerpo de la solicitud de OpenAI Chat Completions. La ruta de destino para cada entrada de mensaje es json/messages/item:
json/messages/item/role→ columna de origenrolejson/messages/item/content→ columna de origencontent
Si la operación también agrega resultados de llamadas a herramientas a la historia (para su uso con el patrón de bucle de llamadas a herramientas), el CSV puede incluir columnas adicionales. Utiliza Unmap en el script del campo de destino para omitir el campo cuando la columna esté vacía, en lugar de enviar un valor nulo o una cadena vacía:
// En el script de destino para json/messages/item/tool_call_id
if(length(trim(tool_call_id)) == 0, Unmap(), tool_call_id)
Aplica el mismo patrón a name si incluyes una columna tool_name:
// En el script de destino para json/messages/item/name
if(length(trim(tool_name)) == 0, Unmap(), tool_name)
Esto asegura que el campo esté ausente del objeto JSON serializado cuando esté vacío. La API de OpenAI requiere que tool_call_id y name estén ausentes (no nulos ni vacíos) para los mensajes estándar de user y assistant.
Conectar al endpoint LLM
Coloca la actividad HTTP v2 POST que apunte al endpoint de OpenAI Chat Completions después de la transformación. Para la configuración de conexión y autenticación, consulta Usar OpenAI para procesar datos en una operación de Studio.
Parte 4: Agregar la respuesta y actualizar Cloud Datastore
Después de la llamada LLM, un paso de script extrae la respuesta del asistente, agrega tanto el mensaje del usuario como la respuesta del asistente al historial almacenado y escribe la cadena actualizada de nuevo en Cloud Datastore.
Construir la cadena de historial actualizada
<trans>
// Extract the assistant response
$assistantReply = TrimChars(GetJSONString($jitterbit.response, "/choices/0/message/content"), "\"");
// Build the two new rows to append
userMessage = Array();
userMessage[0] = "user";
userMessage[1] = $userInput;
assistantMessage = Array();
assistantMessage[0] = "assistant";
assistantMessage[1] = $assistantReply;
newExchange = SumCSV(userMessage) + "\n" + SumCSV(assistantMessage);
// Combine prior history with the new exchange
$updatedHistory = trim($historyMessages);
if(length($updatedHistory) > 0,
$updatedHistory = $updatedHistory + "\n"
);
$updatedHistory = $updatedHistory + newExchange;
</trans>
updatedHistory contiene todos los intercambios previos más el mensaje actual del usuario y la respuesta del asistente. El mensaje del sistema no se incluye: se antepone dinámicamente al inicio de cada turno en Parte 2 y no necesita ser almacenado.
Escribir el historial actualizado en Cloud Datastore
Utiliza el patrón de consulta-inserción-actualización de Almacenar y recuperar el estado de la sesión usando Cloud Datastore para escribir updatedHistory en el campo ConversationHistory, utilizando el mismo identificador de sesión que se usó en Parte 2.
Nota
La actividad Actualizar Elementos coincide el registro a actualizar por su campo Key. Si el resultado de la consulta de Parte 2 devolvió totalItems = 0, la operación de inserción debe ejecutarse en su lugar. Estructura la cadena posterior a la actualización para que coincida con el patrón en la guía de Cloud Datastore.
Enfoque alternativo: GetInstance()
La función GetInstance proporciona una forma alternativa de asignar roles de mensaje cuando los mensajes ya están almacenados como un arreglo estructurado (por ejemplo, recuperados de un arreglo JSON o de una tabla de base de datos con una fila por mensaje). En una transformación que itera sobre instancias de mensajes, utiliza TargetInstanceCount para obtener el índice de fila actual y asignar roles según la posición par/impar:
<trans>
// Assign alternating user/assistant roles based on row position (1-based)
$role = if(TargetInstanceCount() % 2 == 1, "user", "assistant");
</trans>
Mapea role a json/messages/item/role. Este enfoque funciona cuando todos los turnos están almacenados con sus valores de contenido en orden cronológico y la asignación de roles se puede derivar únicamente de la posición. No admite un mensaje del sistema como una entrada distinta o metadatos de rol por mensaje.
El enfoque SumCSV en la Parte 2 es más flexible para el patrón de agente conversacional: admite un mensaje del sistema explícito, permite cualquier rol por fila y almacena el historial completo como un solo campo de Cloud Datastore sin requerir un esquema de fila por mensaje separado.
Verificar la integración
-
Desplegar y ejecutar la operación con una clave de sesión que aún no existe en el almacenamiento. Proporciona un mensaje inicial del usuario.
-
En los registros de operación, confirma que el resultado de la consulta muestra
totalItems = 0y que la operación de inserción se ejecutó para crear el registro de sesión. -
En Consola de Administración > Cloud Datastore, abre el almacenamiento y confirma que existe un registro con la clave esperada y que
ConversationHistorycontiene una fila de usuario y una fila de asistente. -
Ejecuta la operación nuevamente con la misma clave de sesión y una pregunta de seguimiento que se refiera al primer intercambio.
-
Confirma que la respuesta del LLM refleja el contexto previo. En Cloud Datastore, confirma que
ConversationHistoryahora contiene dos pares de usuario/asistente. -
Si la respuesta del LLM ignora el contexto previo, utiliza
WriteToOperationLogpara registrarmessagesantes de la transformación y confirma que las interacciones anteriores aparecen en la cadena CSV. -
Si la transformación genera un error de desajuste de esquema, confirma que el conteo de columnas del esquema de origen CSV coincide con el número de valores pasados a cada llamada de
SumCSV. Todas las filas deben tener el mismo número de columnas.