Zum Inhalt springen

Routen von LLM-Antworten zu Studio-Operationen mithilfe von Funktionsaufrufen in Jitterbit Studio

Einführung

Der Funktionsaufruf ist eine Fähigkeit des LLM, bei der anstelle von freiem Text das Modell eine strukturierte Auswahl zurückgibt, welche Funktion aufgerufen werden soll und welche Argumente übergeben werden. In Studio bedeutet dies, dass das LLM auswählen kann, welche Operation als Antwort auf eine Benutzeranfrage ausgeführt werden soll, indem beispielsweise eine Nachricht über einen fehlenden Gehaltscheck an eine HR-Benachrichtigungsoperation weitergeleitet wird, während eine Nachricht über eine Anfrage für Softwarezugang an eine IT-Bereitstellungsoperation weitergeleitet wird.

Dieser Leitfaden behandelt zwei Ansätze zur Implementierung dieses Musters:

  • Teil 1: Formale Funktionsaufrufe: Definieren Sie Tool-Schemas in JSON, reichen Sie diese mit der LLM-Anfrage über den HTTP v2 Connector ein und erhalten Sie eine strukturierte tool_calls-Antwort. Ein Skript extrahiert den Funktionsnamen und die Argumente und leitet dann an die entsprechende Operation weiter. Dieser Ansatz liefert zuverlässige, strukturierte Ausgaben und wird für den produktiven Einsatz empfohlen.
  • Teil 2: Prompt-basiertes Routing: Beschreiben Sie die verfügbaren Operationen als einfachen Text im System-Prompt und analysieren Sie dann die Textantwort des LLM auf den ausgewählten Funktionsnamen und leiten Sie die Ausführung mithilfe einer Case-Anweisung weiter. Dieser Ansatz erfordert keine Erstellung von Tool-Schemas, hängt jedoch davon ab, dass das LLM die Anweisungen im Prompt genau befolgt.

Dieser Leitfaden setzt Vertrautheit mit der OpenAI Prompt-Aktivität und dem HTTP v2 Connector voraus. Für Einrichtungshinweise siehe OpenAI zur Verarbeitung von Daten in einer Studio-Operation verwenden und Eine REST-API mit dem HTTP v2 Connector aufrufen.

Entwurfsmuster

Beide Ansätze teilen sich denselben konzeptionellen Ablauf und die gleiche Betriebsstruktur:

  1. Das LLM erhält die Nachricht des Benutzers zusammen mit einer Beschreibung der verfügbaren Operationen (der Tool-Liste).
  2. Das LLM wählt die geeignete Operation aus und gibt einen Funktionsnamen zurück (und im Teil 1 strukturierte Argumente).
  3. Ein Studio-Skript extrahiert den Funktionsnamen und leitet die Ausführung an die entsprechende Operation weiter.

Die Operationenkette folgt dieser Struktur:

flowchart LR A[LLM Prompt-Operation] -->|Bei Erfolg| B[Dispatcher-Skript-Operation] --> C[Zieloperation]

Die LLM Prompt-Operation sendet die Benutzeranfrage an das Modell und speichert die Antwort. Die Dispatcher-Skript-Operation liest die Antwort, extrahiert den ausgewählten Funktionsnamen und ruft die entsprechende Operation mit RunOperation auf. Jede Zieloperation führt die tatsächliche Arbeit für diese Funktion aus.

Globale Variablen übertragen den extrahierten Funktionsnamen und die Argumente vom Dispatcher in jede Zieloperation.

Teil 1: Formale Funktionsaufrufe

Die OpenAI Chat Completions API akzeptiert ein tools-Array im Anfragekörper. Jeder Eintrag im Array definiert eine verfügbare Funktion: ihren Namen, eine Beschreibung, die das Modell verwendet, um zu entscheiden, wann es sie aufrufen soll, und ein JSON-Schema-Objekt, das ihre Parameter beschreibt. Wenn das Modell eine Funktion auswählt, gibt es ein tool_calls-Array in seiner Antwort zurück, anstatt message.content auszufüllen.

Schritt 1: Definieren Sie die Tool-Schemas

Jedes Tool-Schema ist ein JSON-Objekt mit drei Feldern: name, description und parameters.

Der name ist der Bezeichner, den Ihr Dispatcher-Skript überprüfen wird. Die description sagt dem Modell, wann es dieses Tool aufrufen soll: Schreiben Sie es als klare Aussage über den Zweck der Funktion. Das parameters-Objekt folgt den JSON-Schema-Konventionen: Listen Sie jeden Parameter unter properties auf, setzen Sie seinen type und description und listen Sie erforderliche Parameter unter required auf.

Beispiel-Schemas für zwei Tools (eines zur Benachrichtigung der Personalabteilung, eines zur Benachrichtigung der 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"]
      }
    }
  }
]

