Implementieren Sie eine LLM-Tool-Calling-Schleife in Jitterbit Studio
Einführung
Single-Round-Funktionsaufrufe (behandelt unter Leiten Sie LLM-Responses an Studio-Operationen mithilfe von Funktionsaufrufen weiter) verarbeiten pro Request eine Toolauswahl: das Modell wählt eine Funktion, eine Studio-Operation führt diese aus, und die Interaktion endet. Viele agentenbasierte Workflows erfordern mehr als einen Toolaufruf, um eine einzelne Benutzeranfrage zu beantworten: Das Modell muss möglicherweise einen CRM-Datensatz abfragen, dann Kontoinformationen abrufen und anschließend eine Zusammenfassung mit beiden Ergebnissen erstellen.
Eine Tool-Calling-Schleife verarbeitet dies, indem jedes Tool-Ergebnis als tool-Rolle-Nachricht an das LLM zurückgegeben und das Modell mit der erweiterten Konversation erneut aufgerufen wird. Die Schleife wiederholt sich, bis das Modell eine Klartext-Response ohne Tool-Aufrufe erzeugt oder eine maximale Iterationslimit erreicht ist.
Diese Anleitung baut auf:
- Leiten Sie LLM-Responses an Studio-Operationen mithilfe von Funktionsaufrufen weiter für die Tool-Schemadefinition und das Single-Round-Dispatch-Muster. Lesen Sie zuerst diese Anleitung.
- Erstellen Sie einen Multi-Turn-LLM-Chat mit Konversationsverlauf, wenn Sie die Tool-Calling-Schleife mit persistentem Konversationsspeicher über Benutzer-Turns hinweg kombinieren.
Designmuster
Die Schleife fügt zwei Schritte zum Single-Round-Funktionsaufrufs-Muster hinzu: das Anfügen des Tool-Ergebnisses zum Messages-Array und das erneute Aufrufen des LLM. Die Schleife wiederholt sich, solange die Modell-Response 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-Request-Body (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 kumulierten Tool-Austausch-Nachrichten aus allen vorherigen Runden als JSON-Array-String. Wächst mit jeder Iteration. |
tools_resp |
Die neueste LLM-Response, die eine tool_calls-Auswahl enthielt. Wird verwendet, um die Assistent-Nachricht zur Akkumulation zu extrahieren. |
call_llm_again |
Wird auf true gesetzt, wenn ein Tool-Aufruf läuft; wird auf false gesetzt, wenn das Modell eine endgültige Response zurückgibt. |
Teil 1: Initialisieren Sie die Schleifenvariablen
Vor dem ersten LLM-Aufruf erstellen Sie die Basis-Nachrichten und den initialen Request-Body und setzen alle Schleifenstatus-Variablen zurück. Fügen Sie einen Script-Schritt 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 Leiten Sie LLM-Responses an Studio-Operationen mithilfe von Funktionsaufrufen weiter.
Hinweis
Speichern Sie die Basis-Nachrichten in non_tool_messages_json, bevor die Schleife beginnt. Jede Iteration kombiniert diese Basis-Nachrichten mit den kumulierten Tool-Austausche, um das vollständige Messages-Array zu rekonstruieren. Aktualisieren Sie non_tool_messages_json nicht innerhalb der Schleife.
Teil 2: Analysieren Sie die Tool-Call-Response
Verketten Sie eine LLM-Anrufe-Operation (HTTP v2 POST zum OpenAI-Chat-Completions-Endpoint mit InAndOut als Request-Body). Für Verbindungs- und Authentifizierungseinrichtung siehe Rufen Sie eine REST-API mit dem HTTP-v2-Connector auf.
Bei Erfolg fügen Sie einen Script-Schritt hinzu, um die Response zu lesen und die Schleifenkontrollvariablen zu setzen:
// 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 Identifier, den die API jedem Tool-Aufruf zuweist. Er muss in der Tool-Ergebnis-Nachricht in Teil 4 genau wie erhalten zurückgegeben werden, oder die API lehnt den Request ab.
Hinweis
tool_calls fehlt in der Response, wenn das Modell Klartext 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 einen der folgenden Schritte durch:
- Deaktivieren Sie parallele Tool-Aufrufe in der LLM-Anfrage, damit das Modell höchstens einen Aufruf pro Antwort zurückgibt. Für die OpenAI- und Azure OpenAI-Chat-Completion-APIs setzen Sie
parallel_tool_callsim Anfragebody auffalse, der in Teil 1 erstellt wird. - Durchlaufen Sie das Array
tool_calls, senden Sie jeden Tool und fügen Sie vor dem nächsten LLM-Aufruf pro Eintrag einetool-Resultatmeldung hinzu. 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 entsprechendestool-Resultat für jedetool_call_idin der Assistentenmeldung, die einmal versendet wird.
Teil 3: Senden an den Tool-Vorgang
Verwenden Sie eine Case-Anweisung, um basierend auf function_name an den korrekten Tool-Vorgang zu senden. Folgen Sie dabei dem gleichen Muster wie unter LLM-Antworten mithilfe von Function Calling an Studio-Vorgänge weiterleiten. Jeder Zielvorgang 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 in jedem Zielvorgang, um einzelne Argumentwerte zu extrahieren.
Teil 4: Append-Tool-Resultat und Anfrage neu erstellen
Nachdem der Tool-Vorgang function_resp setzt, erstellen Sie das aktualisierte Messages-Array für den nächsten LLM-Aufruf. Dieser Schritt erfordert komplexe JSON-Manipulation: Analysieren Sie die kumulierten Meldungen, fügen Sie neue Einträge an und serialisieren Sie das Ergebnis neu. 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-Resultatmeldung im Array stehen. Die OpenAI-API erfordert, dass die tool_calls-Auswahl und das entsprechende tool-Resultat nebeneinander und in der gleichen Reihenfolge wie die Aufrufe erfolgt sind. Eine nicht übereinstimmende oder fehlende tool_call_id verursacht einen 400-Fehler.
Tipp
Wenn der Tool-Vorgang strukturierte Daten zurückgibt (z. B. ein JSON-Objekt), serialisieren Sie diese in eine Zeichenfolge, bevor Sie sie function_resp zuweisen. Das Inhaltsfeld content der tool-Rollenmeldung muss eine Zeichenfolge sein.
Teil 5: Loop steuern
Schließen Sie den LLM-Aufruf, den Dispatcher und die Anfrageneuerstellung in einen Jitterbit-Script-Controller mithilfe einer While-Schleife ein. Platzieren Sie diesen Controller am Anfang der Vorgangskette:
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)
);
Der Vorgang LLM Call verwendet InAndOut als Anfragebody und führt den Parser für Teil 2 bei Erfolg aus. Der Vorgang Tool Dispatcher führt die Teil 3-Case-Anweisung aus. Append Tool Result ist das Teil 4-JavaScript-Skript, hier als benannte Skriptkomponente mit RunScript referenziert.
Durch das Setzen eines maximalen Iterationslimits werden Endlosschleifen vermieden, wenn ein Tool konsistent einen Fehler zurückgibt und das Modell darauf reagiert, indem es denselben Tool erneut anfordert.
Tipp
Beginnen Sie mit einem Limit von 5 Iterationen. Die meisten Workflows werden in einer oder zwei Runden aufgelöst. Wenn Sie das Limit konsistent erreichen, deutet dies auf ein Problem mit dem Prompt-Design oder dem Tool-Resultat hin, nicht auf einen Bedarf für ein höheres Limit.
Alternative: Jitterbit-Script-Meldungserstellung
Wenn Sie JavaScript vermeiden möchten, kann die Meldungsansammlung in Teil 4 vollständig in Jitterbit Script mithilfe von Stringverkettung implementiert werden. Der HR Agent implementiert diesen Ansatz, wobei gpt.registeredTools als Projektvariable die serialisierten Tool-Schemas hält (entsprechend toolsJson in diesem Leitfaden), wobei call_llm_again die Schleife steuert.
Der Jitterbit-Script-Ansatz erstellt die Assistent- und Tool-Ergebnismeldungen, indem JSON-Strings direkt verkettet werden, anstatt JSON.parse und JSON.stringify zu verwenden. Das akkumulierte Array wird verwaltet, indem die Assistentenmeldung 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 Felds messages in InAndOut erfordert das Ersetzen des vorhandenen Array-Werts innerhalb des JSON-Strings, was fehleranfällig ist, wenn der Nachrichteninhalt Sonderzeichen enthält. Verwende den JavaScript-Ansatz in Teil 4, wenn möglich. Reserviere den Jitterbit-Script-Ansatz für Projekte, in denen JavaScript nicht verfügbar ist.
Integration überprüfen
-
Stelle die Controller-Operation bereit und führe sie aus, indem du eine Benutzermeldung verwendest, die genau einen Tool-Aufruf erfordert. Bestätige 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ätige in den Protokollen, dass der zweite LLM-Aufruf das erweiterte Messages-Array empfangen hat (protokolliere
InAndOutmitWriteToOperationLogvor dem Aufruf des LLM) und dass er eine einfache Textantwort ohnetool_callszurückgegeben hat. -
Sende eine Benutzermeldung, die zwei aufeinanderfolgende Tool-Aufrufe erfordert (z. B. einen Kontakt nachschlagen und dann ein Ticket für diesen Kontakt erstellen). Bestätige, dass
loop_count2 erreicht, und überprüfe anschließend die akkumulierten Meldungen.tools_messagesist ein serialisierter JSON-Array-String, daher protokolliere ihn nach Abschluss der Schleife, um seinen Inhalt zu sehen:WriteToOperationLog("tools_messages: " + $tools_messages);Bestätige in der protokollierten Zeichenfolge, dass vier Objekte vorhanden sind, die zwischen
"role":"assistant"und"role":"tool"wechseln (zwei von jedem): Jede Runde fügt die Assistentenmeldung, die das Tool ausgewählt hat, gefolgt von dessentool-Ergebnis ein. Dietool_call_idjedertool-Meldung sollte mit deridin der vorherigentool_calls-Angabe der Assistentenmeldung übereinstimmen. -
Sende eine Meldung, die keinen Tool-Aufruf erfordert (z. B. eine allgemeine Frage, die das Modell aus seinem eigenen Wissen beantworten kann). Bestätige, dass die Schleife nicht ausgeführt wird (der ursprüngliche LLM-Aufruf gibt keine
tool_callszurück,call_llm_againbleibtfalseundloop_countbleibt 0). -
Falls die API einen 400-Fehler zurückgibt, der auf eine ungültige
tool_call_idhinweist, protokolliere den Wert vontool_call_idund vergleiche 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. -
Falls die Schleife das Iterationslimit erreicht, protokolliere
InAndOutzu Beginn jeder Runde, um die akkumulierten Meldungen 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 der Benutzeranfrage entspricht.