🎁 Neu Kostenlos registrieren, 10 Aufrufe gratis. Bis zu 1 $, ohne Karte.
GLM 5.2 Tool Calls in Agent Loops: Was „OpenAI-kompatibel“ verschweigt

GLM 5.2 Tool Calls in Agent Loops: Was „OpenAI-kompatibel“ verschweigt

Inhalt
  1. Derselbe Turn auf drei Arten
  2. Text und Tool Call kommen gemeinsam
  3. Es denkt laut
  4. Was ein Tool-Call-Turn mit GLM 5.2 kostet
  5. Wann GLM 5.2 passt und wie man es sinnvoll betreibt
  6. Hinweis
  7. Quellen

Richtet man einen bestehenden Agent Loop im OpenAI-Stil auf GLM 5.2, funktioniert fast alles direkt: Man sendet tools, erhält tool_calls, führt sie aus und schickt die Ergebnisse zurück. Dann passiert etwas, das in den SDK-Beispielen nie vorkommt. Der Assistant liefert im selben Turn wie die Tool Calls eine Textzeile zurück:

{
  "choices": [{
    "finish_reason": "tool_calls",
    "message": {
      "role": "assistant",
      "content": "I'll look up both pieces of information for you at the same time!",
      "tool_calls": [
        {"id": "call_…", "type": "function",
         "function": {"name": "get_weather", "arguments": "{\"city\":\"Paris\"}"}},
        {"id": "call_…", "type": "function",
         "function": {"name": "get_time", "arguments": "{\"city\":\"Tokyo\"}"}}
      ]
    }
  }]
}

TL;DR

  • Ein warmer Tool-Call-Turn kostete mit GLM 5.2 $0.0009, gegenüber $0.0042 mit gpt-5.5 und $0.0051 mit claude-opus-4-8 (gemessen am 2026-06-30).
  • Die mediane Latenz eines warmen Turns lag bei GLM 5.2 bei 6.6s, gegenüber 1.9s bei gpt-5.5 und 3.1s bei opus-4-8: Der günstige Turn ist zugleich der langsame.
  • GLM 5.2 liefert sichtbaren Text im selben Turn wie tool_calls und setzt dabei finish_reason: "tool_calls"; laut OpenAI-Contract ist content in diesem Fall null.
  • Jeder warme Turn mit GLM 5.2 enthielt etwa 27 Reasoning-Tokens; bei gpt-5.5 und claude-opus-4-8 waren es für dieselbe Aufgabe 0.

Zwei Konventionen haben sich durchgesetzt. Bei OpenAI sendet man Function-Schemas, erhält tool_calls zurück und antwortet für jeden Call mit einer tool-Message, die über tool_call_id zugeordnet wird:

resp = openai.chat.completions.create(model="…", tools=tools, tool_choice="auto", messages=messages)
# assistant.tool_calls → [{"id": "call_…", "function": {"name": "get_weather", "arguments": "{\"city\":\"Paris\"}"}}]
messages.append(resp.choices[0].message)
messages.append({"role": "tool", "tool_call_id": "call_…", "content": "18C, clear"})

Anthropic verwendet eine andere Struktur: Tools enthalten ein input_schema, das Modell erzeugt tool_use-Blöcke, und die Antwort erfolgt als tool_result-Block:

resp = anthropic.messages.create(model="…", tools=tools, messages=messages)
# resp.content → [{"type": "tool_use", "id": "toolu_…", "name": "get_weather", "input": {"city": "Paris"}}]
messages.append({"role": "assistant", "content": resp.content})
messages.append({"role": "user", "content": [
    {"type": "tool_result", "tool_use_id": "toolu_…", "content": "18C, clear"}]})

GLM 5.2 spricht den OpenAI-Dialekt.

Laut OpenAI-Contract ist message.content gleich null, wenn finish_reason den Wert tool_calls hat. Viele Agent Loops verlassen sich darauf: Sie unterscheiden zwischen „Content oder Tool Calls“, protokollieren content als finale Antwort oder prüfen explizit, ob das Feld leer ist. GLM liefert beides gleichzeitig. Damit bricht genau diese Annahme zuerst.

