🎁 Nuevo Regístrate gratis, 10 llamadas de regalo. Hasta 1 $, sin tarjeta.
Tool calls de GLM 5.2: lo que oculta la compatibilidad con OpenAI

Tool calls de GLM 5.2: lo que oculta la compatibilidad con OpenAI

Contenido
  1. Un mismo turno, tres formas de resolverlo
  2. El texto llega junto con la llamada a herramientas
  3. Razona en voz alta
  4. Cuánto cuesta un turno con llamadas a herramientas en GLM 5.2
  5. Cuándo elegir GLM 5.2 y cómo usarlo bien
  6. Aviso
  7. Fuentes

Conecta un bucle de agente basado en el formato de OpenAI a GLM 5.2 y casi todo funcionará sin cambios: envías tools, recibes tool_calls, las ejecutas y devuelves los resultados. Pero después ocurre algo que nunca aparece en los ejemplos de los SDK. El asistente devuelve una línea de texto en el mismo turno que las llamadas a herramientas:

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

  • Un turno en caliente con llamadas a herramientas costó $0.0009 en GLM 5.2, frente a $0.0042 en gpt-5.5 y $0.0051 en claude-opus-4-8 (medición del 2026-06-30).
  • La latencia mediana de un turno en caliente de GLM 5.2 fue de 6.6s, frente a 1.9s en gpt-5.5 y 3.1s en opus-4-8: el turno barato también es el lento.
  • GLM 5.2 devuelve texto visible en el mismo turno que tool_calls con finish_reason: "tool_calls"; en el contrato de OpenAI, content es null en ese caso.
  • Cada turno en caliente de GLM 5.2 incluyó unos 27 tokens de razonamiento; gpt-5.5 y claude-opus-4-8 incluyeron 0 en la misma tarea.

Hay dos convenciones principales y conviene tener presentes ambas. En la de OpenAI, envías esquemas de funciones, recibes tool_calls y respondes a cada llamada con un mensaje tool asociado mediante 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"})

La de Anthropic tiene otra estructura: las herramientas incluyen un input_schema, el modelo emite bloques tool_use y la respuesta se envía en un bloque 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"}]})

GLM 5.2 habla el dialecto de OpenAI.

Según el contrato de OpenAI, message.content es null cuando finish_reason vale tool_calls. Muchos bucles de agentes dependen de ese comportamiento: bifurcan la lógica entre «contenido o llamadas a herramientas», registran content como respuesta final o comprueban que esté vacío. GLM devuelve las dos cosas a la vez, y esa es la primera suposición que deja de cumplirse.

El comportamiento descrito aquí se registró a partir de solicitudes reales con llamadas a herramientas dirigidas a glm-5.2, usando gpt-5.5 y claude-opus-4-8 como referencias en la misma tarea. En resumen: GLM 5.2 expone la interfaz de la API de OpenAI, pero en un par de aspectos se comporta más como Claude que como GPT. Los bucles diseñados para OpenAI son los que fallan.

Un mismo turno, tres formas de resolverlo

Mismo prompt, mismas dos herramientas, tres modelos:

GLM (glm-5.2)OpenAI (gpt-5.5)Anthropic (claude-opus-4-8)
Interfaz de APIchat-completions de OpenAIchat-completions de OpenAImessages de Anthropic
Texto en el turno de llamada a herramientaspreámbulo en content (no null)content es nullun bloque text antes de tool_use
Razonamiento en ese turnoexpuesto: reasoning_content + reasoning_tokensoculto; solo reasoning_tokens en usagesolo como bloque thinking, si se habilita
Llamadas a herramientas en paralelosí, con indexsí, varios bloques tool_use
Señal de finalizaciónfinish_reason: "tool_calls"finish_reason: "tool_calls"stop_reason: "tool_use"
Prefijo del ID de llamadacall_…call_…toolu_…

Hay dos filas que pueden romper un bucle: el texto incluido en el turno de llamada a herramientas y el razonamiento que aparece en ese mismo turno. El resto funciona como cabría esperar.

