Implementieren Sie eine LLM-Tool-Calling-Schleife in Jitterbit Studio
Einführung
Single-Round-Funktionsaufrufe (behandelt in LLM-Antworten mithilfe von Funktionsaufrufen zu Studio-Operationen weiterleiten) verarbeiten pro Anfrage eine Toolauswahl: Das Modell wählt eine Funktion aus, eine Studio-Operation führt sie aus, und die Interaktion endet. Viele agentengesteuerte Workflows erfordern mehr als einen Tool-Aufruf, um eine einzelne Benutzeranfrage zu beantworten: Das Modell muss möglicherweise einen CRM-Datensatz abfragen, dann Kontodaten abrufen und dann eine Zusammenfassung mit beiden Ergebnissen erstellen.
Eine Tool-Calling-Schleife verarbeitet dies, indem jedes Tool-Ergebnis als tool-Rollennachricht an das LLM zurückgegeben wird und das Modell erneut mit der erweiterten Konversation aufgerufen wird. Die Schleife wiederholt sich, bis das Modell eine Nur-Text-Antwort ohne Tool-Aufrufe erzeugt oder eine maximale Iterationsbegrenzung erreicht wird.
Diese Anleitung baut auf Folgendem auf:
- LLM-Antworten mithilfe von Funktionsaufrufen zu Studio-Operationen weiterleiten für die Tool-Schema-Definition und das Single-Round-Dispatch-Muster. Lesen Sie diese Anleitung zuerst.
- Erstellen Sie einen mehrteiligen LLM-Chat mit Konversationsverlauf, wenn Sie die Tool-Calling-Schleife mit persistentem Konversationsspeicher über Benutzerinteraktionen hinweg kombinieren.
Designmuster
Die Schleife fügt dem Single-Round-Funktionsaufrufen-Muster zwei Schritte hinzu: Anhängen des Tool-Ergebnisses an das Messages-Array und erneutes Aufrufen des LLM. Die Schleife wiederholt sich, solange die Modellantworte ein tool_calls-Array enthält.
Build initial request
(base messages + tools)"] --> B["HTTP v2
LLM call"] B --> C{"tool_calls
in response?"} C -->|Yes| D["Script
Extract function
name and ID"] D --> E["Dispatcher
Run tool
operation"] E --> F["Script
Append tool result
rebuild request"] F --> B C -->|No| G["Script
Extract final
response"]
Fünf globale Variablen führen den Status über Iterationen hinweg:
| Variable | Zweck |
|---|---|
InAndOut |
Der aktuelle LLM-Anfragekörper (vor jedem Aufruf aktualisiert). |
non_tool_messages_json |
Die Basis-Nachrichten (Systemaufforderung und Benutzernachricht) als JSON-Array-String. Bleibt über alle Iterationen hinweg konstant. |
tools_messages |
Die gesammelten Tool-Austausch-Nachrichten aus allen vorherigen Runden als JSON-Array-String. Wächst mit jeder Iteration. |
tools_resp |
Die neueste LLM-Antwort, die eine tool_calls-Auswahl enthielt. Wird verwendet, um die Assistenten-Nachricht zur Akkumulation zu extrahieren. |
call_llm_again |
Auf true gesetzt, wenn ein Tool-Aufruf läuft; auf false gesetzt, wenn das Modell eine endgültige Antwort zurückgibt. |
Teil 1: Initialisieren Sie die Schleifenvariablen
Vor dem ersten LLM-Aufruf erstellen Sie die Basis-Nachrichten und den anfänglichen Anfragekörper und setzen Sie alle Schleifenstatsvariablen zurück. Fügen Sie einen Skriptschritt am Anfang der Operation hinzu:
// Escape and build the base messages as a JSON array string
systemMsg = "{\"role\":\"system\",\"content\":\""
+ Replace($systemPrompt, "\"", "\\\"") + "\"}";
userMsg = "{\"role\":\"user\",\"content\":\""
+ Replace($userMessage, "\"", "\\\"") + "\"}";
$non_tool_messages_json = "[" + systemMsg + "," + userMsg + "]";
// Build the full initial request body
$InAndOut = "{\"model\":\"gpt-4o\","
+ "\"messages\":[" + systemMsg + "," + userMsg + "],"
+ "\"tools\":" + $toolsJson + ","
+ "\"tool_choice\":\"auto\"}";
// Initialize loop state
$tools_messages = "";
$tools_resp = "";
$call_llm_again = false;
$loop_count = 0;
toolsJson ist eine Projektvariable, die das serialisierte Tool-Schema-Array enthält. Für das Tool-Definitionsformat und die Konstruktion der Schemas siehe LLM-Antworten mithilfe von Funktionsaufrufen zu Studio-Operationen weiterleiten.
Hinweis
Speichern Sie die Basis-Nachrichten in non_tool_messages_json, bevor die Schleife beginnt. Jede Iteration kombiniert diese Basis-Nachrichten mit den gesammelten Tool-Austauschvorgängen, um das vollständige Messages-Array neu zu erstellen. Aktualisieren Sie non_tool_messages_json nicht innerhalb der Schleife.
Teil 2: Analysieren Sie die Tool-Call-Antwort
Verketten Sie einen LLM-Aufruf (HTTP v2 POST zum OpenAI Chat Completions-Endpunkt mit InAndOut als Anfragekörper). Für Verbindungs- und Authentifizierungseinrichtung siehe Rufen Sie eine REST-API mithilfe des HTTP v2-Connectors auf.
Fügen Sie bei Erfolg einen Skriptschritt hinzu, um die Antwort zu lesen und die Schleifenkontrollvariablen festzulegen:
// Check whether the model selected a tool
toolCallsVal = GetJSONString($jitterbit.response, "/choices/0/message/tool_calls");
hasToolCalls = (toolCallsVal != "null" && Length(toolCallsVal) > 2);
If(hasToolCalls,
$tool_call_id = TrimChars(GetJSONString($jitterbit.response,
"/choices/0/message/tool_calls/0/id"), "\"");
$function_name = TrimChars(GetJSONString($jitterbit.response,
"/choices/0/message/tool_calls/0/function/name"), "\"");
$function_arguments = GetJSONString($jitterbit.response,
"/choices/0/message/tool_calls/0/function/arguments");
$tools_resp = $jitterbit.response;
$call_llm_again = true;
,
$call_llm_again = false;
$final_response = TrimChars(GetJSONString($jitterbit.response,
"/choices/0/message/content"), "\"");
);
tool_call_id ist ein eindeutiger Bezeichner, den die API jedem Tool-Aufruf zuweist. Er muss in der Tool-Ergebnisnachricht in Teil 4 genau wie empfangen zurückgegeben werden, sonst lehnt die API die Anfrage ab.
Hinweis
tool_calls fehlt in der Antwort, wenn das Modell Nur-Text zurückgibt. Der GetJSONString-Aufruf gibt in diesem Fall "null" zurück, und die Längenkontrolle > 2 unterscheidet korrekt ein gefülltes Array (das mindestens [...] mit einer Länge von 3 oder mehr ist) von einem fehlenden oder leeren Wert.
Behandlung mehrerer Tool-Aufrufe
Das obige Skript liest tool_calls/0, den ersten Tool-Aufruf in der Antwort. Ein LLM kann mehrere Tool-Aufrufe in einer einzelnen Antwort zurückgeben (parallele Tool-Aufrufe), und alle Aufrufe nach dem ersten werden ignoriert. Um jeden Aufruf zu verarbeiten, führen Sie eines der folgenden Verfahren durch:
- Deaktivieren Sie parallele Tool-Aufrufe in der LLM-Anfrage, damit das Modell maximal einen Aufruf pro Antwort zurückgibt. Für die OpenAI- und Azure OpenAI Chat Completions APIs setzen Sie
parallel_tool_callsauffalseim Anfragekörper, der in Teil 1 erstellt wird. - Durchlaufen Sie das Array
tool_calls, versenden Sie jedes Tool und fügen Sie vor dem nächsten LLM-Aufruf einetool-Ergebnismeldung pro Eintrag an. Verwenden SieGetJSONStringmit einem inkrementierenden Index (z. B./choices/0/message/tool_calls/1/id), um jeden zusätzlichen Aufruf zu lesen. Die LLM-API erfordert ein passendestool-Ergebnis für jedetool_call_idin der Assistentenmeldung, die einmal gesendet wird.
Teil 3: Versand zur Tool-Operation
Verwenden Sie eine Case-Anweisung, um basierend auf function_name zur korrekten Tool-Operation zu versenden. Folgen Sie dabei dem gleichen Muster wie unter LLM-Antworten mithilfe von Function Calling zu Studio-Operationen weiterleiten. Jede Zieloperation führt die angeforderte Funktion aus und setzt function_resp auf die Ergebniszeichenfolge.
function_arguments enthält die Parameterauswahl des Modells als JSON-Zeichenfolge. Analysieren Sie diese mit JSONParser innerhalb jeder Zieloperation, um einzelne Argumentwerte zu extrahieren.
Teil 4: Tool-Ergebnis anfügen und Anfrage neu erstellen
Nachdem die Tool-Operation function_resp setzt, erstellen Sie das aktualisierte Nachrichtenarray für den nächsten LLM-Aufruf. Dieser Schritt erfordert komplexe JSON-Manipulation: Analysieren Sie die gesammelten Nachrichten, fügen Sie neue Einträge an und serialisieren Sie das Ergebnis erneut. Implementieren Sie dies als JavaScript-Skriptschritt:
var tool_resp = JSON.parse($tools_resp);
var prev_tool_msgs = $tools_messages ? JSON.parse($tools_messages) : [];
var base_msgs = JSON.parse($non_tool_messages_json);
// The assistant message that selected the tool (must precede the tool result)
var assistant_msg = tool_resp.choices[0].message;
// The tool result returned by the Studio operation
var tool_result_msg = {
"role": "tool",
"tool_call_id": $tool_call_id,
"content": String($function_resp)
};
// Accumulate all tool exchanges: assistant selection followed by tool result
prev_tool_msgs.push(assistant_msg);
prev_tool_msgs.push(tool_result_msg);
// Rebuild the full request with base messages + all accumulated tool exchanges
var req = JSON.parse($InAndOut);
req["messages"] = base_msgs.concat(prev_tool_msgs);
$tools_messages = JSON.stringify(prev_tool_msgs);
$InAndOut = JSON.stringify(req);
Um JavaScript in einem Skriptschritt zu verwenden, setzen Sie die Skriptsprache im Script-Editor auf JavaScript, bevor Sie Inhalte hinzufügen.
Hinweis
Die Assistentenmeldung (tool_resp.choices[0].message) muss unmittelbar vor ihrer entsprechenden tool-Ergebnismeldung im Array stehen. Die OpenAI-API erfordert, dass die tool_calls-Auswahl und das entsprechende tool-Ergebnis nebeneinander und in der gleichen Reihenfolge wie die Aufrufe stehen. Eine nicht übereinstimmende oder fehlende tool_call_id verursacht einen 400-Fehler.
Tipp
Wenn die Tool-Operation strukturierte Daten zurückgibt (z. B. ein JSON-Objekt), serialisieren Sie diese in eine Zeichenfolge, bevor Sie sie function_resp zuweisen. Das Feld content der tool-Rollenmeldung muss eine Zeichenfolge sein.
Teil 5: Schleife steuern
Umhüllen Sie den LLM-Aufruf, den Dispatcher und die Schritte zum Neuerstellen der Anfrage in einem Jitterbit Script-Controller mit einer While-Schleife. Platzieren Sie diesen Controller am Anfang der Operationskette:
maxIterations = 5;
// First LLM call (always runs before the loop)
RunOperation("<TAG>operation:LLM Call</TAG>");
// Loop until the model returns a final response or the limit is reached
while($call_llm_again == true && $loop_count < maxIterations,
$loop_count = $loop_count + 1;
RunOperation("<TAG>operation:Tool Dispatcher</TAG>");
RunScript("<TAG>script:Append Tool Result</TAG>");
RunOperation("<TAG>operation:LLM Call</TAG>");
);
If($loop_count >= maxIterations && $call_llm_again == true,
WriteToOperationLog("Tool-calling loop reached " + maxIterations
+ " iterations without a final response. Last function: " + $function_name)
);
Die Operation LLM Call verwendet InAndOut als Anfragekörper und führt den Parser aus Teil 2 bei Erfolg aus. Die Operation Tool Dispatcher führt die Case-Anweisung aus Teil 3 aus. Append Tool Result ist das JavaScript-Skript aus Teil 4, das hier als benannte Skriptkomponente mit RunScript referenziert wird.
Das Festlegen einer maximalen Iterationsbegrenzung verhindert Endlosschleifen, wenn ein Tool konsistent einen Fehler zurückgibt und das Modell darauf reagiert, indem es das gleiche Tool erneut anfordert.
Tipp
Beginnen Sie mit einer Begrenzung von 5 Iterationen. Die meisten Workflows werden in einer oder zwei Runden gelöst. Wenn Sie die Begrenzung konsistent erreichen, deutet dies auf ein Problem mit dem Prompt-Design oder dem Tool-Ergebnis hin, nicht auf die Notwendigkeit einer höheren Begrenzung.
Alternative: Jitterbit Script-Nachrichtenerstellung
Wenn Sie JavaScript vermeiden möchten, kann die Nachrichtenakkumulation in Teil 4 vollständig in Jitterbit Script mithilfe von Zeichenkettenverkettung implementiert werden. Der HR Agent implementiert diesen Ansatz und verwendet gpt.registeredTools als Projektvariable, um die serialisierten Tool-Schemas zu speichern (entsprechend toolsJson in diesem Leitfaden), wobei call_llm_again die Schleife steuert.
Der Jitterbit-Script-Ansatz erstellt die Nachrichten des Assistenten und des Tool-Ergebnisses, indem JSON-Strings direkt verkettet werden, anstatt JSON.parse und JSON.stringify zu verwenden. Das akkumulierte Array wird verwaltet, indem die Assistentennachricht aus tools_resp mit GetJSONString extrahiert und das Tool-Ergebnis als formatierter String angefügt wird:
// Extract the full assistant message object from the previous response
assistantMsgJson = GetJSONString($tools_resp, "/choices/0/message");
// Build the tool result message
escapedResp = Replace($function_resp, "\"", "\\\"");
toolResultJson = "{\"role\":\"tool\",\"tool_call_id\":\""
+ $tool_call_id + "\",\"content\":\"" + escapedResp + "\"}";
// Accumulate: start a new array or append to the existing one
If(Length($tools_messages) == 0,
$tools_messages = "[" + assistantMsgJson + "," + toolResultJson + "]"
,
$tools_messages = Left($tools_messages, Length($tools_messages) - 1)
+ "," + assistantMsgJson + "," + toolResultJson + "]"
);
// Rebuild the request by replacing the messages field
// (omitted: requires parsing and replacing the messages array in $InAndOut)
Das vollständige Ersetzen des Feldes messages in InAndOut erfordert das Ersetzen des vorhandenen Array-Werts innerhalb der JSON-Zeichenkette, was fehleranfällig ist, wenn der Nachrichteninhalt Sonderzeichen enthält. Verwenden Sie den JavaScript-Ansatz in Teil 4, wenn möglich. Reservieren Sie den Jitterbit-Script-Ansatz für Projekte, in denen JavaScript nicht verfügbar ist.
Integration überprüfen
-
Stellen Sie die Controller-Operation bereit und führen Sie sie aus, indem Sie eine Benutzernachricht verwenden, die genau einen Tool-Aufruf erfordert. Bestätigen Sie in den Operationsprotokollen, dass
loop_countauf 1 erhöht wird und dass die Tool-Operation ausgeführt wurde und ein Ergebnis zurückgegeben hat. -
Bestätigen Sie in den Protokollen, dass der zweite LLM-Aufruf das erweiterte Messages-Array erhalten hat (protokollieren Sie
InAndOutmitWriteToOperationLogvor dem LLM-Aufruf) und dass er eine einfache Textantwort ohnetool_callszurückgegeben hat. -
Senden Sie eine Benutzernachricht, die zwei aufeinanderfolgende Tool-Aufrufe erfordert (z. B. einen Kontakt nachschlagen und dann ein Ticket für diesen Kontakt erstellen). Bestätigen Sie, dass
loop_count2 erreicht, und überprüfen Sie dann die akkumulierten Nachrichten.tools_messagesist eine serialisierte JSON-Array-Zeichenkette. Protokollieren Sie sie nach Abschluss der Schleife, um ihren Inhalt anzuzeigen:WriteToOperationLog("tools_messages: " + $tools_messages);Bestätigen Sie in der protokollierten Zeichenkette, dass vier Objekte vorhanden sind, die zwischen
"role":"assistant"und"role":"tool"wechseln (zwei von jedem): Jede Runde fügt die Assistentennachricht an, die das Tool ausgewählt hat, gefolgt von seinemtool-Ergebnis. Dietool_call_idjedertool-Nachricht sollte mit deridim Eintragtool_callsder vorherigen Assistentennachricht übereinstimmen. -
Senden Sie eine Nachricht, die keinen Tool-Aufruf erfordert (z. B. eine allgemeine Frage, die das Modell aus seinem eigenen Wissen beantworten kann). Bestätigen Sie, dass die Schleife nicht ausgeführt wird (der erste LLM-Aufruf gibt keine
tool_callszurück,call_llm_againbleibtfalseundloop_countbleibt 0). -
Wenn die API einen 400-Fehler mit Verweis auf eine ungültige
tool_call_idzurückgibt, protokollieren Sie den Wert vontool_call_idund vergleichen Sie ihn mit dem Feldidinchoices[0].message.tool_calls[0]aus der vorherigen LLM-Antwort. Eine Nichtübereinstimmung bedeutet normalerweise, dasstools_respaktualisiert wurde, bevor die ID extrahiert wurde. -
Wenn die Schleife das Iterationslimit erreicht, protokollieren Sie
InAndOutam Anfang jeder Runde, um die akkumulierten Nachrichten zu überprüfen. Ein wiederholter Tool-Aufruf für dieselbe Funktion mit denselben Argumenten deutet darauf hin, dass die Tool-Operation ein Fehlerergebnis zurückgibt, das das Modell erneut versucht, oder dass die Tool-Beschreibung nicht mit der Benutzeranfrage übereinstimmt.