Das hier beschriebene Verhalten stammt aus echten Tool-Calling-Requests an glm-5.2. Als Referenz liefen gpt-5.5 und claude-opus-4-8 mit derselben Aufgabe. Kurz gesagt: GLM 5.2 nutzt die API-Oberfläche von OpenAI, verhält sich in einigen Punkten aber eher wie Claude als wie GPT. Dadurch stolpert ausgerechnet ein für OpenAI gebauter Loop.

Derselbe Turn auf drei Arten

Derselbe Prompt, dieselben zwei Tools, drei Modelle:

GLM (glm-5.2)OpenAI (gpt-5.5)Anthropic (claude-opus-4-8)
API-OberflächeOpenAI Chat CompletionsOpenAI Chat CompletionsAnthropic Messages
Text im Tool-Call-TurnPräambel in content (nicht null)content ist nullein text-Block vor tool_use
Reasoning in diesem Turnsichtbar: reasoning_content + reasoning_tokensverborgen; nur reasoning_tokens in usagenur als thinking-Block, sofern aktiviert
Parallele Tool Callsja, mit indexjaja, mehrere tool_use-Blöcke
Abschlusssignalfinish_reason: "tool_calls"finish_reason: "tool_calls"stop_reason: "tool_use"
Präfix der Tool-Call-IDcall_…call_…toolu_…

Zwei Zeilen sind für Agent Loops kritisch: Text im Tool-Call-Turn und sichtbares Reasoning in diesem Turn. Der Rest ist erfreulich unspektakulär.

Text und Tool Call kommen gemeinsam

GLM 5.2 liefert zusammen mit tool_calls regelmäßig eine kurze Präambel in content und setzt dabei finish_reason: "tool_calls". Das ist weder ein Fehler noch ein seltenes Verhalten.

Hier ist derselbe Turn für alle drei Modelle, gekürzt auf den relevanten Unterschied:

// OpenAI gpt-5.5: content is null on a tool-call turn
"message": { "content": null,
             "tool_calls": [ {/* get_weather */}, {/* get_time */} ] }

// GLM glm-5.2: content carries a preamble
"message": { "content": "I'll look up both pieces of information for you at the same time!",
             "tool_calls": [ {/* get_weather */}, {/* get_time */} ] }

// Anthropic claude-opus-4-8: a text block sits before the tool_use blocks
"content": [ { "type": "text", "text": "I'll get both pieces of information for you." },
             { "type": "tool_use", /* get_weather */ },
             { "type": "tool_use", /* get_time */ } ]

Bei OpenAI bleibt content null, GLM befüllt das Feld, und Anthropic stellt schon immer einen text-Block voran. GLM kombiniert also das Wire Format von OpenAI mit der Gewohnheit von Anthropic, vor einer Aktion kurz anzukündigen, was passiert. Ein gegen OpenAI entwickelter Loop wird davon überrascht. Die Korrektur ist klein, muss aber bewusst umgesetzt werden: Behandelt einen Tool-Call-Turn nicht länger als inhaltsleer.

resp = client.chat.completions.create(model="glm-5.2", messages=msgs, tools=tools)
msg = resp.choices[0].message

# GLM may return assistant text in the same turn as the tool calls.
if msg.content:
    log.debug("preamble: %s", msg.content)   # keep or drop, but don't assume it's empty

msgs.append(msg)
for call in msg.tool_calls:
    result = dispatch(call.function.name, json.loads(call.function.arguments))
    msgs.append({"role": "tool", "tool_call_id": call.id, "content": result})

Wenn der Loop content als Antwort des Assistant an den Nutzer ausgibt, erscheint nun vor jedem Tool Call eine Zeile wie „Ich prüfe das kurz“. Entscheidet bewusst, ob ihr sie anzeigen wollt. Diese Entscheidung sollte nicht implizit durch das sonst übliche Schweigen des Modells fallen.

Es denkt laut

GLM 5.2 ist ein Reasoning-Modell und pausiert sein Reasoning nicht bei der Tool-Nutzung. Auch ein Tool-Call-Turn enthält Reasoning, das GLM 5.2 als Text offenlegt. Bei einer nicht gestreamten Response zeigt die Token-Abrechnung das deutlich:

