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
Qwen models are called through /v1/chat/completions or /v1/messages. The platform passes the request body through: Qwen-specific parameters (enable_thinking, thinking_budget, top_k, enable_search and so on) are forwarded unchanged and the upstream model decides whether they take effect. This page is organised by scenario, following Alibaba Cloud Model Studio's official docs (deep thinking, web search, vision, structured output, function calling, context caching 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 |
|---|---|---|---|---|
qwen3.8-max | Qwen3.8 flagship, text + image / video understanding | 1,000,000 | 131,072 | chat, streaming, vision, tools, thinking, cache |
qwen3.7-max | Qwen3.7 flagship, text | 1,000,000 | 131,072 | chat, streaming, tools, thinking, cache |
qwen3.7-plus | Qwen3.7 balanced, text + image / video understanding | 1,000,000 | 131,072 | chat, streaming, vision, tools, thinking, cache |
qwen3-vl-plus | Qwen3-VL vision understanding | 262,144 | 32,768 | chat, streaming, vision, tools, thinking, cache |
Capability tags are whatever GET /v1/models returns. qwen3.7-max has no vision tag and cannot take images (it errors in testing, see Image and video input).
The platform never switches thinking on or off for you. It does not inject enable_thinking, thinking_budget, reasoning_effort or temperature by default. If you omit them the upstream default applies: the official docs say qwen3.8-max, qwen3.7-max and qwen3.7-plus think by default; the default for qwen3-vl-plus is not stated. Pass enable_thinking explicitly when you need deterministic behaviour.
Control Qwen thinking with enable_thinking, not thinking. In both the OpenAI and Anthropic formats use the top-level enable_thinking / thinking_budget (in extra_body for the Python SDK). A thinking field you send is forwarded unchanged (except adaptive, which is not forwarded) but is not converted into enable_thinking, thinking_budget or reasoning_effort; the upstream of qwen3.7-plus validates thinking.type (only enabled / disabled / auto), and the other models are unverified, so do not depend on it.
Scenario overview
| Scenario | Official docs cover it | Our status | Example |
|---|---|---|---|
Deep thinking (enable_thinking switch, reading the reasoning) | Yes | Supported | Thinking mode |
Thinking budget thinking_budget, effort reasoning_effort, preserve_thinking | Yes | Partly supported: per official docs, not tested | Notes in Thinking mode |
| Streaming | Yes | Partly supported: same pipeline, not tested on Qwen specifically | Streaming |
| Function calling (including parallel calls) | Yes | Supported | Tool calls |
Streamed tool-call arguments (tool_stream) | Yes | Partly supported: per official docs, not tested | Notes in Tool calls |
Structured output: json_object | Yes | Supported | JSON output |
Structured output: json_schema | Yes (some models) | Supported (tested on qwen3.7-max; qwen3-vl-plus is not on the official list) | JSON Schema |
Web search (enable_search) | Yes | Partly supported: basic search tested; sources, strategies and other options not tested; the official docs say Chat Completions does not return search sources | Web search |
| Image understanding (single image) | Yes | Partly supported: qwen3-vl-plus tested; qwen3.8-max and qwen3.7-plus per official docs (not tested); qwen3.7-max not supported | Image and video input |
| Multi-image, video understanding, OCR, grounding, document parsing | Yes | Partly supported: per official docs, not tested | Image and video input |
| Context caching: implicit | Yes | Supported (automatic, no parameter) | Context caching |
Context caching: explicit (cache_control) | Yes | Partly supported: depends on an update that is not released yet, currently has no effect in production | Context caching |
| Anthropic-format calls | Yes (official Anthropic compatibility) | Partly supported: same pipeline, not tested on Qwen specifically | Anthropic format |
tool_choice: "required" | Official docs say Qwen does not support it | Not supported | None |
| Named function in thinking mode | Official docs say not supported | Not supported; set enable_thinking: false first | See Tool calls |
Long-document Q&A by file id (qwen-long) | Yes (separate model) | Not integrated: the platform has no file upload endpoint and no such model | None |
| Role-play dedicated models | Yes (separate models) | Not integrated | None |
| Batch | Yes | Not supported: the platform offers no batch processing | None |
Image input on qwen3.7-max | No (text model) | Not supported: returns 400 in testing | See Image and video input |
Thinking mode
Evidence: tested (live test account, 2026-10-19), qwen3.8-max (on) and qwen3.7-plus (off).
When to use: turn thinking on for reasoning, code and maths that need several steps; turn it off for plain chat to save latency and tokens. enable_thinking is not an OpenAI standard field: put it in extra_body with the Python SDK, at the top level of the body for raw HTTP.
Request
from openai import OpenAI
client = OpenAI(base_url="https://api.modelsite.ai/v1", api_key="sk-ms-xxxxxxxx")
# Thinking on
resp = client.chat.completions.create(
model="qwen3.8-max",
messages=[{"role": "user", "content": "9.11 和 9.9 哪个大?一句话回答。"}],
max_tokens=1500,
extra_body={"enable_thinking": True},
)
msg = resp.choices[0].message
print(getattr(msg, "reasoning_content", None)) # the reasoning
print(msg.content) # the final answer
# Disable thinking
resp = client.chat.completions.create(
model="qwen3.7-plus",
messages=[{"role": "user", "content": "用一句话解释量子纠缠"}],
max_tokens=300,
extra_body={"enable_thinking": False},
)Response (thinking on, qwen3.8-max): the reasoning is in reasoning_content, the answer in content, thinking tokens in usage.completion_tokens_details.reasoning_tokens.
{
"id": "chatcmpl-xxxx",
"object": "chat.completion",
"created": 1760000000,
"model": "qwen3.8-max",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "9.9 更大。",
"refusal": null,
"reasoning_content": "We need answer user's simple Chinese question: \"9.11 和 9.9 哪个大?一句话回答。\" Need answer one sentence. Need be careful: numeric comparison 9.11 vs 9.9. 9.9 = 9.90, so 9.9 larger than 9.11. Need final one sentence in Chinese."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 78,
"completion_tokens": 90,
"total_tokens": 168,
"prompt_tokens_details": {
"cached_tokens": 0,
"text_tokens": 78
},
"completion_tokens_details": {
"reasoning_tokens": 81,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0,
"text_tokens": 90
}
}
}Response (thinking off, qwen3.7-plus): no reasoning_content, reasoning_tokens is 0.
{
"id": "chatcmpl-xxxx",
"object": "chat.completion",
"created": 1760000000,
"model": "qwen3.7-plus",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "量子纠缠是指两个或多个粒子形成一种特殊的关联状态,使得无论它们相距多远,对其中一个粒子的测量会瞬间决定另一个粒子的状态。",
"refusal": null
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 17,
"completion_tokens": 31,
"total_tokens": 48,
"prompt_tokens_details": {
"cached_tokens": 0,
"text_tokens": 17
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
}
}Notes
thinking_budget(per official docs, not tested): an integer, the maximum number of tokens the thinking part may use, after which the model answers directly; officially supported on Qwen3.8 / 3.7 / 3.6 / 3.5 / Qwen3-VL, default is the model's maximum chain-of-thought length; put it inextra_body.reasoning_effort(per official docs, not tested): officially listed only for the qwen3.8 family, valuesxhigh(default),medium,low, withnoneturning thinking off; it cannot be set together withthinking_budget.qwen3.7-max,qwen3.7-plusandqwen3-vl-plusare not listed for this parameter, do not depend on it.preserve_thinking(per official docs, not tested): boolean, defaultfalse; whentruethereasoning_contentof assistant messages in history is also used as input, the official docs require passing it back unchanged, and the history thinking counts as input tokens and is billed. The platform forwardsreasoning_contentin history to the upstream; your client must put the previous round's reasoning back into the history itself.- Sampling:
temperatureranges over [0, 2) and its default depends on the model and on thinking; the official advice is to set only one oftemperatureandtop_p;top_kofficially defaults to 20, is not an OpenAI field, put it inextra_body; the platform does not range-check, so out-of-range values go to the upstream unchanged. max_completion_tokensis the total output cap, covering thinking and the answer, and is recommended for thinking models;qwen3-vl-plusis not in its official support list, so usemax_tokens; when both are sent the platform forwards onlymax_completion_tokens.
Streaming
Evidence: per official docs (not tested); the streaming pipeline matches the real responses on the DeepSeek and GLM pages.
When to use: show output as it is generated; especially recommended for thinking models (thinking takes long and non-streaming calls can time out). Pass stream: true; reasoning arrives in delta.reasoning_content, the answer in delta.content.
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="qwen3.8-max",
messages=[{"role": "user", "content": "数到五,用逗号分隔。"}],
max_tokens=1000,
stream=True,
extra_body={"enable_thinking": 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: the SSE chunk structure is the same as for other models (see the streaming response on the DeepSeek page), with usage at the end.
Notes
- If
stream_optionsis not set the gateway addsinclude_usage. - Official advice: thinking takes long, so for long prompts stream the response or set the client timeout to 180 seconds or more.
Tool calls
Evidence: tested (live test account, 2026-10-19), qwen3.7-plus, first round only (the model returning tool calls); the second round that sends tool results back is per official docs (not tested).
When to use: let the model decide to call functions you define; with parallel_tool_calls: true it returns several independent calls at once. The model does not run functions: your code runs them and puts each result back as a role: "tool" message (with the matching tool_call_id) before the next request.
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": "查询北京和上海现在的天气。"}]
resp = client.chat.completions.create(
model="qwen3.7-plus", messages=messages, tools=tools,
parallel_tool_calls=True, max_tokens=500,
extra_body={"enable_thinking": False},
)
msg = resp.choices[0].message
messages.append(msg) # put the assistant message with tool_calls back into historyFirst response: two tool_calls at once (Beijing and Shanghai).
{
"id": "chatcmpl-xxxx",
"object": "chat.completion",
"created": 1760000000,
"model": "qwen3.7-plus",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "我来为您查询北京和上海的天气。\n\n",
"refusal": null,
"tool_calls": [
{
"id": "call_xxxx",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\": \"北京\"}"
}
},
{
"id": "call_xxxx",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\": \"上海\"}"
},
"index": 1
}
]
},
"finish_reason": "tool_calls"
}
],
"usage": {
"prompt_tokens": 300,
"completion_tokens": 60,
"total_tokens": 360,
"prompt_tokens_details": {
"cached_tokens": 0,
"text_tokens": 300
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
}
}Second round (per official docs, not tested): append one role: "tool" message per tool_calls entry with matching tool_call_id, then request again; the official docs advise removing tool_choice when summarising tool output, otherwise the API returns tool calls again.
for call in msg.tool_calls:
messages.append({"role": "tool", "tool_call_id": call.id, "content": "Sunny, 26°C"})
resp = client.chat.completions.create(
model="qwen3.7-plus", messages=messages, tools=tools, max_tokens=500,
extra_body={"enable_thinking": False},
)
print(resp.choices[0].message.content)Notes
tool_choice: officially defaultauto;nonedisables tools;requiredis documented as not supported for Qwen models; a named function is not supported in thinking mode, so setenable_thinking: falsefirst when you must force a tool.parallel_tool_callsofficially defaults tofalseand must betruefor parallel calls; use it only for independent tasks, dependent calls need a serial loop.tool_stream(per official docs, not tested): boolean, defaultfalse, only together withstream: true, streams tool arguments incrementally; the official docs list only some qwen3.8 / 3.7 tiers; put it inextra_body.nmust be 1 whentoolsis set.- Anthropic-format
tool_choice: {"type": "none"}becomestool_choice: "none";disable_parallel_tool_use: truebecomesparallel_tool_calls: false.
JSON output
Evidence: tested (live test account, 2026-10-19), qwen3.7-max, thinking off.
When to use: stable JSON, for example information extraction. Set response_format: {"type": "json_object"}; the prompt must explicitly contain the word JSON, otherwise the request errors (official).
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="qwen3.7-max",
messages=[
{"role": "system", "content": "提取姓名和年龄,以 JSON 输出,格式:{\"name\": \"...\", \"age\": 0}"},
{"role": "user", "content": "大家好,我叫张三,今年 20 岁。"},
],
response_format={"type": "json_object"},
extra_body={"enable_thinking": False},
)
print(json.loads(resp.choices[0].message.content))Response
{
"id": "chatcmpl-xxxx",
"object": "chat.completion",
"created": 1760000000,
"model": "qwen3.7-max",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "{\"name\": \"张三\", \"age\": 20}",
"refusal": null
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 54,
"completion_tokens": 13,
"total_tokens": 67,
"prompt_tokens_details": {
"cached_tokens": 0
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
}
}Notes
- Official advice: do not set
max_tokensfor structured output, it can cut the JSON; field names and types may vary between calls, so validate before using downstream. - In thinking mode
json_objectmay not return strict JSON; turning thinking off is advised.
JSON Schema
Evidence: tested (live test account, 2026-10-19), qwen3.7-max, thinking off.
When to use: automated parsing that needs precise control of fields and types. Use json_schema in response_format, preferably with strict: true and additionalProperties: false; the prompt does not need to contain the word JSON. Officially only some families (Qwen3.7-Plus, Qwen3.7-Max, Qwen3.8-Max and so on) are open, and qwen3-vl-plus is not on the list.
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="qwen3.7-max",
messages=[{"role": "user", "content": "大家好,我叫张三,今年 20 岁。"}],
response_format={
"type": "json_schema",
"json_schema": {
"name": "user_info",
"strict": True,
"schema": {
"type": "object",
"properties": {"name": {"type": "string"}, "age": {"type": "integer"}},
"required": ["name", "age"],
"additionalProperties": False,
},
},
},
extra_body={"enable_thinking": False},
)
print(resp.choices[0].message.content)Response (the keys came back in the order age, name, different from the json_object call above, which shows the output is driven by the schema)
{
"id": "chatcmpl-xxxx",
"object": "chat.completion",
"created": 1760000000,
"model": "qwen3.7-max",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "{\"age\": 20, \"name\": \"张三\"}",
"refusal": null
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 26,
"completion_tokens": 14,
"total_tokens": 40,
"prompt_tokens_details": {
"cached_tokens": 0
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
}
}Notes
- In strict mode keywords such as
multipleOf,uniqueItems,contains,patternPropertiesandpropertyNamesreturn 400 (official). - Image, video and audio input do not support
json_schema; they fall back tojson_objectand the schema is not enforced (official).
Web search
Evidence: tested (live test account, 2026-10-19), qwen3.7-max, only the most basic enable_search: true; the other options are per official docs (not tested).
When to use: questions that depend on live information (weather, news, quotes). enable_search is not an OpenAI field: put it in extra_body with the Python SDK; once on, the model decides whether a search is needed.
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="qwen3.7-max",
messages=[{"role": "user", "content": "今天杭州的天气怎么样?一句话。"}],
max_tokens=500,
extra_body={"enable_search": True, "enable_thinking": False},
)
print(resp.choices[0].message.content)Response: note that prompt_tokens is 4270 while the question itself is only a dozen tokens: the searched web content is injected into the prompt as input and billed as input tokens.
{
"id": "chatcmpl-xxxx",
"object": "chat.completion",
"created": 1760000000,
"model": "qwen3.7-max",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "今天杭州多云,气温23~31℃。",
"refusal": null
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 4270,
"completion_tokens": 12,
"total_tokens": 4282,
"prompt_tokens_details": {
"cached_tokens": 0
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
}
}Notes
- Searching adds a lot of input tokens; estimate the cost yourself.
- Other options per official docs (not tested):
search_options.forced_search(search every time),search_strategy(turbodefault /max/agent/agent_max, theagentkinds are charged extra per call),enable_search_extension(vertical data such as weather and stocks),freshness,assigned_site_listand so on. The platform forwards all of these fields unchanged; whether they take effect is up to the upstream. - The official docs say the OpenAI-compatible Chat Completions does not return search sources or citation marks (
enable_source/enable_citationwork only on the native DashScope interface). - Per the official docs the Qwen3.8 multimodal interface does not support the
agentstrategy; thinking models can also setenable_search.
Image and video input
Evidence: tested (live test account, 2026-10-19), qwen3-vl-plus (single image) and qwen3.7-max (confirmed unsupported); qwen3.8-max, qwen3.7-plus, multi-image, video, OCR and grounding are per official docs (not tested).
When to use: visual Q&A, description, OCR, chart analysis, screenshot to code, multi-image comparison, video understanding. Put images in the content array; image_url.url is a public URL or a Base64 data URL. Only models whose capability tags include vision can take images: qwen3.8-max, qwen3.7-plus, qwen3-vl-plus.
Single-image request (qwen3-vl-plus, a solid red 64x64 PNG)
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="qwen3-vl-plus",
messages=[{"role": "user", "content": [
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{b64}"}},
{"type": "text", "text": "这张图是什么颜色?一句话。"},
]}],
max_tokens=200,
)
print(resp.choices[0].message.content)Response: usage.prompt_tokens_details.image_tokens is the number of tokens the image takes. qwen3-vl-plus did not think in this request (officially off by default), so reasoning_content is an empty string.
{
"id": "chatcmpl-xxxx",
"object": "chat.completion",
"created": 1760000000,
"model": "qwen3-vl-plus",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "这张图是纯红色。",
"refusal": null,
"reasoning_content": ""
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 81,
"completion_tokens": 7,
"total_tokens": 88,
"prompt_tokens_details": {
"cached_tokens": 0,
"text_tokens": 15,
"image_tokens": 66
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0,
"text_tokens": 7
}
}
}Unsupported case: qwen3.7-max has no vision tag; sending an image returned 400 in testing:
{
"error": {
"code": "api_error",
"message": "The request could not be completed. (",
"type": "api_error"
}
}Other vision scenarios (per official docs, not tested)
- Multiple images: put several
image_urlblocks incontent.qwen3.8-maxandqwen3.7-plusofficially take up to 2048 images,qwen3-vl-plusup to 256; the token total of all images and text must stay below the model's maximum input. - Video file: use a
video_urlblock; for an image sequence treated as video use avideoblock (an array of image URLs).fpscontrols frame sampling, officially 0.1 to 10 with default 2.0; see the official docs for where the field goes. Official video-file duration limits: 2 seconds to 2 hours for Qwen3.8 / 3.7, 2 seconds to 1 hour forqwen3-vl-plus. The platform has not verified how video is passed or its size limits, so try a short sample first. - OCR, information extraction, problem solving, screenshot to code, grounding, document parsing: all are the same image input with a different prompt, no extra parameter; the official advice is to avoid a system message for general chat and put the instructions in the user message.
resp = client.chat.completions.create(
model="qwen3.8-max",
messages=[{"role": "user", "content": [
{"type": "video_url", "video_url": {"url": "https://example.com/demo.mp4"}},
{"type": "text", "text": "Summarise this video and give the time of the key events."},
]}],
max_tokens=1000,
extra_body={"enable_thinking": False},
)Notes
- Image limits (official): width and height above 10 pixels, aspect ratio at most 200:1; up to 4K BMP, JPEG, PNG, TIFF, WEBP and HEIC, from 4K to 8K only JPEG and PNG; at most 20 MB per image.
- The platform and the upstream gateway have their own request-body size limits; try large images and long videos on a small scale first.
qwen3-vl-plusofficially has thinking off by default,qwen3.8-maxandqwen3.7-plushave it on; passenable_thinkingexplicitly for deterministic behaviour.
Context caching
Evidence: tested (live test account, 2026-10-19), qwen3.7-max: implicit cache hits were tested; explicit caching depends on an update that is not released yet and showed no effect in production.
When to use: the same long document or long system prompt asked about repeatedly, or multi-round chat.
Implicit caching (automatic): cannot be turned off, no request parameter, hits are not guaranteed; officially the minimum is about 1024 tokens and a hit is usually billed at about 20% of the input price (varies by model); put repeated content at the start of the prompt and changing content at the end. Hits are in usage.prompt_tokens_details.cached_tokens.
Request: the same system prompt of about 3,300 tokens, followed by different questions.
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)..."
for q in ["退货期限是几天?一句话", "退款几个工作日到账?一句话"]:
resp = client.chat.completions.create(
model="qwen3.7-max",
messages=[
{"role": "system", "content": "你是客服助手,根据下面的制度回答。\n" + KNOWLEDGE},
{"role": "user", "content": q},
],
max_tokens=60,
extra_body={"enable_thinking": False},
)
print(resp.choices[0].message.content, resp.usage.prompt_tokens_details.cached_tokens)Response (only usage shown): 2304 of the 3316 input tokens hit the cache.
{
"usage": {
"prompt_tokens": 3316,
"completion_tokens": 8,
"total_tokens": 3324,
"prompt_tokens_details": {
"cached_tokens": 2304
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
}
}The request in this test put a cache_control marker on the system message's content block, yet usage has no cache_creation_input_tokens: the hit came from the implicit cache, which means the marker did not trigger explicit caching.
Explicit caching (cache_control: {"type": "ephemeral"}, depends on an update not released yet): the official rules are to put the marker on a content block of messages, only ephemeral, 5-minute lifetime, at most 4 markers per request, cached block at least 1024 tokens, markers only inside content; creating a cache is billed at 125% of the input price and a hit usually at 10%; usage appears in cache_creation_input_tokens and cached_tokens. Production currently strips these markers from the request, so explicit caching has no effect; they will be forwarded once the update ships. Explicit and implicit caching are mutually exclusive: one request can use only one of them.
Anthropic format
Evidence: per official docs (not tested); the same pipeline was tested on DeepSeek and MiniMax, not on Qwen specifically.
When to use: the client only speaks /v1/messages. 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="qwen3.8-max",
max_tokens=1500,
messages=[{"role": "user", "content": "用一句话解释量子纠缠"}],
extra_body={"enable_thinking": True},
)
for block in resp.content:
if block.type == "thinking":
print("thinking:", block.thinking)
elif block.type == "text":
print("answer:", block.text)Notes
- Control thinking with the top-level
enable_thinking/thinking_budget, not Anthropic'sthinkingfield (see the notice at the top). - In the Anthropic format
top_kcan use the standard top-level field;stop_sequencesmaps tostop;metadata.user_idmaps touser.
Parameter quick reference
| Parameter | Notes |
|---|---|
enable_thinking, thinking_budget, preserve_thinking | Qwen-specific, put in extra_body, forwarded unchanged |
reasoning_effort | Officially listed only for the qwen3.8 family; cannot be set together with thinking_budget |
thinking | Forwarded unchanged, not converted; adaptive is not forwarded; the qwen3.7-plus upstream accepts only enabled / disabled / auto |
top_k, repetition_penalty, seed | Not OpenAI fields, put in extra_body; top_k officially defaults to 20 |
max_completion_tokens / max_tokens | The former includes thinking; qwen3-vl-plus uses max_tokens; when both are sent only max_completion_tokens is forwarded |
tool_choice | auto / none / named function (non-thinking); required is not supported |
parallel_tool_calls, tool_stream | Officially default false, put tool_stream in extra_body |
n | 1 to 4, must be 1 when tools is set |
response_format | text / json_object / json_schema (some models) |
enable_search, search_options | Web search, put in extra_body |
vl_high_resolution_images, fps | Vision related; see the official docs for the field shape, whether the upstream honours them is unverified |
cache_control | Explicit-cache marker, currently stripped in production, see Context caching |
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, and the converted fields may not take effect on Qwen, so use enable_thinking to switch thinking; reasoning.exclude: true or include_reasoning: false removes the reasoning from the response, thinking tokens are still billed.
Official docs