El texto llega junto con la llamada a herramientas

GLM 5.2 suele emitir un breve preámbulo del asistente en content junto con tool_calls, con finish_reason: "tool_calls". No es un error ni ocurre de forma esporádica.

Este es el mismo turno en los tres modelos, reducido a la parte que cambia:

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

OpenAI deja content en null, GLM lo rellena y Anthropic siempre ha colocado ahí un bloque text. GLM combina el formato de OpenAI con la costumbre de Anthropic de explicar lo que va a hacer antes de actuar. Por eso, un bucle escrito para OpenAI puede encontrarse con un caso inesperado. La corrección es pequeña, pero debe ser intencionada: deja de asumir que un turno con llamadas a herramientas no contiene texto.

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

Si el bucle muestra content al usuario como respuesta del asistente, ahora verá una frase como «déjame comprobarlo» antes de cada llamada a herramientas. Decide si quieres conservarla. La decisión debe tomarla tu aplicación, no depender de que el modelo guarde silencio.

Razona en voz alta

GLM 5.2 es un modelo de razonamiento, también cuando usa herramientas. Los turnos con llamadas a herramientas incluyen razonamiento, y GLM 5.2 lo expone como texto. En una respuesta sin streaming, el desglose de tokens lo deja claro:

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

Casi la mitad del completion fue razonamiento, aunque la salida visible de la solicitud solo contenía dos llamadas breves a funciones. En este aspecto, los tres modelos se comportan de forma distinta. GLM 5.2 devuelve el razonamiento en reasoning_content y añade el recuento de tokens. OpenAI factura los reasoning_tokens indicados en usage, pero nunca muestra el texto. Anthropic solo lo expone mediante bloques thinking, y únicamente cuando se activa el razonamiento extendido. De forma predeterminada, GLM 5.2 es el más transparente de los tres.

Esto tiene dos consecuencias. La primera es el coste: esos tokens de razonamiento se pagan también en los turnos con llamadas a herramientas, y un bucle de agente acumula muchos turnos. El parámetro que determina esa cifra es reasoning effort, como explicamos en GLM 5.2: reasoning effort es el parámetro que controla el coste. Cuenta los tokens de razonamiento en todos los turnos, no solo en la respuesta final.

La segunda es el orden durante el streaming. GLM envía primero el razonamiento, después el texto del preámbulo y por último las llamadas a herramientas:

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

Un parser creado para chat completions estándar de OpenAI no reconoce el campo reasoning_content e ignorará silenciosamente esa primera ráfaga. Normalmente no supone un problema. Sí lo es si la interfaz activa el estado «pensando…» al recibir el primer delta de contenido: lo primero que llega es el razonamiento, no el contenido, y el indicador nunca cambia de estado.

Cuánto cuesta un turno con llamadas a herramientas en GLM 5.2

El comportamiento solo explica una parte; la otra es la factura, sobre todo porque un bucle de agente repite el mismo tipo de turno muchas veces. Usamos un prefijo fijo —un system prompt de unos 2,000 tokens más las definiciones de las herramientas— y cambiamos el mensaje del usuario en cada llamada. Estos son los resultados de diez turnos en caliente:

por turno en caliente con llamadas a herramientasGLM glm-5.2OpenAI gpt-5.5Anthropic claude-opus-4-8
Coste$0.0009$0.0042$0.0051
Latencia (mediana)6.6s1.9s3.1s
Prompt en caché≈96%≈81%≈97%
Tokens de razonamiento≈2700
Coste en frío → en caliente3.4×2.8×4.9×

GLM 5.2 es la opción barata: cada turno en caliente cuesta aproximadamente 4.5× menos que GPT-5.5 y 5.4× menos que Opus. También es la lenta, con una latencia entre dos y tres veces y media mayor. El motivo es que consume tokens de razonamiento en todos los turnos, mientras que los otros dos modelos no consumieron ninguno en esta tarea. Ese es el intercambio: GLM reduce el coste a cambio de más latencia, y reasoning effort permite ajustar el equilibrio.