Tipp

Schreiben Sie die Tool-Beschreibungen aus der Perspektive des Modells: Beschreiben Sie die Situation, in der das Modell diese Funktion aufrufen sollte, nicht, was die zugrunde liegende Operation tut. Vage Beschreibungen führen dazu, dass das Modell das falsche Tool auswählt.

Schritt 2: Die Werkzeuge in die LLM-Anfrage einfügen

Verwenden Sie eine HTTP v2 POST-Aktivität, um den OpenAI Chat Completions-Endpunkt (https://api.openai.com/v1/chat/completions) aufzurufen. Im Anfragekörper-Transformation konstruieren Sie die vollständige JSON-Anfrage als Zeichenfolge und mappen sie auf das Feld body.

Ein repräsentativer Anfragekörper, der eine Projektvariable für den API-Schlüssel und globale Variablen für die Benutzer-Nachricht und den Gesprächsverlauf verwendet:

{
  "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"
}

Das Setzen von tool_choice auf "auto" ermöglicht es dem Modell zu entscheiden, ob eine Funktion aufgerufen oder eine einfache Textantwort zurückgegeben wird. Um einen Funktionsaufruf zu erzwingen, setzen Sie tool_choice auf "required".

Für die HTTP v2-Verbindung und die Authentifizierungseinrichtung siehe Rufen Sie eine REST-API mit dem HTTP v2-Connector auf.

Schritt 3: Die tool_calls-Antwort analysieren

Wenn das Modell ein Werkzeug auswählt, enthält der Antwortkörper ein tool_calls-Array in choices[0].message. Fügen Sie einen Transformationsskriptknoten hinzu, um den Funktionsnamen und die Argumente zu extrahieren und sie als globale Variablen für die Verwendung in den Dispatcher- und Zieloperationen zu speichern.

In der Transformation, die auf die HTTP v2-Aktivität folgt, fügen Sie auf der obersten Ebene einen Skriptknoten hinzu:

<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 konvertiert die arguments-Zeichenfolge (ein JSON-Objekt) in ein Wörterbuch. Die Schlüssel in args entsprechen den Parameternamen, die im Werkzeug-Schema definiert sind.

Hinweis

tool_calls ist in der Antwort nicht vorhanden, wenn das Modell einfachen Text anstelle eines Funktionsaufrufs zurückgibt. Der $function_name = ""-Zweig behandelt diesen Fall, sodass das Dispatcher-Skript im nächsten Schritt es an eine Fallback-Operation weiterleiten kann.

Schritt 4: An die Zieloperation weiterleiten

Erstellen Sie eine zweite Operation, die an den Erfolg der LLM Prompt-Operation angekettet ist. Diese Operation enthält ein einzelnes Skriptwerkzeug, das function_name liest und die entsprechende Zieloperation aufruft:

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 führt die Zieloperation synchron aus. Die in Schritt 3 festgelegten globalen Variablen (arg_email_body, arg_recipient_name usw.) sind innerhalb jeder Zieloperation verfügbar.

Tipp

Um den Verlauf der Konversation zwischen den Interaktionen zu speichern, verwenden Sie Cloud Datastore, um das Nachrichtenarray über die Ausführungen der Operationen hinweg zu persistieren. Wenn Sie Eingaben über einen nativen LLM-Connector anstelle von HTTP v2 senden, können die OpenAI-, Azure OpenAI- und Amazon Bedrock-Connectoren stattdessen den Chat-Kontext über die Operationen hinweg für Sie in Cloud-Agentengruppen (mit privaten Agenten, die ihn im Speicher behalten) beibehalten.

Teil 2: Prompt-basiertes Routing

Dieser Ansatz bettet die Liste der verfügbaren Operationen direkt im System-Prompt als einfachen Text ein, weist das Modell an, mit genau einem Funktionsnamen zu antworten, und verwendet eine Case Anweisung zur Weiterleitung. Es ist kein Tool-Schema-JSON erforderlich.

Schritt 1: Erstellen des Tool-Manifests

Verwenden Sie AddToDict, um jede verfügbare Operation zu registrieren. Speichern Sie die Beschreibung und die optionale Parameterliste zusammen in einem einzigen String, getrennt durch ein |-Zeichen:

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.");

Fügen Sie einen unknown_route-Eintrag hinzu, damit das Modell einen sicheren Rückfall hat, wenn die Absicht des Benutzers unklar ist.

Schritt 2: Manifest in Text umwandeln

Verwenden Sie GetKeys, um über das Wörterbuch zu iterieren und eine einfache Textliste für die Einbettung im System-Prompt zu erstellen:

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;

Schritt 3: Manifest im System-Prompt einfügen

In der LLM-Anforderungsnachricht fügen Sie tools_text in die Systemnachricht ein und weisen das Modell an, mit genau einem Funktionsnamen zu antworten. Fügen Sie die Nachricht des Benutzers als separate user-Nachricht hinzu, damit das Modell eine Anfrage hat, die es weiterleiten kann. Die Systemanweisung muss eindeutig sein: Das Modell muss das erwartete Ausgabeformat kennen.

{
  "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"
    }
  ]
}

