🎁 Novo Cadastre-se grátis, 10 chamadas por nossa conta. Até US$ 1, sem cartão.
Tool calls do GLM 5.2: o que a compatibilidade com OpenAI esconde

Tool calls do GLM 5.2: o que a compatibilidade com OpenAI esconde

Conteúdo
  1. O mesmo turno de três formas
  2. O texto vem junto com a chamada de ferramenta
  3. Ele pensa em voz alta
  4. Quanto custa um turno com chamada de ferramenta no GLM 5.2
  5. Quando usar o GLM 5.2 e como operá-lo bem
  6. Aviso
  7. Fontes

Aponte um loop de agente existente, no estilo da OpenAI, para o GLM 5.2 e quase tudo simplesmente funciona: você envia tools, recebe tool_calls, executa as ferramentas e devolve os resultados. Então acontece algo que os exemplos dos SDKs nunca mostram. O assistente retorna uma linha de texto no mesmo turno das chamadas de ferramentas:

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

  • Um turno aquecido com chamada de ferramenta no GLM 5.2 custou $0.0009, contra $0.0042 no gpt-5.5 e $0.0051 no claude-opus-4-8 (medição de 2026-06-30).
  • A latência mediana dos turnos aquecidos do GLM 5.2 foi de 6.6s, contra 1.9s no gpt-5.5 e 3.1s no opus-4-8: o turno mais barato também é o mais lento.
  • O GLM 5.2 retorna texto visível no mesmo turno que tool_calls, com finish_reason: "tool_calls"; no contrato da OpenAI, content fica nulo nesse caso.
  • Cada turno aquecido do GLM 5.2 usou cerca de 27 tokens de raciocínio; gpt-5.5 e claude-opus-4-8 usaram 0 na mesma tarefa.

Duas convenções predominam, e é útil ter ambas em mente. Na OpenAI, você envia os schemas das funções, recebe tool_calls e responde com uma mensagem tool para cada chamada, associada por tool_call_id:

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

Na Anthropic, o formato é diferente: as ferramentas têm um input_schema, o modelo emite blocos tool_use e você responde com um bloco tool_result:

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

O GLM 5.2 fala o dialeto da OpenAI.

No contrato da OpenAI, message.content é null quando finish_reason é tool_calls. Muitos loops de agentes dependem disso: separam os caminhos entre “conteúdo ou chamadas de ferramentas”, registram content como resposta final ou verificam que o campo está vazio. O GLM entrega os dois de uma vez, e essa é a primeira suposição que deixa de valer.

Esse comportamento foi observado em requisições reais com chamadas de ferramentas para glm-5.2, usando gpt-5.5 e claude-opus-4-8 na mesma tarefa como referências. Em resumo: o GLM 5.2 usa a interface da API da OpenAI, mas, em alguns aspectos, se comporta mais como o Claude do que como o GPT. Um loop projetado para a OpenAI é justamente o que tropeça.

O mesmo turno de três formas

O mesmo prompt, as mesmas duas ferramentas e três modelos:

GLM (glm-5.2)OpenAI (gpt-5.5)Anthropic (claude-opus-4-8)
Interface da APIchat-completions da OpenAIchat-completions da OpenAImessages da Anthropic
Texto no turno da chamada de ferramentapreâmbulo em content (não nulo)content é nullum bloco text antes de tool_use
Raciocínio nesse turnoexposto: reasoning_content + reasoning_tokensoculto; apenas reasoning_tokens em usagesomente como bloco thinking, se habilitado
Chamadas de ferramentas em paralelosim, com indexsimsim, vários blocos tool_use
Sinal de conclusãofinish_reason: "tool_calls"finish_reason: "tool_calls"stop_reason: "tool_use"
Prefixo do ID da chamadacall_…call_…toolu_…

Duas linhas são as que quebram os loops: texto no turno da chamada de ferramenta e raciocínio exposto nesse turno. O restante funciona como esperado.

O texto vem junto com a chamada de ferramenta

