ModelSiteAPI

GLM Models

Scenario-based examples for glm-5.3 / glm-5.3-flash: deep thinking, streaming, tool calls, JSON output, context caching, image input

GLM models are called through /v1/chat/completions or /v1/messages. The platform passes the request body through: vendor-specific parameters are forwarded unchanged and the upstream model decides whether they take effect. This page is organised by scenario, following Zhipu's official capability docs (deep thinking, streaming, function calling, structured output, context caching, vision, web search and so on). What is supported is decided by the upstream we actually connect to, not by the official site.

Every scenario carries an evidence label:

  • Tested (live test account, 2026-10-19): called for real on production; responses come from real output (id and timestamps replaced with placeholders).
  • Per official docs (not tested): checked against the official documentation only, no real request.

Supported models

Model idDescriptionContext windowMax outputCapability tags
glm-5.3GLM-5.3 flagship, text only, thinking always on1,000,000131,072chat, streaming, tools, thinking, cache
glm-5.3-flashGLM-5.3-Flash, faster and cheaper, thinking always on1,000,000131,072chat, streaming, tools, thinking, cache
  • Capability tags are whatever GET /v1/models returns. Neither model has the vision tag; see Image input.
  • The official docs describe glm-5.3 as text only.

The platform never switches thinking on or off for you. It does not inject thinking, reasoning_effort or temperature by default; whatever you send is forwarded. The GLM-5.3 family forces thinking and it cannot be turned off (see below).

Scenario overview

ScenarioOfficial docs cover itOur statusExample
Deep thinking (effort, reading the reasoning)YesSupported (thinking always on, cannot be disabled)Deep thinking
StreamingYesSupportedStreaming
Function calling (tool calls)YesSupported; tool_choice only supports autoTool calls
Streamed tool-call arguments (tool_stream)YesPartly supported: per official docs, not testedNotes in Tool calls
Structured output (JSON mode)YesSupported (json_object)JSON output
Context cachingYesSupported (implicit, automatic, no parameter)Context caching
Vision (images)Officially glm-5.3-flash is multimodal, glm-5.3 is text onlyPartly supported: glm-5.3-flash read an image in testing, but the platform does not list it as a vision model and makes no promise; glm-5.3 not supportedImage input
Preserved thinking (clear_thinking: false)YesPartly supported: per official docs, not testedPreserved thinking
Anthropic-format callsThe vendor has an Anthropic-compatible endpointPartly supported: same pipeline, not tested on GLM specificallyAnthropic format
Web search (web_search tool)YesNot supported: in testing tools accepts only the function type, a web_search tool returns 400None
Disabling thinking (thinking: disabled)Not supported officially (GLM-5.3 forces thinking)Not supported: the platform returns 400 directlySee Deep thinking
Role play (dedicated models such as CharGLM)Yes (separate models)Not integrated: the platform has not connected such modelsNone
Video and file inputOfficially glm-5.3-flash supports themNot integrated: no vision capability tag, unverifiedNone

Deep thinking

Evidence: tested (live test account, 2026-10-19), glm-5.3.

When to use: complex analysis, multi-step reasoning, design work. The GLM-5.3 family forces thinking, so you do not need to send thinking; use reasoning_effort to set the depth, which accepts only low, high and max (official default max). The reasoning is in reasoning_content, the final answer in content.

Request

from openai import OpenAI

client = OpenAI(base_url="https://api.modelsite.ai/v1", api_key="sk-ms-xxxxxxxx")

resp = client.chat.completions.create(
    model="glm-5.3",
    messages=[{"role": "user", "content": "9.11 和 9.9 哪个大?一句话回答。"}],
    max_tokens=1500,
    reasoning_effort="low",
)
msg = resp.choices[0].message
print(getattr(msg, "reasoning_content", None))  # the reasoning
print(msg.content)                              # the final answer

Response

{
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "9.9 大,因为 0.9 > 0.11。",
        "refusal": null,
        "reasoning_content": "Simple: 9.11 vs 9.9. 9.9 is larger."
      },
      "finish_reason": "stop"
    }
  ],
  "created": 1760000000,
  "id": "chatcmpl-xxxx",
  "model": "glm-5.3",
  "object": "chat.completion",
  "request_id": "req-xxxx",
  "usage": {
    "completion_tokens": 37,
    "completion_tokens_details": {
      "reasoning_tokens": 20,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0
    },
    "prompt_tokens": 28,
    "prompt_tokens_details": {
      "cached_tokens": 0
    },
    "reasoning_tokens": 20,
    "total_tokens": 65
  }
}

