Skip to content

Thinking

Reasoning before the answer, on by default, off with chat_template_kwargs.enable_thinking.

A thinking model reasons before answering and returns the reasoning beside the answer.

Thinking on and off

Thinking is on by default. "chat_template_kwargs": {"enable_thinking": false} turns thinking off.

PropertyThinking onThinking off
chat_template_kwargs.enable_thinkingtrue (default)false
message.reasoningReasoning textnull
Streamed reasoningdelta.reasoningNone
usage.completion_tokensAnswer plus reasoningAnswer
usage.completion_tokens_details.reasoning_tokensReasoning tokens0
First output tokenReasoningAnswer

chat_template_kwargs is not an OpenAI parameter. The Python SDK sends the field through extra_body; curl and fetch send the field at the top level of the body.

Example

The example asks the same question twice: first with thinking on (the default), then with thinking off.

curl

QUESTION='[{"role": "user", "content": "Is 91 prime? Answer yes or no."}]'

# Thinking on (the default)
curl https://api.albastov.com/v1/chat/completions \
  -H "Authorization: Bearer $ALBASTAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "qwen3.8-27b", "max_tokens": 400,
       "messages": '"$QUESTION"'}'

# Thinking off
curl https://api.albastov.com/v1/chat/completions \
  -H "Authorization: Bearer $ALBASTAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "qwen3.8-27b", "max_tokens": 400,
       "messages": '"$QUESTION"',
       "chat_template_kwargs": {"enable_thinking": false}}'

Python

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.albastov.com/v1",
    api_key=os.environ["ALBASTAR_API_KEY"],
)
question = [{"role": "user", "content": "Is 91 prime? Answer yes or no."}]

# Thinking on (the default)
on = client.chat.completions.create(
    model="qwen3.8-27b", messages=question, max_tokens=400,
)
msg = on.choices[0].message
print("reasoning:", getattr(msg, "reasoning", None))
print("answer:", msg.content.strip())
print("reasoning tokens:", on.usage.completion_tokens_details.reasoning_tokens)

# Thinking off
off = client.chat.completions.create(
    model="qwen3.8-27b", messages=question, max_tokens=400,
    extra_body={"chat_template_kwargs": {"enable_thinking": False}},
)
print("answer without thinking:", off.choices[0].message.content.strip())

The response with thinking on, abridged: the reasoning is cut to its central sentence, and fields other than the message and the completion token counts are left out.

Response, thinking on (abridged)
{
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": "\n\nNo",
        "reasoning": "… 91=7*13 not prime. Answer no. …"
      }
    }
  ],
  "usage": {
    "completion_tokens": 50,
    "completion_tokens_details": {"reasoning_tokens": 46}
  }
}

Token budget

max_tokens includes reasoning tokens. A low max_tokens ends the response during the reasoning, with finish_reason: "length" and empty content. Set max_tokens to 1,000 or more for hard questions, and stream long reasoning: a non-streamed request that sends no response byte for 100 s ends with 524, a gateway timeout.

Reasoning field

The reasoning field is reasoning (delta.reasoning in a stream). Clients written for other servers may read reasoning_content instead. The OpenAI Python SDK returns reasoning as an attribute: read message.reasoning.

  • content can start with blank lines after the reasoning. Trim content.
  • Send earlier assistant turns with content only, without reasoning.

Model support

Every chat model reasons before answering by default: capabilities.thinking is true for each in GET /v1/models. On every chat model, chat_template_kwargs.enable_thinking: false turns the reasoning off.

chat_template_kwargs, max_tokens and the reasoning response fields: Chat completions reference.