Saltar al contenido

Enrutar respuestas de LLM a operaciones de Studio usando llamada a funciones en Jitterbit Studio

Introducción

La llamada a funciones es una capacidad de LLM donde, en lugar de devolver texto libre, el modelo devuelve una selección estructurada de cuál función llamar y qué argumentos pasar. En Studio, esto significa que el LLM puede seleccionar qué operación ejecutar en respuesta a una solicitud del usuario, enrutando un mensaje sobre un cheque de nómina faltante a una operación de notificación de HR, por ejemplo, mientras enruta un mensaje sobre una solicitud de acceso a software a una operación de aprovisionamiento de IT.

Esta guía cubre dos enfoques para implementar este patrón:

  • Parte 1: Llamada a funciones formal: Define esquemas de herramientas en JSON, envíalos con la solicitud de LLM a través del conector HTTP v2, y recibe una respuesta estructurada de tool_calls. Un script extrae el nombre de la función y los argumentos, luego envía a la operación correcta. Este enfoque produce resultados confiables y estructurados, y se recomienda para uso en producción.
  • Parte 2: Enrutamiento basado en instrucciones: Describe las operaciones disponibles como texto sin formato en la instrucción del sistema, luego analiza la respuesta de texto del LLM para encontrar el nombre de función seleccionado y envía usando una sentencia Case. Este enfoque no requiere crear esquemas de herramientas pero depende de que el LLM siga la instrucción de forma precisa.

Esta guía asume familiaridad con la actividad Prompt de OpenAI y el conector HTTP v2. Para detalles de configuración, consulta Usar OpenAI para procesar datos en una operación de Studio y Llamar a una API REST usando el conector HTTP v2.

Patrón de diseño

Ambos enfoques comparten el mismo flujo conceptual y estructura de operación:

  1. El LLM recibe el mensaje del usuario junto con una descripción de las operaciones disponibles (la lista de herramientas).
  2. El LLM selecciona la operación apropiada y devuelve un nombre de función (y en la Parte 1, argumentos estructurados).
  3. Un script de Studio extrae el nombre de la función y enruta la ejecución a la operación correspondiente.

La cadena de operaciones sigue esta estructura:

%%{init: {"themeVariables": {"lineColor": "#6b7280", "edgeLabelBackground": "#f5f5f5"}}}%% flowchart LR A[Operación LLM Prompt] -->|Al tener éxito| B[Operación script Dispatcher] --> C[Operación de destino]

La operación LLM Prompt envía el mensaje del usuario al modelo y almacena la respuesta. La operación script Dispatcher lee la respuesta, extrae el nombre de función seleccionada, y llama a la operación correspondiente usando RunOperation. Cada operación de destino realiza el trabajo actual para esa función.

Variables globales llevan el nombre de función extraída y los argumentos desde el dispatcher hacia cada operación de destino.

Parte 1: Llamada a funciones formal

La API de OpenAI Chat Completions acepta un arreglo de tools en el cuerpo de la solicitud. Cada entrada en el arreglo define una función disponible: su nombre, una descripción que el modelo usa para decidir cuándo llamarla, y un objeto JSON Schema que describe sus parámetros. Cuando el modelo selecciona una función, devuelve un arreglo de tool_calls en su respuesta en lugar de rellenar message.content.

Paso 1: Define los esquemas de herramientas

Cada esquema de herramienta es un objeto JSON con tres campos: name, description y parameters.

El name es el identificador que tu script dispatcher verificará. La description le dice al modelo cuándo llamar esta herramienta: escríbela como una declaración clara del propósito de la función. El objeto parameters sigue convenciones de JSON Schema: lista cada parámetro bajo properties, establece su type y description, y lista parámetros requeridos bajo required.

Esquemas de ejemplo para dos herramientas (una para notificar a HR, otra para notificar a IT):

[
  {
    "type": "function",
    "function": {
      "name": "notify_hr",
      "description": "Send a message to the HR team, for example about onboarding, payroll, or leave requests.",
      "parameters": {
        "type": "object",
        "properties": {
          "email_body": {
            "type": "string",
            "description": "The full text of the message to send."
          },
          "recipient_name": {
            "type": "string",
            "description": "The name of the HR contact to address."
          }
        },
        "required": ["email_body", "recipient_name"]
      }
    }
  },
  {
    "type": "function",
    "function": {
      "name": "notify_it",
      "description": "Send a message to the IT team, for example about software access, hardware, or account issues.",
      "parameters": {
        "type": "object",
        "properties": {
          "email_body": {
            "type": "string",
            "description": "The full text of the message to send."
          },
          "issue_type": {
            "type": "string",
            "description": "A short label for the type of issue, for example 'access request' or 'hardware fault'."
          }
        },
        "required": ["email_body", "issue_type"]
      }
    }
  }
]

Consejo

Escribe las descripciones de herramientas desde la perspectiva del modelo: describe la situación en la que el modelo debe llamar a esta función, no lo que hace la operación subyacente. Las descripciones vagas hacen que el modelo seleccione la herramienta incorrecta.