Disabling thinking is rejected: neither glm-5.3 nor glm-5.3-flash can turn thinking off. A request with "thinking": {"type": "disabled"} gets a 400 from the platform directly and is not sent upstream:

{
  "error": {
    "code": "invalid_request_error",
    "message": "This model does not support disabling thinking: thinking.type \"disabled\" is not allowed.",
    "type": "invalid_request_error"
  }
}

If code migrated from another model sends thinking: {"type": "disabled"}, remove it before switching to GLM-5.3, or use reasoning_effort: "low" to reduce thinking.

Notes

  • reasoning_effort accepts only low, high and max; other values are documented to error; the platform does not map them.
  • max_tokens ranges from 1 to 131072, officially at least 1024 is recommended, and thinking tokens count toward the output: a value that is too small leaves only reasoning and no answer. The official parameter table lists only max_tokens, so use it rather than max_completion_tokens.
  • Sampling: temperature ranges over [0, 1] (not OpenAI's 0 to 2), default 1.0; top_p ranges over [0.01, 1.0], default 0.95; the official advice is to tune only one of them. The platform does not range-check, so out-of-range values go to the upstream unchanged. With do_sample: false temperature and top_p are ignored (put it in extra_body).
  • stop takes at most 4 strings.
  • reasoning_content can also come back empty: in the glm-5.3-flash tool-call test usage.completion_tokens_details.reasoning_tokens was 0 and the response had no reasoning. Do not assume reasoning is present every time.

Streaming

Evidence: tested (live test account, 2026-10-19), glm-5.3-flash.

When to use: show output as it is generated. Pass stream: true; reasoning arrives in delta.reasoning_content, the answer in delta.content; finish_reason and usage appear only in the last chunks, and some chunks have no choices, so check before reading.

Request

from openai import OpenAI

client = OpenAI(base_url="https://api.modelsite.ai/v1", api_key="sk-ms-xxxxxxxx")

stream = client.chat.completions.create(
    model="glm-5.3-flash",
    messages=[{"role": "user", "content": "数到五,用逗号分隔。"}],
    max_tokens=600,
    reasoning_effort="low",
    stream=True,
)
reasoning, content = "", ""
for chunk in stream:
    if not chunk.choices:
        continue
    d = chunk.choices[0].delta
    if getattr(d, "reasoning_content", None):
        reasoning += d.reasoning_content
    elif d.content:
        content += d.content
print(content)

Response

data: {"id":"chatcmpl-xxxx","object":"chat.completion.chunk","created":1760000000,"model":"glm-5.3-flash","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning_content":""}}]}

data: {"id":"chatcmpl-xxxx","object":"chat.completion.chunk","created":1760000000,"model":"glm-5.3-flash","choices":[{"index":0,"delta":{"content":"一"}}]}

data: {"id":"chatcmpl-xxxx","object":"chat.completion.chunk","created":1760000000,"model":"glm-5.3-flash","choices":[{"index":0,"delta":{"content":"、二、三"}}]}

data: {"id":"chatcmpl-xxxx","object":"chat.completion.chunk","created":1760000000,"model":"glm-5.3-flash","choices":[{"index":0,"delta":{"content":"、四、五"}}]}

data: {"id":"chatcmpl-xxxx","object":"chat.completion.chunk","created":1760000000,"model":"glm-5.3-flash","choices":[{"delta":{},"finish_reason":"stop","index":0}]}

