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 (
idand timestamps replaced with placeholders). - Per official docs (not tested): checked against the official documentation only, no real request.
Supported models
| Model id | Description | Context window | Max output | Capability tags |
|---|---|---|---|---|
glm-5.3 | GLM-5.3 flagship, text only, thinking always on | 1,000,000 | 131,072 | chat, streaming, tools, thinking, cache |
glm-5.3-flash | GLM-5.3-Flash, faster and cheaper, thinking always on | 1,000,000 | 131,072 | chat, streaming, tools, thinking, cache |
- Capability tags are whatever
GET /v1/modelsreturns. Neither model has thevisiontag; see Image input. - The official docs describe
glm-5.3as 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
| Scenario | Official docs cover it | Our status | Example |
|---|---|---|---|
| Deep thinking (effort, reading the reasoning) | Yes | Supported (thinking always on, cannot be disabled) | Deep thinking |
| Streaming | Yes | Supported | Streaming |
| Function calling (tool calls) | Yes | Supported; tool_choice only supports auto | Tool calls |
Streamed tool-call arguments (tool_stream) | Yes | Partly supported: per official docs, not tested | Notes in Tool calls |
| Structured output (JSON mode) | Yes | Supported (json_object) | JSON output |
| Context caching | Yes | Supported (implicit, automatic, no parameter) | Context caching |
| Vision (images) | Officially glm-5.3-flash is multimodal, glm-5.3 is text only | Partly 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 supported | Image input |
Preserved thinking (clear_thinking: false) | Yes | Partly supported: per official docs, not tested | Preserved thinking |
| Anthropic-format calls | The vendor has an Anthropic-compatible endpoint | Partly supported: same pipeline, not tested on GLM specifically | Anthropic format |
Web search (web_search tool) | Yes | Not supported: in testing tools accepts only the function type, a web_search tool returns 400 | None |
Disabling thinking (thinking: disabled) | Not supported officially (GLM-5.3 forces thinking) | Not supported: the platform returns 400 directly | See Deep thinking |
| Role play (dedicated models such as CharGLM) | Yes (separate models) | Not integrated: the platform has not connected such models | None |
| Video and file input | Officially glm-5.3-flash supports them | Not integrated: no vision capability tag, unverified | None |
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 answerResponse
{
"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_effortaccepts onlylow,highandmax; other values are documented to error; the platform does not map them.max_tokensranges 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 onlymax_tokens, so use it rather thanmax_completion_tokens.- Sampling:
temperatureranges over [0, 1] (not OpenAI's 0 to 2), default 1.0;top_pranges 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. Withdo_sample: falsetemperatureandtop_pare ignored (put it inextra_body). stoptakes at most 4 strings.reasoning_contentcan also come back empty: in theglm-5.3-flashtool-call testusage.completion_tokens_details.reasoning_tokenswas 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_optionsis not set the gateway addsinclude_usage, andusageappears in the last chunk, which has emptychoices.
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 historyFirst 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_choiceaccepts onlyauto(official: default and onlyauto). The platform does not block other values and we have not verified whether the upstream errors; in the Anthropic formatany(converted torequired) andtool(converted to a named function) may not be accepted upstream, so useautoonly.toolstakes up to 128 functions; function names may contain onlya-zA-Z0-9_-and be at most 64 characters.tool_stream(streamed tool-call arguments): per official docs, not tested. Boolean, defaultfalse; together withstream: truethe function-call arguments are streamed in pieces and you concatenatedelta.tool_calls[*].function.argumentsbyindex; not an OpenAI field, put it inextra_body. The official docs say GLM-5.3 enables it by default; whetherglm-5.3-flashis in that scope is unverified.- Anthropic-format
tool_choice: {"type": "none"}becomestool_choice: "none", anddisable_parallel_tool_use: truebecomesparallel_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_controlmarker 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 containsusage.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_contentreturned by the previous round back into the history in full, unmodified and in order; the platform forwards thereasoning_contentof assistant messages in history to the upstream. - This scenario was not tested; whether it takes effect is up to the upstream.
thinking.typecan only beenabledon 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-levelreasoning_effort(low/high/max) to the body, which the platform forwards unchanged. - The reasoning is expected to come back as a
thinkingcontent block (expected behaviour, not tested on GLM).
Parameter quick reference
| Parameter | Notes |
|---|---|
thinking | Only enabled; disabled returns 400; adaptive is not forwarded; clear_thinking is forwarded unchanged as a sub-field |
reasoning_effort | Accepts only low / high / max |
max_tokens | 1 to 131072; max_completion_tokens is forwarded unchanged (not renamed), whether GLM recognises it is unverified, so use max_tokens |
temperature, top_p, do_sample | See Deep thinking |
stop | At most 4 strings |
tools, tool_choice | Up to 128 functions; tool_choice supports auto only |
tool_stream | Per official docs, not tested, put it in extra_body |
response_format | text / json_object; no json_schema |
request_id, user_id | Zhipu identifier fields, not OpenAI standard, put them in extra_body and they are forwarded unchanged |
stream_options | Not 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_body | Forwarded flat, unchanged |
developer role | Converted 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
DeepSeek Models
Scenario-based examples for deepseek-v4.1-flash / deepseek-v4-flash-0731 / deepseek-v4-pro: chat, thinking, tool calls, JSON output, prefix completion, caching, image input
Qwen Models
Scenario-based examples for qwen3.7-max / qwen3.7-plus / qwen3.8-max / qwen3-vl-plus: thinking, tool calls, JSON output, web search, image and video understanding, caching