Paso 2: Incluir las herramientas en la solicitud del LLM

Usa una actividad HTTP v2 POST para llamar al endpoint de OpenAI Chat Completions (https://api.openai.com/v1/chat/completions). En la transformación del cuerpo de la solicitud, construye la solicitud JSON completa como una cadena y asígnala al campo body.

Un cuerpo de solicitud representativo, usando una variable de proyecto para la clave de API y variables globales para el mensaje del usuario y el historial de conversación:

{
  "model": "gpt-4",
  "messages": [
    {
      "role": "system",
      "content": "You are a helpful assistant. Use the available functions to handle the user's request."
    },
    {
      "role": "user",
      "content": "$user_message"
    }
  ],
  "tools": <tools array from Step 1>,
  "tool_choice": "auto"
}

Establecer tool_choice en "auto" permite que el modelo decida si llamar a una función o devolver una respuesta de texto simple. Para forzar una llamada de función, establece tool_choice en "required".

Para la configuración de conexión y autenticación HTTP v2, consulta Llamar a una API REST usando el conector HTTP v2.

Paso 3: Analizar la respuesta de tool_calls

Cuando el modelo selecciona una herramienta, el cuerpo de la respuesta incluye un array tool_calls en choices[0].message. Añade un nodo de script de transformación para extraer el nombre de la función y los argumentos, y guárdalos como variables globales para usarlos en el dispatcher y las operaciones de destino.

En la transformación que sigue a la actividad HTTP v2, añade un nodo de script a nivel raíz:

<trans>
// Check whether the model made a function call
toolCalls = Source.choices[0].message.tool_calls;

If(Length(toolCalls) > 0,
    // Extract the function name and parse the arguments JSON string
    $function_name = toolCalls[0].function.name;
    args = JSONParser(toolCalls[0].function.arguments);

    // Store individual arguments as global variables for downstream operations
    $arg_email_body     = args["email_body"];
    $arg_recipient_name = args["recipient_name"];
    $arg_issue_type     = args["issue_type"];

    WriteToOperationLog("Function selected: " + $function_name);
,
    // No function call: model returned plain text
    $function_name = "";
    WriteToOperationLog("No function call in response");
);
</trans>

JSONParser convierte la cadena arguments (un objeto JSON) en un diccionario. Las claves en args corresponden a los nombres de parámetros definidos en el esquema de herramienta.

Nota

tool_calls no está presente en la respuesta cuando el modelo devuelve texto simple en lugar de llamar a una función. La rama $function_name = "" maneja este caso para que el script dispatcher en el siguiente paso pueda enrutarlo a una operación de respaldo.

Paso 4: Distribuir a la operación de destino

Crea una segunda operación, encadenada en el éxito de la operación LLM Prompt. Esta operación contiene una única herramienta Script que lee function_name y llama a la operación de destino apropiada:

Case($function_name == "notify_hr",
    RunOperation("<TAG>operation:Notify HR</TAG>");,

$function_name == "notify_it",
    RunOperation("<TAG>operation:Notify IT</TAG>");,

true,
    // Default case: unknown function name or plain text response
    WriteToOperationLog("No matching function for: " + $function_name)
);

RunOperation ejecuta la operación de destino de forma sincrónica. Las variables globales establecidas en el Paso 3 (arg_email_body, arg_recipient_name, etc.) están disponibles dentro de cada operación de destino.

Consejo

Para almacenar el historial de conversación entre turnos, usa Cloud Datastore para persistir el array de mensajes entre ejecuciones de operación. Si envías prompts a través de un conector LLM nativo en lugar de HTTP v2, y ese conector ofrece una configuración Store chat context across operations, puede retener el contexto de chat entre operaciones para ti en grupos de agentes en la nube, con agentes privados reteniéndolo en memoria automáticamente.

Parte 2: Enrutamiento basado en prompts

Este enfoque incrusta la lista de operaciones disponibles directamente en el prompt del sistema como texto simple, instruye al modelo a responder con exactamente un nombre de función, y usa una sentencia Case para distribuir. No se requiere JSON de esquema de herramienta.

Paso 1: Construir el manifiesto de herramientas

Usa AddToDict para registrar cada operación disponible. Almacena la descripción y la lista de parámetros opcional juntas en una única cadena, separadas por un carácter |:

AddToDict($tools_dict, "get_account_info",
    "Retrieve account details for a customer.|(account_name)");

AddToDict($tools_dict, "create_ticket",
    "Create a support ticket for a reported issue.|(subject,description)");

AddToDict($tools_dict, "send_notification",
    "Send a notification message to a user.|(user_id,message)");

AddToDict($tools_dict, "unknown_route",
    "Ask the user for clarification when the request is ambiguous.");

Incluya una entrada unknown_route para que el modelo tenga un respaldo seguro cuando la intención del usuario no sea clara.

Step 2: Convertir el manifiesto a texto

Use GetKeys para iterar sobre el diccionario y construir una lista de texto sin formato para incrustar en el aviso del sistema:

toolText = "";
keys = GetKeys($tools_dict);
i = 0;
while(i < Length(keys),
    key    = keys[i];
    entry  = $tools_dict[key];
    desc   = Split(entry, "|")[0];
    params = Split(entry, "|")[1];

    toolText = toolText + "- " + key + ": " + desc;
    If(Length(params) > 0,
        toolText = toolText + " Parameters: " + params
    );
    toolText = toolText + "\n";
    i++
);
$tools_text = toolText;

Step 3: Incluir el manifiesto en el aviso del sistema

En el cuerpo de la solicitud LLM, inserte tools_text en el mensaje del sistema e indique al modelo que responda con exactamente un nombre de función. Incluya el mensaje del usuario como un mensaje de rol user separado para que el modelo tenga una solicitud que enrutar. La instrucción del sistema debe ser explícita: el modelo necesita conocer el formato de salida esperado.

{
  "model": "gpt-4",
  "messages": [
    {
      "role": "system",
      "content": "You are a routing assistant. Based on the user's message, respond with exactly one function name from the list below. Do not include any explanation or other text.\n\nAvailable functions:\n$tools_text"
    },
    {
      "role": "user",
      "content": "$user_message"
    }
  ]
}

El mensaje del sistema contiene la instrucción de enrutamiento y el manifiesto de herramientas (tools_text); el mensaje del usuario contiene la solicitud real (user_message) que el modelo enruta.

Nota

El enrutamiento basado en avisos depende de que el modelo siga la instrucción de formato de salida. Si el modelo devuelve más que el nombre de la función, la llamada a Trim en el Paso 4 elimina los espacios en blanco circundantes, pero no puede corregir respuestas de varias palabras o formateadas. Pruebe el aviso con el modelo objetivo antes de implementar.

Step 4: Extraer el nombre de la función de la respuesta

El modelo devuelve el nombre de la función en choices[0].message.content. Agregue un nodo de script en la transformación después de la actividad HTTP v2 para almacenarlo como una variable global:

<trans>
$function_name = Trim(Source.choices[0].message.content);
WriteToOperationLog("Routing to: " + $function_name);
</trans>

Trim elimina cualquier espacio en blanco inicial o final de la respuesta del modelo.

Step 5: Enviar a la operación objetivo

Encadene una operación despachadora en el éxito de la operación LLM Prompt, usando el mismo patrón Case que en la Parte 1:

Case($function_name == "get_account_info",
    RunOperation("<TAG>operation:Get Account Info</TAG>");,

$function_name == "create_ticket",
    RunOperation("<TAG>operation:Create Ticket</TAG>");,

$function_name == "send_notification",
    RunOperation("<TAG>operation:Send Notification</TAG>");,

$function_name == "unknown_route",
    RunOperation("<TAG>operation:Ask For Clarification</TAG>");,

true,
    WriteToOperationLog("Unrecognised function name: " + $function_name)
);

La rama true final captura cualquier respuesta que no coincida con un nombre de función conocido (por ejemplo, si el modelo devuelve una oración en lugar de una palabra clave única).

Verificar la integración

Verificar la Parte 1 (llamada de función formal)

  1. Implemente y ejecute la operación LLM Prompt con un mensaje de usuario que debe activar una herramienta específica (por ejemplo, un mensaje sobre un problema de nómina para activar notify_hr).

  2. En los registros de operación, confirme que la entrada de registro muestre Function selected: notify_hr (o el nombre de función esperado).

  3. Confirme que la operación despachadora se ejecutó y que la operación objetivo correspondiente (Notify HR) se completó correctamente.

  4. Envíe un mensaje que no deba activar ninguna herramienta (por ejemplo, un saludo general). Confirme que el registro muestre No function call in response y que ninguna operación objetivo se haya llamado inesperadamente.

  5. Si el modelo selecciona consistentemente la herramienta incorrecta, revise las descripciones de las herramientas. Las descripciones que se superponen o carecen de especificidad hacen que el modelo adivine incorrectamente.

  6. Si JSONParser genera un error, confirme que choices[0].message.tool_calls[0].function.arguments sea una cadena JSON válida en la respuesta sin procesar. Un campo de argumentos vacío o mal formado suele indicar un problema de configuración del modelo o del aviso.

Verificar la Parte 2 (enrutamiento basado en avisos)

  1. Implemente y ejecute la operación LLM Prompt con un mensaje que se asigne claramente a una función disponible.

  2. En los registros de operación, confirme que la entrada de registro muestre Routing to: seguido del nombre de función esperado como una sola palabra.

  3. Confirme que la operación objetivo correspondiente se ejecutó y se completó correctamente.

  4. Envía un mensaje ambiguo. Confirma que el registro muestre Routing to: unknown_route y que la operación de clarificación se haya ejecutado.

  5. Si la rama true final se activa inesperadamente, inspecciona el valor choices[0].message.content sin procesar en el registro. Una respuesta que contiene texto adicional (como "I would call: get_account_info") indica que la instrucción del indicador del sistema necesita ser más directiva. Agrega un ejemplo explícito al indicador, como: Example response: get_account_info.