O GLM 5.2 normalmente emite um preâmbulo curto em content junto com tool_calls, usando finish_reason: "tool_calls". Não é um erro nem um comportamento ocasional.

Este é o mesmo turno nos três modelos, reduzido à parte que muda:

// 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 */ } ]

A OpenAI deixa content como nulo; o GLM preenche o campo; a Anthropic sempre colocou um bloco text nessa posição. Portanto, o GLM combina o formato de transporte da OpenAI com o hábito da Anthropic de narrar antes de agir. Um loop escrito para a OpenAI acaba pego de surpresa. A correção é pequena, mas precisa ser intencional. Pare de tratar um turno com chamada de ferramenta como se ele não tivesse conteúdo:

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})

Se o seu loop exibe content ao usuário como resposta do assistente, agora ele mostrará uma linha como “vou verificar” antes de cada chamada de ferramenta. Decida se isso faz sentido para o seu produto. Essa decisão deve ser sua, não uma consequência do silêncio do modelo.

Ele pensa em voz alta

O GLM 5.2 é um modelo de raciocínio, e esse raciocínio não é interrompido durante o uso de ferramentas. O turno com a chamada também contém raciocínio, e o GLM 5.2 o expõe como texto. Em uma resposta sem streaming, a contagem de tokens deixa isso explícito:

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

Quase metade da completion foi raciocínio, embora a saída visível da requisição sejam apenas duas chamadas curtas de função. É nesse ponto que os três modelos divergem. O GLM 5.2 entrega o raciocínio em reasoning_content, além da contagem de tokens. A OpenAI cobra pelos reasoning_tokens registrados em usage, mas nunca mostra o texto. A Anthropic só o exibe em blocos thinking, e apenas quando o extended thinking está habilitado. Por padrão, o GLM 5.2 é o mais transparente dos três.

Isso tem duas consequências. A primeira é custo: você paga pelos tokens de raciocínio nos turnos com chamadas de ferramentas, e um loop de agente tem muitos turnos. O reasoning effort é o controle que altera esse valor, como explicamos em GLM 5.2: o reasoning effort é a alavanca de custo. Conte os tokens de raciocínio em todos os turnos, não apenas na resposta final.

A segunda é a ordem no streaming. Quando a requisição usa streaming, o GLM envia primeiro o raciocínio, depois o texto do preâmbulo e, por fim, as chamadas de ferramentas:

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

Um parser feito para chat completions convencionais da OpenAI não conhece o campo reasoning_content e ignora silenciosamente esse bloco inicial. Em geral, isso não causa problemas. Mas causa quando a UI exibe um estado “pensando…” a partir do primeiro delta de conteúdo: a primeira coisa que chega pela conexão é o raciocínio, não o conteúdo, e o indicador nunca muda de estado.

Quanto custa um turno com chamada de ferramenta no GLM 5.2

O comportamento é só metade da história; a outra metade é a conta, principalmente porque um loop de agente repete esse turno muitas vezes. Com um prefixo fixo — um system prompt de aproximadamente 2.000 tokens mais as definições das ferramentas — e uma mensagem do usuário diferente em cada chamada, estes foram os resultados de dez turnos aquecidos:

por turno aquecido com chamada de ferramentaGLM glm-5.2OpenAI gpt-5.5Anthropic claude-opus-4-8
Custo$0.0009$0.0042$0.0051
Latência (mediana)6.6s1.9s3.1s
Prompt em cache≈96%≈81%≈97%
Tokens de raciocínio≈2700
Custo a frio → aquecido3.4×2.8×4.9×

O GLM 5.2 é o mais barato: por turno aquecido, custa aproximadamente 4.5× menos que o GPT-5.5 e 5.4× menos que o Opus. Também é o mais lento, com latência de duas a três vezes e meia maior, porque usa tokens de raciocínio em todos os turnos, enquanto os outros dois não usaram nenhum nessa tarefa. Essa é a troca: o GLM reduz o custo em troca de latência, e o reasoning effort controla esse equilíbrio.

