Implementieren Sie eine LLM-Tool-Calling-Schleife in Jitterbit Studio
Einführung
Die einmalige Funktionsaufrufverarbeitung (behandelt in LLM-Antworten an Studio-Operationen mit Funktionsaufrufen weiterleiten) behandelt eine Tool-Auswahl pro Anfrage: Das Modell wählt eine Funktion aus, eine Studio-Operation führt sie aus, und die Interaktion endet. Viele agentische Workflows erfordern mehr als einen Tool-Aufruf, um eine einzige Benutzeranfrage zu beantworten: Das Modell muss möglicherweise einen CRM-Datensatz abfragen, dann Kontodetails abrufen und schließlich eine Zusammenfassung unter Verwendung beider Ergebnisse erstellen.
Eine Tool-Calling-Schleife behandelt dies, indem sie jedes Tool-Ergebnis als tool-Rollen-Nachricht an das LLM zurückgibt und das Modell erneut mit dem erweiterten Gespräch aufruft. Die Schleife wiederholt sich, bis das Modell eine Antwort im Klartext ohne Tool-Aufrufe produziert oder ein maximales Iterationslimit erreicht ist.
Dieser Leitfaden baut auf:
- LLM-Antworten an Studio-Operationen mit Funktionsaufrufen weiterleiten für die Definition des Tool-Schemas und das einmalige Dispatch-Muster. Lesen Sie diesen Leitfaden zuerst.
- Erstellen Sie einen Multi-Turn-LLM-Chat mit Gesprächshistorie, wenn Sie die Tool-Calling-Schleife mit einer persistenten Gesprächsspeicherung über Benutzerwechsel hinweg kombinieren.
Entwurfsmuster
Die Schleife fügt dem einmaligen Funktionsaufrufmuster zwei Schritte hinzu: das Anhängen des Tool-Ergebnisses an das Nachrichten-Array und das erneute Aufrufen des LLM. Die Schleife wiederholt sich, solange die Modellantwort 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 tragen den Status über Iterationen hinweg:
| Variable | Zweck |
|---|---|
InAndOut |
Der aktuelle LLM-Anforderungstext (vor jedem Aufruf aktualisiert). |
non_tool_messages_json |
Die Basisnachrichten (Systemaufforderung und Benutzernachricht) als JSON-Array-String. Bleibt über alle Iterationen hinweg konstant. |
tools_messages |
Die angesammelten Tool-Austauschnachrichten aus allen vorherigen Runden als JSON-Array-String. Wächst mit jeder Iteration. |
tools_resp |
Die aktuellste LLM-Antwort, die eine tool_calls-Auswahl enthielt. Wird verwendet, um die Assistenten-Nachricht zur Ansammlung zu extrahieren. |
call_llm_again |
Wird auf true gesetzt, wenn ein Tool-Aufruf in Bearbeitung ist; wird auf false gesetzt, wenn das Modell eine endgültige Antwort zurückgibt. |
Teil 1: Initialisieren der Schleifenvariablen
Vor dem ersten LLM-Aufruf die Basisnachrichten und den anfänglichen Anfragekörper erstellen und alle Schleifenstatusvariablen zurücksetzen. Fügen Sie einen Skriptschritt zu Beginn des Vorgangs 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 Format der Tool-Definition und wie man die Schemata erstellt, siehe Route LLM-Antworten zu Studio-Vorgängen mithilfe von Funktionsaufrufen.
Hinweis
Speichern Sie die Basisnachrichten in non_tool_messages_json, bevor die Schleife beginnt. Jede Iteration kombiniert diese Basisnachrichten mit den angesammelten Tool-Austauschen, um das vollständige Nachrichtenarray wiederherzustellen. Aktualisieren Sie non_tool_messages_json nicht innerhalb der Schleife.
Teil 2: Analysieren der Tool-Aufrufantwort
Verketten Sie einen LLM-Aufruf-Vorgang (HTTP v2 POST an den OpenAI Chat Completions-Endpunkt, mit InAndOut als Anfragekörper). Für die Verbindung und Authentifizierungseinrichtung siehe Rufen Sie eine REST-API mithilfe des HTTP v2-Connectors auf.
Bei Erfolg fügen Sie einen Skriptschritt hinzu, um die Antwort zu lesen und die Schleifensteuerungsvariablen 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 eine eindeutige Kennung, die die API jedem Tool-Aufruf zuweist. Sie muss in der Tool-Ergebnisnachricht in Teil 4 genau so zurückgegeben werden, wie sie empfangen wurde, oder die API wird die Anfrage ablehnen.
Hinweis
tool_calls fehlt in der Antwort, wenn das Modell einfachen Text zurückgibt. Der GetJSONString-Aufruf gibt in diesem Fall "null" zurück, und die Längenprüfung > 2 unterscheidet korrekt ein gefülltes Array (das mindestens [...], Länge 3 oder mehr hat) von einem fehlenden oder leeren Wert.
Verarbeitung 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 einzigen Antwort zurückgeben (parallele Tool-Aufrufe), und alle Aufrufe nach dem ersten werden ignoriert. Um jeden Aufruf zu verarbeiten, tun Sie eines der Folgenden:
- 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 Completions APIs setzen Sie
parallel_tool_callsim Anfragekörper auffalse, wie in Teil 1 beschrieben. - Iterieren Sie über das
tool_calls-Array, indem Sie das Tool aufrufen und für jeden Eintrag ein Assistenten-/tool-Nachrichtenpaar anhängen, bevor der nächste LLM-Aufruf erfolgt. Die LLM-API erfordert ein passendestool-Ergebnis für jedetool_call_idin der Assistenten-Nachricht.
Teil 3: An das Tool-Operation dispatchen
Verwenden Sie eine Case Anweisung, um an die richtige Tool-Operation basierend auf function_name zu dispatchen, und folgen Sie dem gleichen Muster wie in LLM-Antworten an Studio-Operationen weiterleiten mit Funktionsaufruf. Jede Zieloperation führt die angeforderte Funktion aus und setzt function_resp auf den Ergebnisstring.
function_arguments enthält die Parameterauswahlen des Modells als JSON-String. Parsen Sie es mit JSONParser innerhalb jeder Zieloperation, um die einzelnen Argumentwerte zu extrahieren.
Teil 4: Das Tool-Ergebnis anhängen und die Anfrage neu aufbauen
Nachdem die Tool-Operation function_resp gesetzt hat, bauen Sie das aktualisierte Nachrichten-Array für den nächsten LLM-Aufruf auf. Dieser Schritt erfordert komplexe JSON-Manipulation: das Parsen der angesammelten Nachrichten, das Anhängen neuer Einträge und das erneute Serialisieren des Ergebnisses. Implementieren Sie es als JavaScript-Skript-Schritt:
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 Skript-Schritt zu verwenden, setzen Sie die Skriptsprache im Skripteditor auf JavaScript, bevor Sie Inhalte hinzufügen.
Hinweis
Die Assistenten-Nachricht (tool_resp.choices[0].message) muss unmittelbar vor der entsprechenden tool-Ergebnismeldung im Array erscheinen. Die OpenAI-API erfordert, dass die Auswahl der tool_calls und das entsprechende tool-Ergebnis benachbart und in der gleichen Reihenfolge wie die Aufrufe gemacht werden. Eine nicht übereinstimmende oder fehlende tool_call_id verursacht einen 400-Fehler.
Tipp
Wenn die Tool-Operation strukturierte Daten zurückgibt (zum Beispiel ein JSON-Objekt), serialisieren Sie es in einen String, bevor Sie es function_resp zuweisen. Das content-Feld der tool-Rollen-Nachricht muss ein String sein.
Teil 5: Die Schleife steuern
Wickeln Sie den LLM-Aufruf, den Dispatcher und die Schritte zum Wiederaufbau der Anfrage in einen Jitterbit-Skript-Controller mit einer While-Schleife ein. Platzieren Sie diesen Controller am Anfang der Operationenkette:
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 LLM Call-Operation verwendet InAndOut als Anfragekörper und führt den Teil 2 Antwortparser bei Erfolg aus. Die Tool Dispatcher-Operation führt die Teil 3 Case-Anweisung aus. Append Tool Result ist das Teil 4 JavaScript-Skript, das hier als benannte Skriptkomponente unter Verwendung von RunScript referenziert wird.
Das Festlegen einer maximalen Iterationsgrenze verhindert, dass Schleifen außer Kontrolle geraten, wenn ein Tool ständig einen Fehler zurückgibt und das Modell reagiert, indem es dasselbe Tool erneut anfordert.
Tipp
Beginnen Sie mit einer Grenze von 5 Iterationen. Die meisten Workflows lösen sich in ein oder zwei Runden; das ständige Erreichen der Grenze signalisiert ein Problem mit dem Prompt-Design oder dem Tool-Ergebnis und nicht die Notwendigkeit einer höheren Grenze.
Alternative: Jitterbit-Skript-Nachrichtenaufbau
Wenn Sie JavaScript vermeiden möchten, kann die Nachrichtenakkumulation im Teil 4 vollständig in Jitterbit-Skript unter Verwendung von String-Verkettung implementiert werden. Der HR Agent implementiert diesen Ansatz, indem er gpt.registeredTools als Projektvariable verwendet, um die serialisierten Tool-Schemas (entsprechend toolsJson in diesem Leitfaden) zu halten, wobei call_llm_again die Schleife steuert.
Der Jitterbit-Skript-Ansatz erstellt die Nachrichten des Assistenten und des Tool-Ergebnisses, indem er JSON-Strings direkt verkettet, anstatt JSON.parse und JSON.stringify zu verwenden. Das akkumulierte Array wird durch das Extrahieren der Assistenten-Nachricht aus tools_resp unter Verwendung von GetJSONString und das Anhängen des Tool-Ergebnisses als formatierten String aufrechterhalten:
// 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)
Die vollständige Ersetzung des messages-Felds in InAndOut erfordert die Ersetzung des vorhandenen Array-Werts innerhalb des JSON-Strings, was anfällig ist, wenn der Nachrichteninhalt Sonderzeichen enthält. Verwenden Sie den JavaScript-Ansatz in Teil 4, wenn möglich; reservieren Sie den Jitterbit-Skriptansatz für Projekte, in denen JavaScript nicht verfügbar ist.
Integration überprüfen
-
Bereitstellen und ausführen der Steuerungsoperation mit einer Benutzer-Nachricht, die genau einen Tool-Aufruf erfordert. Bestätigen Sie in den Betriebsprotokollen, 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 Nachrichten-Array erhalten hat (protokollieren Sie
InAndOutmitWriteToOperationLog, bevor Sie den LLM aufrufen) und dass er eine Antwort im Klartext ohnetool_callszurückgegeben hat. -
Senden Sie eine Benutzer-Nachricht, die zwei aufeinanderfolgende Tool-Aufrufe erfordert (zum Beispiel, einen Kontakt suchen und dann ein Ticket für diesen Kontakt erstellen). Bestätigen Sie, dass
loop_count2 erreicht, und überprüfen Sie dann die angesammelten Nachrichten.tools_messagesist ein serialisierter JSON-Array-String, protokollieren Sie ihn, nachdem die Schleife abgeschlossen ist, um seinen Inhalt zu sehen:WriteToOperationLog("tools_messages: " + $tools_messages);Bestätigen Sie im protokollierten String, dass es vier Objekte gibt, abwechselnd
"role":"assistant"und"role":"tool"(jeweils zwei): Jede Runde fügt die Assistenten-Nachricht hinzu, die das Tool ausgewählt hat, gefolgt von ihremtool-Ergebnis. Dietool_call_idjedertool-Nachricht sollte mit deridim vorhergehenden Eintrag dertool_calls-Nachricht des Assistenten übereinstimmen. -
Senden Sie eine Nachricht, die keinen Tool-Aufruf erfordert (zum Beispiel eine allgemeine Frage, die das Modell aus seinem eigenen Wissen beantworten kann). Bestätigen Sie, dass die Schleife nicht ausgeführt wird (der anfängliche LLM-Aufruf gibt keine
tool_callszurück,call_llm_againbleibtfalseundloop_countbleibt 0). -
Wenn die API einen 400-Fehler mit dem Hinweis auf eine ungültige
tool_call_idzurückgibt, protokolliere den Wert vontool_call_idund vergleiche ihn mit demid-Feld inchoices[0].message.tool_calls[0]aus der vorherigen LLM-Antwort. Eine Abweichung bedeutet typischerweise, dasstools_respaktualisiert wurde, bevor die ID extrahiert wurde. -
Wenn die Schleife die Iterationsgrenze erreicht, protokolliere
InAndOutzu Beginn jeder Runde, um die angesammelten Nachrichten zu überprüfen. Ein wiederholter Toolaufruf 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 Toolbeschreibung nicht mit der Anfrage des Benutzers übereinstimmt.