data: {"id":"chatcmpl-xxxx","object":"chat.completion.chunk","created":1760000000,"model":"glm-5.3-flash","choices":[],"usage":{"prompt_tokens":21,"completion_tokens":11,"total_tokens":32,"prompt_tokens_details":{"cached_tokens":0,"created_cache_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"system_fingerprint":"fp_xxxx"}

data: [DONE]

Notes

  • If stream_options is not set the gateway adds include_usage, and usage appears in the last chunk, which has empty choices.

Tool calls

Evidence: tested (live test account, 2026-10-19), glm-5.3-flash; glm-5.3 uses the same pipeline and was not tested separately.

When to use: let the model decide to call functions you define. The model does not run functions: it returns tool_calls, your code runs them and puts each result back as a role: "tool" message (with the matching tool_call_id), and you call the model once more for the final answer.

First request

from openai import OpenAI

client = OpenAI(base_url="https://api.modelsite.ai/v1", api_key="sk-ms-xxxxxxxx")

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Get weather of a location, the user should supply a location first.",
        "parameters": {
            "type": "object",
            "properties": {"location": {"type": "string", "description": "The city and state, e.g. San Francisco, CA"}},
            "required": ["location"],
        },
    },
}]
messages = [{"role": "user", "content": "How is the weather in Hangzhou?"}]
resp = client.chat.completions.create(
    model="glm-5.3-flash", messages=messages, tools=tools,
    tool_choice="auto", max_tokens=800, reasoning_effort="low",
)
msg = resp.choices[0].message
messages.append(msg)  # put the assistant message with tool_calls back into history

First response: finish_reason is tool_calls; function.arguments is a JSON string that you must parse yourself.

{
  "id": "chatcmpl-xxxx",
  "object": "chat.completion",
  "created": 1760000000,
  "model": "glm-5.3-flash",
  "choices": [
    {
      "finish_reason": "tool_calls",
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "refusal": null,
        "tool_calls": [
          {
            "id": "chatcmpl-tool-xxxx",
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"location\": \"Hangzhou, China\"}"
            }
          }
        ]
      }
    }
  ],
  "usage": {
    "prompt_tokens": 186,
    "completion_tokens": 15,
    "total_tokens": 201,
    "prompt_tokens_details": {
      "cached_tokens": 0,
      "created_cache_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 0,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0
    }
  },
  "system_fingerprint": "fp_xxxx"
}

Second round: run the function, put the result into the history and request again.

for call in msg.tool_calls:
    result = "24℃, cloudy"  # the real result of your function
    messages.append({"role": "tool", "tool_call_id": call.id, "content": result})

resp = client.chat.completions.create(
    model="glm-5.3-flash", messages=messages, tools=tools,
    max_tokens=800, reasoning_effort="low",
)
print(resp.choices[0].message.content)

Second response

{
  "id": "chatcmpl-xxxx",
  "object": "chat.completion",
  "created": 1760000000,
  "model": "glm-5.3-flash",
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "The weather in Hangzhou is currently 24°C and cloudy.",
        "refusal": null
      }
    }
  ],
  "usage": {
    "prompt_tokens": 208,
    "completion_tokens": 15,
    "total_tokens": 223,
    "prompt_tokens_details": {
      "cached_tokens": 0,
      "created_cache_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 0,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0
    }
  },
  "system_fingerprint": "fp_xxxx"
}

Notes

  • tool_choice accepts only auto (official: default and only auto). The platform does not block other values and we have not verified whether the upstream errors; in the Anthropic format any (converted to required) and tool (converted to a named function) may not be accepted upstream, so use auto only.
  • tools takes up to 128 functions; function names may contain only a-zA-Z0-9_- and be at most 64 characters.
  • tool_stream (streamed tool-call arguments): per official docs, not tested. Boolean, default false; together with stream: true the function-call arguments are streamed in pieces and you concatenate delta.tool_calls[*].function.arguments by index; not an OpenAI field, put it in extra_body. The official docs say GLM-5.3 enables it by default; whether glm-5.3-flash is in that scope is unverified.
  • Anthropic-format tool_choice: {"type": "none"} becomes tool_choice: "none", and disable_parallel_tool_use: true becomes parallel_tool_calls: false.

JSON output

Evidence: tested (live test account, 2026-10-19), glm-5.3-flash.

When to use: information extraction and any result that must be machine-parseable. Set response_format: {"type": "json_object"} and describe the expected JSON structure in the prompt; officially only text and json_object are supported, there is no json_schema.

Request

import json
from openai import OpenAI

client = OpenAI(base_url="https://api.modelsite.ai/v1", api_key="sk-ms-xxxxxxxx")