La caché es lo que hace viables estos modelos dentro de un bucle. El system prompt y las definiciones de las herramientas representan la mayor parte de cada prompt y no cambian entre turnos. Cuando el prefijo entra en caché, cada turno cuesta entre 2.8× y 4.9× menos. Hay dos factores que determinan si se aprovecha. GLM y OpenAI almacenan el prefijo en caché automáticamente; Anthropic solo almacena los fragmentos marcados con cache_control. Además, la caché de GLM tarda algo más en calentarse. Una tarea de tres pasos puede pagar el precio completo, mientras que una de treinta pasos aprovecha la caché. Explicamos el mecanismo en Caché de LLM de pesos abiertos.

Cuándo elegir GLM 5.2 y cómo usarlo bien

Al juntar todas las piezas, el perfil queda claro. GLM 5.2 es el modelo barato de la tabla, pero también el lento, y razona en todos los turnos. Ese perfil define los casos en los que aporta más valor.

Encaja en bucles de agentes largos y con muchos pasos, donde el coste pesa más y se pueden aceptar unos segundos por turno. Por ejemplo, agentes de programación en segundo plano, automatizaciones de CI y batch, y tareas que se ejecutan sin supervisión. El razonamiento que aumenta su latencia también le permite rendir bien en tareas reales de programación y planificación, no solo en routing trivial. Después del calentamiento, la caché refuerza esa ventaja: una tarea de treinta pasos amortiza el prefijo y mantiene un coste bajo; una de tres pasos puede pagar el precio completo y asumir la latencia sin obtener ningún beneficio. Usa GLM 5.2 para tareas largas y reserva un modelo más rápido para llamadas interactivas de un solo turno, donde una espera de seis segundos sí se nota.

Cinco prácticas permiten preparar un bucle para GLM 5.2 sin abandonar la interfaz de la API de OpenAI:

  • Asume que un turno con llamadas a herramientas puede incluir content. No compruebes que esté vacío.
  • Espera recibir reasoning_content en la respuesta y reasoning_tokens en usage; presupuesta ambos y usa el ajuste de reasoning effort para intercambiar calidad por coste.
  • Durante el streaming, no vincules el estado de la interfaz al primer delta de contenido, porque el razonamiento llega antes.
  • Reenvía tool_call_id sin modificarlo; trátalo como un valor opaco y no intentes analizarlo ni regenerarlo.
  • Acumula los arguments del streaming por index hasta que se cierre la llamada; no presupongas un número concreto de fragmentos.

Hay dos aspectos contra los que no hace falta protegerse: GLM emite llamadas paralelas a herramientas con un index, como los demás, y completa el ciclo de forma normal. Añade el turno del asistente, después un mensaje tool por cada llamada con su resultado, y el modelo finalizará con finish_reason: "stop". Mantén también el prefijo cacheable idéntico byte a byte entre turnos. El system prompt y las definiciones de las herramientas representan la mayor parte de cada prompt, y un prefijo estable permite que la caché de GLM reduzca el coste una vez que se ha calentado.

Nada de esto es especialmente complejo. Es la diferencia entre «la solicitud funciona» y «el bucle del agente es correcto». Con GLM, esa diferencia se reduce casi por completo a dos suposiciones incorrectas: que un turno con llamadas a herramientas no devuelve texto y que no incluye razonamiento. Elimina esas dos suposiciones, mantén estable el prefijo y un mismo bucle podrá usar GLM, GPT y Claude. GLM lo hará por una fracción del coste siempre que la latencia no sea el objetivo principal.

Aviso

Las cifras anteriores de coste, latencia y caché se midieron el 2026-06-30 usando diez turnos en caliente con llamadas a herramientas por modelo, con glm-5.2, gpt-5.5 y claude-opus-4-8. El coste procede del uso declarado; la latencia es la mediana de tiempo de reloj y varía según la carga y el nivel de reasoning effort. El comportamiento y los precios de los modelos cambian, así que toma estas cifras como referencia y repite las mediciones con tu propio tráfico antes de basarte en ellas.

Fuentes

← Volver al blog