Construir un chat multi-turno con LLM e historial de conversación en Jitterbit Studio
Introducción
Una conversación multi-turno requiere más que enviar un único mensaje del usuario a un LLM: el modelo necesita el historial de intercambios completo para responder coherentemente a preguntas de seguimiento y mantener contexto entre turnos. Esta guía cubre el patrón de bajo nivel para construir y persistir un array de historial de conversación en Studio, usando Cloud Datastore como almacén de sesión y SumCSV para acumular mensajes entre ejecuciones.
Esta guía difiere de la 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 array 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 historial de conversación con llamadas a funciones.
Esta guía se basa en:
- Almacenar y recuperar estado de sesión usando Cloud Datastore para la configuración de Cloud Datastore y el patrón consultar-insertar-actualizar.
- Usar OpenAI para procesar datos en una operación de Studio o Llamar a una API REST usando el conector HTTP v2 para la configuración del endpoint de LLM.
Nota
Esta guía gestiona el historial de conversación explícitamente, que es lo que necesitas cuando llamas al LLM sobre el conector HTTP v2. Si envías prompts a través de un conector LLM nativo en su lugar, y ese conector ofrece un ajuste Almacenar contexto de chat entre operaciones, puede retener contexto de chat por ti: este ajuste mantiene historial entre operaciones que comparten el mismo chatId en grupos de agentes en la nube, y los agentes privados retienen contexto de 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.
Retrieve history by session key"] --> B["Script
Build messages CSV"] --> C["Transformation
Convert CSV to JSON
call LLM"] --> D["Script
Append user + assistant
Update CDS"]
Cada mensaje del usuario y respuesta del asistente se almacena en Cloud Datastore como una fila en una cadena CSV, indexada por un identificador de sesión (típicamente un ID de canal de Slack o ID de usuario). Antes de cada llamada a LLM, se recupera el historial completo y se ensambla en el array messages. Después de que el LLM responde, el mensaje del usuario actual y la respuesta del asistente se agregan 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 estado de sesión usando Cloud Datastore para los pasos completos de configuración. Para agregar 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 agrega un campo llamado ConversationHistory con el tipo Big Text. Los campos integrados Key, Alternative Key, y Value siempre están presentes y no necesitan ser agregados.
Nota
Los campos Big Text soportan hasta 25,000 bytes por elemento. 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 mismo LLM antes de almacenar.
Parte 2: Recuperar historial y construir el array de mensajes
Recuperar el historial
El primer paso de la operación consulta Cloud Datastore para obtener el registro de sesión, utilizando el identificador de sesión (por ejemplo, un ID de canal de Slack) como filtro de clave. Después de la actividad Query Items, 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 de la sesión.
Construir el array de mensajes
En el siguiente paso de 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 va primero; el historial almacenado sigue en el orden en que se acumuló; el mensaje del usuario actual va al final.
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 use la misma clave.
Parte 3: Convertir el array de mensajes a JSON y llamar al LLM
Configurar el esquema de origen de la 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)
Asignar el array de mensajes a la solicitud del LLM
Asigna 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 de herramientas al historial (para usar con el patrón de bucle de llamada de 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 vacío:
// In the target script for 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:
// In the target script for json/messages/item/name
if(length(trim(tool_name)) == 0, Unmap(), tool_name)
Esto garantiza 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 mensajes estándar de user y assistant.
Conectar al endpoint del LLM
Coloca la actividad HTTP v2 POST dirigida al endpoint de OpenAI Chat Completions después de la transformación. Para configurar la 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 al 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 nuevamente 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 anteriores más el mensaje del usuario actual 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 query-insert-update de Almacenar y recuperar el estado de la sesión usando Cloud Datastore para escribir updatedHistory en el campo ConversationHistory, indexado por el mismo identificador de sesión utilizado en Parte 2.
Nota
La actividad Update Items hace coincidir el registro a actualizar por su campo Key. Si el resultado de Query de la Parte 2 devolvió totalItems = 0, entonces debe ejecutarse la operación Insert. Estructura la cadena posterior a la actualización para que coincida con el patrón de 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 se almacenan 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 mensaje, usa TargetInstanceCount para obtener el índice de la 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>
Asigna role a json/messages/item/role. Este enfoque funciona cuando todos los turnos se almacenan 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 entrada distinta o metadatos de rol por mensaje.
El enfoque SumCSV en la Parte 2 es más flexible para el patrón del agente conversacional: admite un mensaje del sistema explícito, permite cualquier rol por fila y almacena el historial completo como un único campo de Cloud Datastore sin requerir un esquema de fila por mensaje separado.
Verifica la integración
-
Implementa y ejecuta la operación con una clave de sesión que aún no exista en el almacenamiento. Proporciona un mensaje inicial del usuario.
-
En los registros de operación, confirma que el resultado de Query muestra
totalItems = 0y que se ejecutó la operación Insert para crear el registro de sesión. -
En Management Console > 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 de nuevo con la misma clave de sesión y una pregunta de seguimiento que haga referencia al primer intercambio.
-
Confirma que la respuesta del LLM refleja el contexto anterior. En Cloud Datastore, confirma que
ConversationHistoryahora contiene dos pares de usuario/asistente. -
Si la respuesta del LLM ignora el contexto anterior, usa
WriteToOperationLogpara registrarmessagesantes de la transformación y confirma que los turnos anteriores aparecen en la cadena CSV. -
Si la transformación genera un error de discrepancia de esquema, confirma que el recuento de columnas del esquema de origen CSV coincida con el número de valores pasados a cada llamada de
SumCSV. Todas las filas deben tener el mismo número de columnas.