resp = client.chat.completions.create(
    model="glm-5.3-flash",
    messages=[
        {"role": "system", "content": "提取姓名和年龄,以 JSON 输出,格式:{\"name\": \"...\", \"age\": 0}"},
        {"role": "user", "content": "大家好,我叫张三,今年 20 岁。"},
    ],
    response_format={"type": "json_object"},
    max_tokens=600,
    reasoning_effort="low",
)
print(json.loads(resp.choices[0].message.content))

Response

{
  "id": "chatcmpl-xxxx",
  "object": "chat.completion",
  "created": 1760000000,
  "model": "glm-5.3-flash",
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "{\"name\": \"张三\", \"age\": 20}",
        "refusal": null,
        "reasoning_content": "Extract."
      }
    }
  ],
  "usage": {
    "prompt_tokens": 48,
    "completion_tokens": 17,
    "total_tokens": 65,
    "prompt_tokens_details": {
      "cached_tokens": 0,
      "created_cache_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 2,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0
    }
  },
  "system_fingerprint": "fp_xxxx"
}

Notes

  • The format definition belongs in the prompt and the model generates according to it; the official docs still recommend validating the result a second time (schema validation plus business checks) and having a fallback.
  • Leave room for thinking in max_tokens, otherwise the JSON may be incomplete.

Context caching

Evidence: tested (live test account, 2026-10-19), glm-5.3-flash.

When to use: the same long system prompt (knowledge base, policy document) asked about repeatedly, or multi-round chat. Caching is implicit: repeated prefixes are recognised automatically, with no request parameter. The official advice is that the repeated part be 500 tokens or more, with stable content first and the changing question in the user message; the cache takes effect asynchronously, so a short wait after the first request makes a hit more likely.

Request: two requests use the same long system prompt and differ only in the user question.

from openai import OpenAI

client = OpenAI(base_url="https://api.modelsite.ai/v1", api_key="sk-ms-xxxxxxxx")

KNOWLEDGE = "...a very long policy document (a few thousand tokens)..."
system = "你是客服助手,根据下面的制度回答。\n" + KNOWLEDGE

for q in ["退货期限是几天?一句话", "退款几个工作日到账?一句话"]:
    resp = client.chat.completions.create(
        model="glm-5.3-flash",
        messages=[{"role": "system", "content": system}, {"role": "user", "content": q}],
        max_tokens=300,
        reasoning_effort="low",
    )
    print(resp.choices[0].message.content, resp.usage.prompt_tokens_details.cached_tokens)

Response: the test used a system prompt of about 3,400 tokens. The first request had cached_tokens 0; the second one right after it (only the user question changed) hit 1152 tokens:

{
  "usage": {
    "prompt_tokens": 3413,
    "completion_tokens": 15,
    "total_tokens": 3428,
    "prompt_tokens_details": {
      "cached_tokens": 1152,
      "created_cache_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 0,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0
    }
  }
}

(Only usage is shown; the other fields match the plain chat response above.)

Notes

  • A hit is not guaranteed: how much hits depends on the upstream; the part that does not hit is billed at the normal input price.
  • A cache_control marker on content blocks has no effect on GLM; the platform strips it, so do not use it.

Image input

Evidence: tested (live test account, 2026-10-19), glm-5.3-flash only.

Neither model has the vision capability tag, so the platform has not opened GLM as a vision model and this can only be "partly supported":

  • glm-5.3-flash: officially a multimodal model. Tested with a solid red 64x64 PNG; the model answered the colour correctly and the response contains usage.prompt_tokens_details.multimodal_tokens. This is upstream behaviour, not a platform commitment, and billing has not been checked separately, so do not use it in production.
  • glm-5.3: officially text only, do not send images.

Request

import base64
from openai import OpenAI

client = OpenAI(base_url="https://api.modelsite.ai/v1", api_key="sk-ms-xxxxxxxx")