O cache é o que torna qualquer um desses modelos viável financeiramente em um loop. O system prompt e as definições das ferramentas representam a maior parte de cada prompt e são idênticos entre os turnos. Depois que o prefixo entra no cache, o turno fica entre 2.8× e 4.9× mais barato. Dois fatores determinam se você terá esse ganho. O GLM e a OpenAI armazenam o prefixo em cache automaticamente; na Anthropic, apenas o conteúdo marcado com cache_control é armazenado. Além disso, o cache do GLM leva um pouco mais de tempo para aquecer. Uma tarefa de três etapas pode pagar o preço integral, enquanto uma de trinta etapas roda com cache. Os detalhes estão em Cache de LLMs open-weight.

Quando usar o GLM 5.2 e como operá-lo bem

Juntando tudo, o GLM 5.2 é o modelo mais barato da tabela, também é o mais lento e raciocina em todos os turnos. Esse perfil deixa claro onde ele faz sentido.

Onde ele se encaixa: loops de agentes longos e com várias etapas, nos quais o custo é a prioridade e alguns segundos por turno são aceitáveis. Agentes de programação em segundo plano, CI, automações em lote e tarefas executadas sem supervisão. O raciocínio que o torna lento também explica por que ele funciona bem em programação e planejamento reais, em vez de apenas fazer roteamento simples. Depois do aquecimento, o cache reforça essa vantagem: uma tarefa de trinta etapas amortiza o prefixo e fica barata, enquanto uma de três etapas pode pagar o preço integral e ainda sofrer a latência sem benefício. Use o GLM 5.2 em tarefas longas e mantenha um modelo mais rápido para chamadas interativas e pontuais, nas quais seis segundos por turno fazem diferença.

Como operar bem o GLM 5.2. Cinco práticas deixam um loop preparado para o GLM sem sair da interface da API da OpenAI:

  • Considere que um turno com chamada de ferramenta pode trazer content. Não verifique que ele está vazio.
  • Espere reasoning_content na conexão e reasoning_tokens em usage; inclua ambos no orçamento e use o controle de reasoning effort para equilibrar qualidade e custo.
  • No streaming, não vincule o estado da UI ao primeiro delta de conteúdo, porque o raciocínio chega antes.
  • Devolva tool_call_id sem nenhuma alteração; trate-o como opaco, sem tentar interpretá-lo ou gerá-lo novamente.
  • Acumule os arguments do streaming por index até a chamada terminar; não presuma uma quantidade fixa de chunks.

Você não precisa se proteger contra dois pontos: o GLM emite chamadas de ferramentas em paralelo com um index, como os demais, e o ciclo fecha normalmente. Adicione o turno do assistente, depois uma mensagem tool por chamada com o respectivo resultado, e o modelo concluirá com finish_reason: "stop". Mantenha também o prefixo armazenável em cache idêntico byte a byte entre os turnos. O system prompt e as definições das ferramentas representam a maior parte de cada prompt, e um prefixo estável permite que o cache do GLM reduza o custo depois de aquecido.

Nada disso é exótico. É a diferença entre “a requisição funcionou” e “o loop do agente está correto”. No GLM, essa diferença se resume principalmente a duas suposições: que um turno com chamada de ferramenta não produz texto e que o modelo não raciocina nesse turno. Elimine essas duas suposições, mantenha o prefixo estável e o mesmo loop funcionará com GLM, GPT e Claude. Onde latência não for a prioridade, o GLM fará isso por uma fração do custo.

Aviso

Os números de custo, latência e cache acima foram medidos em 2026-06-30, com dez turnos aquecidos de chamadas de ferramentas por modelo, usando glm-5.2, gpt-5.5 e claude-opus-4-8. O custo foi calculado a partir do uso informado; a latência é a mediana do tempo total e varia conforme a carga e o reasoning effort. O comportamento e os preços dos modelos mudam, portanto trate esses valores como indicativos e faça novas medições com o seu próprio tráfego antes de depender deles.

Fontes

← Voltar ao blog