Die Systemnachricht enthält die Weiterleitungsanweisung und das Tool-Manifest (tools_text); die Benutzernachricht enthält die tatsächliche Anfrage (user_message), die das Modell weiterleitet.

Hinweis

Die auf Eingabeaufforderungen basierende Weiterleitung hängt davon ab, dass das Modell der Anweisung zum Ausgabeformat folgt. Wenn das Modell mehr als den Funktionsnamen zurückgibt, entfernt der Trim Aufruf in Schritt 4 den umgebenden Leerraum, kann jedoch mehrwortige oder formatierte Antworten nicht korrigieren. Testen Sie die Eingabeaufforderung mit dem Zielmodell, bevor Sie sie bereitstellen.

Schritt 4: Extrahieren Sie den Funktionsnamen aus der Antwort

Das Modell gibt den Funktionsnamen in choices[0].message.content zurück. Fügen Sie einen Skriptnode in der Transformation nach der HTTP v2-Aktivität hinzu, um ihn als globale Variable zu speichern:

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

Trim entfernt alle führenden oder nachfolgenden Leerzeichen aus der Antwort des Modells.

Schritt 5: An die Zieloperation weiterleiten

Verketten Sie eine Dispatcher-Operation bei Erfolg der LLM Prompt-Operation, unter Verwendung des gleichen Case-Musters wie Teil 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)
);

Der letzte true-Zweig fängt jede Antwort ab, die nicht mit einem bekannten Funktionsnamen übereinstimmt (zum Beispiel, wenn das Modell einen Satz anstelle eines einzelnen Schlüsselworts zurückgibt).

Überprüfen Sie die Integration

Überprüfung Teil 1 (formale Funktionsaufrufe)

  1. Bereitstellen und ausführen Sie die LLM Prompt-Operation mit einer Benutzernachricht, die ein bestimmtes Tool auslösen sollte (zum Beispiel eine Nachricht über ein Gehaltsproblem, um notify_hr auszulösen).

  2. In den Betriebsprotokollen bestätigen, dass der Protokolleintrag Funktion ausgewählt: notify_hr (oder der erwartete Funktionsname) anzeigt.

  3. Bestätigen, dass die Dispatcher-Operation ausgeführt wurde und dass die entsprechende Zieloperation (Notify HR) erfolgreich abgeschlossen wurde.

  4. Eine Nachricht senden, die kein Tool auslösen sollte (zum Beispiel eine allgemeine Begrüßung). Bestätigen, dass das Protokoll Keine Funktionsaufruf als Antwort anzeigt und dass keine Zieloperation unerwartet aufgerufen wurde.

  5. Wenn das Modell konsequent das falsche Tool auswählt, die Tool-Beschreibungen überprüfen. Überlappende oder unspezifische Beschreibungen führen dazu, dass das Modell falsch rät.

  6. Wenn JSONParser einen Fehler auslöst, bestätigen, dass choices[0].message.tool_calls[0].function.arguments ein gültiger JSON-String in der Rohantwort ist. Ein leeres oder fehlerhaftes Argumentfeld deutet typischerweise auf ein Modell- oder Prompt-Konfigurationsproblem hin.

Überprüfung Teil 2 (aufforderungsbasiertes Routing)

  1. Bereitstellen und ausführen der LLM Prompt-Operation mit einer Nachricht, die klar einer verfügbaren Funktion zugeordnet ist.

  2. In den Betriebsprotokollen bestätigen, dass der Protokolleintrag Routing zu: gefolgt vom erwarteten Funktionsnamen als ein einzelnes Wort anzeigt.

  3. Bestätigen, dass die entsprechende Zieloperation ausgeführt und erfolgreich abgeschlossen wurde.

  4. Eine mehrdeutige Nachricht senden. Bestätigen, dass das Protokoll Routing zu: unknown_route anzeigt und dass die Klärungsoperation ausgeführt wurde.

  5. Wenn der finale true-Zweig unerwartet ausgelöst wird, den Rohwert von choices[0].message.content im Protokoll überprüfen. Eine Antwort, die zusätzlichen Text enthält (wie "Ich würde aufrufen: get_account_info"), deutet darauf hin, dass die Systemaufforderungsanweisung direkter sein muss. Ein explizites Beispiel zur Aufforderung hinzufügen, wie: Beispielantwort: get_account_info.