b64 = base64.b64encode(open("red.png", "rb").read()).decode()
resp = client.chat.completions.create(
    model="glm-5.3-flash",
    messages=[{"role": "user", "content": [
        {"type": "text", "text": "这张图是什么颜色?一句话。"},
        {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{b64}"}},
    ]}],
    max_tokens=600,
    reasoning_effort="low",
)
print(resp.choices[0].message.content)

Response

{
  "id": "chatcmpl-xxxx",
  "object": "chat.completion",
  "created": 1760000000,
  "model": "glm-5.3-flash",
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "这张图是红色的。",
        "refusal": null
      }
    }
  ],
  "usage": {
    "prompt_tokens": 37,
    "completion_tokens": 7,
    "total_tokens": 44,
    "prompt_tokens_details": {
      "cached_tokens": 0,
      "created_cache_tokens": 0,
      "multimodal_tokens": {
        "image": 16
      }
    },
    "completion_tokens_details": {
      "reasoning_tokens": 0,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0
    }
  },
  "system_fingerprint": "fp_xxxx"
}

Preserved thinking

Evidence: per official docs (not tested).

When to use: multi-round agent tasks where the model should reuse its earlier thinking. clear_thinking inside the thinking object is a boolean; the official default is true (discard the reasoning_content of earlier rounds); with false it is kept, and the history's reasoning_content must then be passed back unchanged and in the original order. The official advice for GLM-5.3-Flash is false.

Request

resp = client.chat.completions.create(
    model="glm-5.3-flash",
    messages=messages,   # assistant messages in history carry the reasoning_content returned earlier, unchanged
    max_tokens=1500,
    reasoning_effort="high",
    extra_body={"thinking": {"type": "enabled", "clear_thinking": False}},
)

Notes

  • Your client must put the reasoning_content returned by the previous round back into the history in full, unmodified and in order; the platform forwards the reasoning_content of assistant messages in history to the upstream.
  • This scenario was not tested; whether it takes effect is up to the upstream.
  • thinking.type can only be enabled on the GLM-5.3 family.

Anthropic format

Evidence: per official docs (not tested); the same pipeline was tested on DeepSeek and MiniMax, not on GLM specifically.

When to use: the client only speaks /v1/messages (Anthropic SDK, Claude Code, and so on). See the Messages page for usage and authentication (the SDK needs auth_token, not api_key).

Request

from anthropic import Anthropic

client = Anthropic(base_url="https://api.modelsite.ai", auth_token="sk-ms-xxxxxxxx")

resp = client.messages.create(
    model="glm-5.3-flash",
    max_tokens=1500,
    messages=[{"role": "user", "content": "用一句话解释量子纠缠"}],
    extra_body={"reasoning_effort": "low"},
)
for block in resp.content:
    if block.type == "thinking":
        print("thinking:", block.thinking)
    elif block.type == "text":
        print("answer:", block.text)

Notes

  • GLM-5.3 forces thinking, so do not send thinking: {"type": "disabled"}; to reduce thinking add the top-level reasoning_effort (low / high / max) to the body, which the platform forwards unchanged.
  • The reasoning is expected to come back as a thinking content block (expected behaviour, not tested on GLM).

Parameter quick reference

ParameterNotes
thinkingOnly enabled; disabled returns 400; adaptive is not forwarded; clear_thinking is forwarded unchanged as a sub-field
reasoning_effortAccepts only low / high / max
max_tokens1 to 131072; max_completion_tokens is forwarded unchanged (not renamed), whether GLM recognises it is unverified, so use max_tokens
temperature, top_p, do_sampleSee Deep thinking
stopAt most 4 strings
tools, tool_choiceUp to 128 functions; tool_choice supports auto only
tool_streamPer official docs, not tested, put it in extra_body
response_formattext / json_object; no json_schema
request_id, user_idZhipu identifier fields, not OpenAI standard, put them in extra_body and they are forwarded unchanged
stream_optionsNot in the official parameter table; the platform adds include_usage to streaming requests that omit it; whether the upstream recognises it is unverified
top_k, n, service_tier, store, metadata, etc.Not listed officially; forwarded unchanged, whether the upstream recognises them is unverified
Unknown top-level fields, keys in extra_bodyForwarded flat, unchanged
developer roleConverted to system

Also: the reasoning object (OpenRouter style) is handled by the platform itself; enabled: true adds reasoning_effort: "medium" and effort: "none" becomes thinking: disabled, both of which GLM-5.3 rejects, so use reasoning_effort directly; reasoning.exclude: true or include_reasoning: false removes the reasoning from the response, thinking tokens are still billed.

Official docs

On this page