"usage": {
  "prompt_tokens": 224,
  "completion_tokens": 68,
  "completion_tokens_details": { "reasoning_tokens": 30 },
  "total_tokens": 292
}

Fast die Hälfte der Completion entfiel auf Reasoning, obwohl die sichtbare Ausgabe nur aus zwei kurzen Function Calls bestand. Hier unterscheiden sich alle drei Modelle. GLM 5.2 liefert das Reasoning als reasoning_content zusammen mit der Token-Anzahl. OpenAI berechnet die reasoning_tokens in usage, zeigt den Text aber nie an. Anthropic gibt ihn nur als thinking-Blöcke aus und auch nur dann, wenn Extended Thinking aktiviert ist. GLM 5.2 legt standardmäßig am meisten offen.

Das hat zwei Folgen. Erstens die Kosten: Reasoning-Tokens fallen auch in Tool-Call-Turns an, und ein Agent Loop besteht aus vielen Turns. Über den Reasoning Effort lässt sich dieser Wert steuern. Darum geht es ausführlich in GLM 5.2: Reasoning Effort als Kostenhebel. Zählt Reasoning-Tokens in jedem Turn, nicht nur in der finalen Antwort.

Zweitens die Reihenfolge beim Streaming. GLM sendet zuerst das Reasoning, danach die Präambel und anschließend die Tool Calls:

reasoning_content  (many deltas)
content            (a few deltas)
tool_calls         (id + name, then arguments)

Ein Parser für reguläre OpenAI Chat Completions kennt das Feld reasoning_content nicht und ignoriert diesen ersten Block stillschweigend. Meist ist das unproblematisch. Es wird zum Problem, wenn die UI einen „Denkt nach…“-Status anhand des ersten Content-Deltas steuert. Im Stream kommt zuerst das Reasoning und nicht der Content. Der Statuswechsel wird dadurch nie ausgelöst.

Was ein Tool-Call-Turn mit GLM 5.2 kostet

Das Verhalten ist nur die eine Hälfte; die andere ist die Rechnung. In einem Agent Loop wiederholt sich derselbe Turn viele Male. Gemessen über zehn warme Turns mit einem festen Präfix aus einem etwa 2,000 Token langen System Prompt und den Tool-Definitionen, wobei sich die User Message bei jedem Call änderte:

pro warmem Tool-Call-TurnGLM glm-5.2OpenAI gpt-5.5Anthropic claude-opus-4-8
Kosten$0.0009$0.0042$0.0051
Latenz (Median)6.6s1.9s3.1s
Prompt im Cache≈96%≈81%≈97%
Reasoning-Tokens≈2700
Kosten kalt → warm3.4×2.8×4.9×

GLM 5.2 ist die günstige Option: Pro warmem Turn ist es etwa 4.5× günstiger als GPT-5.5 und 5.4× günstiger als Opus. Gleichzeitig ist es das langsamste Modell und benötigt zwei- bis dreieinhalbmal so lange. Der Grund: GLM verbraucht in jedem Turn Reasoning-Tokens, während die anderen beiden Modelle bei dieser Aufgabe keine verwendet haben. Der Trade-off lautet Kosten gegen Latenz und lässt sich über den Reasoning Effort beeinflussen.

Erst Caching macht diese Modelle in einem Loop bezahlbar. Der System Prompt und die Tool-Definitionen machen den größten Teil jedes Prompts aus und bleiben zwischen den Turns unverändert. Sobald das Präfix im Cache liegt, sinken die Kosten pro Turn um den Faktor 2.8× bis 4.9×. Ob das tatsächlich passiert, hängt von zwei Dingen ab. GLM und OpenAI cachen das Präfix automatisch. Bei Anthropic wird nur gecacht, was explizit mit cache_control markiert ist. Außerdem braucht der Cache von GLM einen Turn länger, bis er greift. Eine Aufgabe mit drei Schritten kann daher vollständig zum vollen Preis laufen, während eine Aufgabe mit dreißig Schritten den Cache nutzt. Die Details stehen in Prompt Caching bei Open-Weight-LLMs.

Wann GLM 5.2 passt und wie man es sinnvoll betreibt

Aus diesen Eigenschaften ergibt sich ein klares Profil. GLM 5.2 ist in dieser Tabelle das günstigste und zugleich langsamste Modell. Außerdem führt es in jedem Turn Reasoning aus. Damit eignet es sich für bestimmte Workloads besonders gut.

GLM 5.2 passt zu langen Agent Loops mit vielen Schritten, bei denen die Kosten wichtiger sind als einige Sekunden Latenz pro Turn. Dazu gehören Coding Agents im Hintergrund, CI- und Batch-Automatisierung sowie unbeaufsichtigte Jobs. Das Reasoning verursacht zwar Latenz, sorgt aber zugleich dafür, dass das Modell bei echten Coding- und Planungsaufgaben bestehen kann und nicht nur triviales Routing beherrscht. Nach dem Warm-up verstärkt das Caching diesen Vorteil: Bei einer Aufgabe mit dreißig Schritten verteilen sich die Kosten des Präfixes und die weiteren Turns bleiben günstig. Eine Aufgabe mit drei Schritten kann dagegen den vollen Preis und die zusätzliche Latenz zahlen, ohne vom Cache zu profitieren. Nutzt GLM 5.2 deshalb für lange Jobs. Für interaktive Single-Shot-Calls, bei denen sechs Sekunden pro Turn deutlich auffallen, ist ein schnelleres Modell besser geeignet.

Fünf Gewohnheiten machen einen Loop fit für GLM 5.2, ohne die OpenAI API zu verlassen:

  • Rechnet bei einem Tool-Call-Turn mit content. Prüft nicht, dass das Feld leer ist.
  • Rechnet im Stream mit reasoning_content und in usage mit reasoning_tokens. Plant beides im Budget ein und nutzt den Reasoning-Effort-Regler, um Qualität gegen Kosten abzuwägen.
  • Steuert beim Streaming den UI-Status nicht über das erste Content-Delta, da zuerst das Reasoning eintrifft.
  • Übernehmt tool_call_id unverändert. Behandelt die ID als opaken Wert und versucht weder, sie zu parsen, noch sie neu zu erzeugen.
  • Sammelt gestreamte arguments anhand von index, bis der Call abgeschlossen ist. Verlasst euch nicht auf eine bestimmte Anzahl von Chunks.

Gegen zwei Dinge müsst ihr euch nicht absichern: GLM liefert parallele Tool Calls wie die anderen Modelle mit einem index, und der Roundtrip wird regulär abgeschlossen. Hängt den Assistant-Turn an, danach für jeden Call eine tool-Message mit dem Ergebnis. Das Modell beendet den Ablauf mit finish_reason: "stop". Haltet dabei das cachefähige Präfix über alle Turns hinweg bytegenau stabil. System Prompt und Tool-Definitionen bilden den größten Teil jedes Prompts. Nur mit einem stabilen Präfix kann der GLM-Cache nach dem Warm-up die Kosten senken.

Das alles ist nicht exotisch. Es ist der Unterschied zwischen „Der Request läuft durch“ und „Der Agent Loop ist korrekt“. Bei GLM geht es im Wesentlichen um zwei falsche Annahmen: Ein Tool-Call-Turn sei still und enthalte kein Reasoning. Entfernt diese beiden Annahmen und haltet das Präfix stabil. Dann funktioniert derselbe Loop mit GLM, GPT und Claude, wobei GLM nur einen Bruchteil kostet, solange nicht die Latenz optimiert werden muss.

Hinweis

Die oben genannten Kosten-, Latenz- und Cache-Werte wurden am 2026-06-30 anhand von zehn warmen Tool-Call-Turns pro Modell mit glm-5.2, gpt-5.5 und claude-opus-4-8 gemessen. Die Kosten stammen aus den gemeldeten Nutzungsdaten. Die Latenz ist der Median der Wall-Clock-Zeit und hängt von Auslastung und Reasoning Effort ab. Modellverhalten und Preise ändern sich. Die Werte sind daher nur als Orientierung gedacht. Messt sie mit eurem eigenen Traffic erneut, bevor ihr Entscheidungen darauf stützt.

Quellen

← Zurück zum Blog