Skip to content

Reasoning আর thinking model

Tokens দিয়ে reasoning model চালানো: Chat Completions-এ reasoning_effort, Messages-এ thinking ও effort, reasoning text কীভাবে ফেরত আসে ও stream হয়, reasoning token কীভাবে গোনা ও বিল হয়, আর gateway কী বদলায় বা বাদ দেয়।

Markdown-এ দেখুন
এই পাতায়

Reasoning model (OpenAI এদের বলে reasoning model, Anthropic ফিচারটার নাম দিয়েছে thinking) উত্তর লেখার আগে সমস্যাটা নিয়ে ভাবে। এই বাড়তি ভাবনায় কঠিন coding, অঙ্ক আর planning-এর কাজে ফল ভালো হয়। তবে দামও আছে: token আর সময় দুটোই বেশি লাগে। model যে thinking token বানায়, সেগুলো হয়তো আপনি কখনো দেখেনই না, কিন্তু তার বিল আপনাকেই দিতে হয়।

এই পেজে আছে: কী পাঠাতে পারেন, কী ফেরত আসে, Tokens thinking token কীভাবে গোনে ও বিল করে, আর কোথায় gateway আপনার request বদলে দেয়। parameter-এর নাম আর প্রতিটা value-র মানে ঠিক করে সেই provider, যে model-টা চালায়। Tokens এগুলো শুধু forward করে, ব্যাখ্যা করে না। তাই provider-এর আচরণ নিয়ে লেখা অংশগুলোকে model-এর maker-দের documentation-এর সারাংশ ধরুন (October 2026-এ checked), Tokens-এর কোনো প্রতিশ্রুতি নয়।

সংক্ষেপে#

আপনি যা call করেনreasoning নিয়ন্ত্রণ করবেন যা দিয়েreasoning text ফিরে আসে যেভাবে
/v1/chat/completionsreasoning_effortmessage বা stream delta-তে reasoning_content, model যদি সেটা দেখায়
/v1/messagesthinking আর output_config.effort (পুরোনো Claude model-এ: thinking.budget_tokens)thinking content block, আর stream-এ thinking_delta event
/v1/responsesreasoning.effort আর reasoning.summaryreasoning output item, যার ভেতরে summary list থাকে

এর কোনটা একটা model মানবে, তা model-ভেদে আলাদা। কোনো model সব সময়ই reasoning করে, বন্ধ করার switch নেই। কোনোটা effort level নেয়, কোনোটা token budget নেয়, আর কোনোটা এই সব field-ই উপেক্ষা করে।

কোনো model reasoning করে কি না, কীভাবে জানবেন#

/models-এর catalog-এ প্রতিটা model-এর context window, দাম আর বিবরণ আছে। কিন্তু "reasoning" বা "thinking" বোঝানোর কোনো flag নেই। জানার উপায়:

  • model-এর পেজ আর maker-এর documentation পড়ুন। Choosing a model পেজে কয়েকটা model-এর কথা আছে যেগুলো সব সময় thinking করে, যেমন Kimi K3 আর GLM-5.3। সেখানে এটাও লেখা আছে, always-on thinking মানে প্রতিটা call-এ বাড়তি output token।
  • একটা test request পাঠিয়ে উত্তরটা দেখুন। reasoning model সাধারণত reasoning_content field, thinking block বা usage-এর ভেতরে reasoning token-এর details ফেরত দেয়। যে উত্তরটা আপনি দেখছেন তার তুলনায় completion_tokens অনেক বেশি হলেও বোঝা যায়।
python
import os
from openai import OpenAI

client = OpenAI(base_url="https://tokens.bd/v1", api_key=os.environ["TOKENS_API_KEY"])

resp = client.chat.completions.create(
    model="deepseek/deepseek-v4.1-flash",
    max_tokens=2000,
    messages=[{"role": "user", "content": "A train leaves at 09:10 and arrives at 11:45. How long is the trip?"}],
)

message = resp.choices[0].message
print("visible answer:", message.content)
print("reasoning text:", getattr(message, "reasoning_content", None))
print("usage:", resp.usage)

reasoning_content OpenAI-র নিজের API-র অংশ নয়। কিছু OpenAI-compatible provider model-এর reasoning text পাঠাতে এই নামটা ব্যবহার করে, আর provider পাঠালে gateway সেটা যেমন আছে তেমনই পৌঁছে দেয়।

Chat Completions: reasoning_effort#

reasoning_effort হলো OpenAI-র parameter, যা ঠিক করে reasoning model কতটা ভাববে। OpenAI-র reasoning guide অনুযায়ী কোন value চলবে তা model-ভেদে আলাদা, আর তালিকায় আছে none, minimal, low, medium, high, xhigh ও max। field না দিলে বেশির ভাগ বর্তমান OpenAI model default হিসেবে medium ধরে। কিছু model কিছু value নেয় না: OpenAI-র documentation অনুযায়ী GPT-6 Astra none দিলে 400 ফেরত দেয়, আর GPT-6.1 Sol none ও minimal দুটোই ফিরিয়ে দেয়। effort কম হলে উত্তর দ্রুত আর সস্তা হয়। কঠিন সমস্যায় effort বেশি দিন।

curl https://tokens.bd/v1/chat/completions \
  -H "Authorization: Bearer $TOKENS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek/deepseek-v4.1-flash",
    "max_completion_tokens": 4000,
    "reasoning_effort": "low",
    "messages": [
      {"role": "user", "content": "Find the bug: for i in range(len(xs)+1): total += xs[i]"}
    ]
  }'

field-টার কী হবে, তা নির্ভর করে model আর তার পেছনের provider-এর ওপর। model reasoning_effort না নিলে provider হয় সেটা উপেক্ষা করে, নয়তো 400 ফেরত দেয়, যা আপনার কাছে আসে invalid_request হয়ে (errors)। একই ধারণার জন্য কিছু maker নিজেদের field-এর নাম ব্যবহার করে। gateway Chat Completions-এর field validate করে না, তাই body-তে provider-specific কোনো field থাকলে সেটা যেমন আছে তেমনই forward হয়। OpenAI SDK-তে এমন field দিতে extra_body ব্যবহার করতে পারেন। provider সেটা মানবে কি না, তা maker-এর সিদ্ধান্ত, তাই তাদের documentation দেখে নিন।

OpenAI-র documentation থেকে দুটো কথা বাস্তবে কাজে লাগে। এক, reasoning model-এর thinking-ও output limit থেকে গোনা হয়। দুই, GPT-5.4 থেকে শুরু করে Chat Completions-এ reasoning_effort none ছাড়া অন্য কিছু হলে tool calling চলে না। ওই model-এ tool ব্যবহার করতে চাইলে reasoning_effort: "none" দিন, অথবা Responses API ব্যবহার করুন।

OpenAI reasoning model-এর জন্য gateway কী বদলায়#

OpenAI-র o-series আর GPT-5 ও তার পরের model max_tokens নেয় না, আর temperature বা top_p 1 ছাড়া অন্য কিছু হলেও ফিরিয়ে দেয়। তবু অনেক client এগুলো পাঠিয়ে দেয়। তাই এই ধরনের model-এ (model-এর নাম দেখে চেনা হয়) Chat Completions request গেলে gateway forward করার আগে body বদলে নেয়:

  • max_tokens-এর নাম বদলে max_completion_tokens হয় (দুটোই পাঠালে আপনারটা থাকে)।
  • temperature আর top_p বাদ যায়, যদি value ঠিক 1 না হয়।

এটা শুধু /v1/chat/completions-এ হয়, Messages বা Responses-এ নয়, আর অন্য maker-দের model-এও নয়। অন্য maker-দের model আপনার parameter যেমন পাঠিয়েছেন তেমনই পায়, আর তাদের কয়েকটা reasoning চলাকালে temperature ফিরিয়ে দেয় বা উপেক্ষা করে।

আপনার চাওয়া max_tokens বা max_completion_tokens-এর খরচ ব্যালান্স দিয়ে না মিটলে gateway সেটা কমিয়ে দিতে পারে (16-র নিচে নামায় না), যেমনটা Chat Completions পেজে বলা আছে। reasoning model-এ এই কমানোর ফলে পুরো allowance thinking-এই শেষ হয়ে যেতে পারে, আর উত্তর ফাঁকা বা ছোট আসে, সঙ্গে finish_reason: "length"। এমন limit দিন যা আপনার ব্যালান্স মেটাতে পারে, নয়তো Billing-এ গিয়ে টাকা যোগ করুন।

Messages: thinking and effort#

/v1/messages-এ Anthropic-এর model একটা thinking object নেয়, আর বর্তমান model-এ একটা output_config.effort level-ও। যে provider Messages API বোঝে, তার কাছে gateway দুটোই না বদলে forward করে। Anthropic-এর documentation অনুযায়ী (October 2026-এ checked, thinking, extended thinking, effort):

  • বর্তমান Claude model (4.7 ও তার পরের, 5.x line-সহ): thinking: {"type": "adaptive"} দিন, আর গভীরতা ঠিক করুন output_config: {"effort": "low" | "medium" | "high" | "xhigh" | "max"} দিয়ে। কোন level আছে, তা model-ভেদে আলাদা। কয়েকটা 5.x model-এ thinking field ছাড়াই thinking আগে থেকে চালু থাকে। পুরোনো form thinking: {"type": "enabled", "budget_tokens": N} এই model-গুলোতে 400 ফেরত দেয়।
  • Claude 4.6: enabled form এখনো চলে, কিন্তু deprecated।
  • Claude 4.5 ও তার আগের: শুধু enabled form আছে। budget_tokens একটা লক্ষ্যমাত্রা, যা অন্তত 1,024 হতে হবে আর max_tokens-এর চেয়ে কম।
  • Thinking text দেখা: অনেক বর্তমান model-এ প্রতিটা block-এর thinking field default-এ ফাঁকা আসে (display তখন omitted)। reasoning-এর সারাংশ পেতে thinking object-এর ভেতরে "display": "summarized" দিন। Anthropic কোনো setting-এই raw chain of thought ফেরত দেয় না।
import os
import anthropic

client = anthropic.Anthropic(base_url="https://tokens.bd", api_key=os.environ["TOKENS_API_KEY"])

message = client.messages.create(
    model="deepseek/deepseek-v4.1-flash",
    max_tokens=8000,
    thinking={"type": "adaptive", "display": "summarized"},
    output_config={"effort": "medium"},
    messages=[{"role": "user", "content": "Plan a safe rollout for a database column rename."}],
)

for block in message.content:
    if block.type == "thinking":
        print("thinking summary:", block.thinking)
    elif block.type == "text":
        print("answer:", block.text)
print(message.usage)

output_config-এর জন্য নতুন Anthropic SDK লাগে। এই উদাহরণগুলো Claude model-এর request-এর গড়ন দেখায়; আপনার model-এর maker যে form documented করেছে, সেটাই ব্যবহার করুন। কোন model কোন form নেয়, তা Tokens-এর catalog-এ লেখা নেই।

thinking থাকলে response-এ text block-এর আগে thinking block আসে:

json
{
  "content": [
    { "type": "thinking", "thinking": "The rename needs a two-step deploy...", "signature": "EosnCkYICxIM..." },
    { "type": "text", "text": "Roll it out in three steps: add the new column..." }
  ],
  "stop_reason": "end_turn",
  "usage": { "input_tokens": 24, "output_tokens": 912 }
}

signature হলো encrypted data, যার সাহায্যে model নিজের reasoning চালিয়ে যেতে পারে। tool-use loop-এ tool result ফেরত পাঠানোর সময় Anthropic চায় thinking block অপরিবর্তিত অবস্থায় আবার পাঠানো হোক। redacted_thinking block-ও একই নিয়ম: তাতে encrypted content থাকে, পড়ার মতো কোনো text থাকে না। শুধু text নয়, assistant-এর পুরো content array রেখে দিন। Tool calling পেজের loop-এ {"role": "assistant", "content": resp.content} দেখানো আছে। Anthropic আরও জানিয়েছে, manual extended thinking-এ tool_choice শুধু auto বা none হতে পারে।

Translate হলে কী টিকে থাকে#

প্রতিটা model এক বা একাধিক provider চালায়, আর gateway সেই provider-কেই পছন্দ করে যে আপনার request-এর format-ই বোঝে। কোনো model শুধু অন্য format-এ পাওয়া গেলে gateway translate করে (Messages দেখুন), আর তখন reasoning এভাবে সামলানো হয়:

কোন দিকেrequest-এ reasoning নিয়ন্ত্রণউত্তরে reasoning
Messages request, provider OpenAI format-এ চলেthinking আর output_config যায় নাprovider যে reasoning_content পাঠায়, সেটা thinking block হয়ে ফেরত আসে না, বাদ পড়ে
Chat Completions request, provider Anthropic format-এ চলেreasoning_effort যায় নাthinking block হয়ে যায় message.reasoning_content (stream করলে delta.reasoning_content)। redacted_thinking block আর signature value বাদ পড়ে

এর ফল:

  • translate হওয়া পথে ওই field দিয়ে reasoning চালু করা বা তার level বদলানো যায় না। তখন model reasoning করবে কি না, তা model-এর default-এর ওপর নির্ভর করে।
  • model thinking-এ যে token খরচ করেছে, usage-এর সংখ্যায় সেগুলো ধরা থাকে। অর্থাৎ যে reasoning আপনি দেখতে পাচ্ছেন না, তার বিলও আপনার।
  • Chat Completions request-এ Anthropic-এর thinking signature যায় না। তাই যে tool-use loop-এ thinking block ফেরত পাঠাতে হয়, সেটা /v1/messages-এ চালান।

নির্দিষ্ট কোনো reasoning setting খাটাতেই হলে model-এর নিজস্ব format-এর endpoint-এ call করুন, আর একটা test request পাঠিয়ে মিলিয়ে নিন: উত্তরে reasoning আছে কি না (একটা thinking block বা reasoning_content), অথবা setting বদলালে usage বদলায় কি না।

Responses API#

POST https://tokens.bd/v1/responses-এ OpenAI-র parameter হলো reasoning, যার ভেতরে effort আর, পড়ার মতো সারাংশ চাইলে, summary। gateway body যেমন আছে তেমনই forward করে, আর support নির্ভর করে model-এর পেছনের provider-এর ওপর (Responses API দেখুন)।

python
import os
from openai import OpenAI

client = OpenAI(base_url="https://tokens.bd/v1", api_key=os.environ["TOKENS_API_KEY"])

resp = client.responses.create(
    model="deepseek/deepseek-v4.1-flash",
    input="Find the bug: for i in range(len(xs)+1): total += xs[i]",
    reasoning={"effort": "low", "summary": "auto"},
    max_output_tokens=4000,
)
print(resp.output_text)
print(resp.usage)

OpenAI-র documentation অনুযায়ী raw reasoning token কখনো ফেরত দেওয়া হয় না। summary দিলে response-এ একটা reasoning output item আসে, যার summary list-এ পড়ার মতো একটা সারাংশ থাকে। tool loop চালিয়ে গেলে function-call-এর output-এর সঙ্গে reasoning item-ও model-কে আবার পাঠাতে বলেছে OpenAI।

Reasoning stream করা#

"stream": true দিলে উত্তরের আগে reasoning আসে, আর model আগে ভাবলে stream কিছুক্ষণ চুপচাপ থাকে।

Chat Completions। যে provider reasoning text দেখায়, সে সেটা পাঠায় delta.reasoning_content হিসেবে, তারপর উত্তরের জন্য delta.content। translate হওয়া Anthropic thinking-ও একই ভাবে পৌঁছায়। যে client অচেনা field উপেক্ষা করে, সে শুধু উত্তরটাই দেখাবে।

import os
from openai import OpenAI

client = OpenAI(base_url="https://tokens.bd/v1", api_key=os.environ["TOKENS_API_KEY"])

stream = client.chat.completions.create(
    model="deepseek/deepseek-v4.1-flash",
    max_tokens=4000,
    stream=True,
    stream_options={"include_usage": True},
    messages=[{"role": "user", "content": "Why does 0.1 + 0.2 != 0.3 in floating point?"}],
)

for chunk in stream:
    if chunk.usage:
        print("\nusage:", chunk.usage)
    if not chunk.choices:
        continue
    delta = chunk.choices[0].delta
    reasoning = getattr(delta, "reasoning_content", None)
    if reasoning:
        print(reasoning, end="", flush=True)  # reasoning text, if the model sends it
    if delta.content:
        print(delta.content, end="", flush=True)

Messages। thinking আসে content_block_delta event-এ thinking_delta হিসেবে। block বন্ধ হওয়ার ঠিক আগে আসে একটা signature_delta, তারপর text block-গুলো। display omitted হলে thinking_delta event-এ ফাঁকা string থাকে, শুধু signature আসে।

python
import os
import anthropic

client = anthropic.Anthropic(base_url="https://tokens.bd", api_key=os.environ["TOKENS_API_KEY"])

stream = client.messages.create(
    model="deepseek/deepseek-v4.1-flash",
    max_tokens=8000,
    stream=True,
    thinking={"type": "adaptive", "display": "summarized"},
    messages=[{"role": "user", "content": "Why does 0.1 + 0.2 != 0.3 in floating point?"}],
)

for event in stream:
    if event.type == "content_block_delta":
        if event.delta.type == "thinking_delta":
            print(event.delta.thinking, end="", flush=True)
        elif event.delta.type == "text_delta":
            print(event.delta.text, end="", flush=True)

stream-এর format, disconnect আর timeout নিয়ে আরও আছে streaming পেজে।

Token গোনা আর বিল#

Reasoning token আসলে output token। OpenAI আর Anthropic দুজনেই জানিয়েছে, model thinking-এ যে token খরচ করে সেগুলো output token হিসেবে বিল হয়, আর output limit (max_completion_tokens বা max_tokens)-এর মধ্যে গোনা হয়, reasoning text আপনাকে ফেরত না দিলেও।

  • provider usage-এ যা রিপোর্ট করে, Tokens সেটাই বিল করে: input, output, আর cache read ও write। প্রতিটা ধরনের token-এর দাম model-এর catalog price অনুযায়ী (prices)। reasoning token output count-এরই অংশ, তাই model-এর output rate-এ দাম ধরা হয়। reasoning-এর আলাদা কোনো দাম নেই।
  • যে উত্তরটা আপনি দেখছেন, সেটা বিলের ছোট একটা অংশ হতে পারে। 300 token-এর উত্তর আর 1,200 thinking token মিলে বিল হয় 1,500 output token। Usage analytics (usage) output token ঠিক যেভাবে বিল হয়েছে সেভাবেই দেখায়।
  • summary বা omitted thinking-এ বিল কমে না। Anthropic জানিয়েছে, summary-র নয়, পুরো thinking token-এর চার্জ লাগে, আর display: "omitted" শুধু latency কমায়।
  • কিছু provider usage-এর ভেতরেই ভাগটা দেখায়, যেমন Chat Completions-এ completion_tokens_details.reasoning_tokens, Responses-এ output_tokens_details.reasoning_tokens আর Messages-এ output_tokens_details.thinking_tokens। field-গুলো provider-এর, যেমন আছে তেমনই পাঠানো হয়। এগুলো শুধু তথ্যের জন্য, বিল হয় output-এর মোট সংখ্যা ধরে।
  • provider কোনো usage না পাঠালে gateway response-এর আকার দেখে আন্দাজ করে, উত্তরের সঙ্গে reasoning_content text-ও গুনে।
  • Anthropic জানিয়েছে, তাদের নতুন model আগের turn-এর thinking block context-এ রেখে দেয় আর পরের turn-এ সেগুলো input হিসেবে বিল করে। thinking-সহ লম্বা tool loop প্রতি round-এ এগুলো আবার পাঠায়, তাই round যত বাড়ে, খরচও তত বাড়ে।

forward করার আগে gateway আপনার output limit ধরে (কিছু না দিলে 8,192 token) worst case-এর টাকা ব্যালান্স থেকে আলাদা করে রাখে, যেমন Chat Completions-এ বলা আছে। reasoning model-এ 32,000 বা তার বেশির মতো বড় limit দিলে model আগে শেষ করলেও অনেক টাকা আটকে থাকে। তবে চার্জ হয় আসল usage অনুযায়ী।

কতটা সীমা রাখবেন#

  • output limit এত বড় রাখুন, যাতে thinking আর উত্তর দুটোই ধরে। model পুরোটা thinking-এই খরচ করে ফেললে উত্তর কাটা বা ফাঁকা আসে, সঙ্গে finish_reason: "length" (Chat Completions) বা stop_reason: "max_tokens" (Messages)। OpenAI-র reasoning model নিয়ে শুরু করার সময় reasoning আর output মিলিয়ে অন্তত 25,000 token রাখতে বলেছে, পরে ধীরে ধীরে কমিয়ে আনতে বলেছে।
  • low বা medium effort দিয়ে শুরু করুন, উত্তর যথেষ্ট ভালো না হলে তবেই বাড়ান। effort বেশি মানে thinking token বেশি, latency-ও বেশি।
  • নিত্যকার কাজে (rename, formatting, ছোটখাটো edit) non-reasoning model, বা model যেখানে মানে সেখানে reasoning_effort: "none", সস্তা আর দ্রুত।

Latency আর timeout#

যে model উত্তরের আগে ভাবে, সে প্রথম token দেওয়ার আগে অনেকক্ষণ চুপ থাকতে পারে। response stream করুন, তাতে আপনার client অগ্রগতি দেখাতে পারবে আর connection সচল থাকবে।

gateway-ও চুপ থাকাটা নজরে রাখে। একটা model-এর পেছনে একাধিক provider থাকলে, streaming provider-এর প্রথম event-এর জন্য gateway default-এ 30 সেকেন্ড অপেক্ষা করে (operator এটা বদলাতে পারেন), তারপর আরেকটা provider configure করা থাকলে সেটা চেষ্টা করে। non-streaming request পায় অন্তত 120 সেকেন্ড। chain-এর শেষ provider-এর জন্য আগেভাগে কেটে দেওয়ার কোনো সময় নেই। যে provider 600 সেকেন্ড কিছুই পাঠায় না, তার শেষ হয় 504 upstream_timeout দিয়ে (errors)। ধীর reasoning model non-streaming call-এ timeout হলে streaming-এ যান, আর নিজের client-এর timeout এমন রাখুন যা আপনার আশা করা সবচেয়ে লম্বা উত্তরের চেয়েও বেশি।

সমস্যা হলে#

লক্ষণসম্ভাব্য কারণসমাধান
reasoning_effort দেওয়ার পর 400 invalid_requestmodel বা provider ওই field বা value নেয় নাfield-টা সরিয়ে দিন, অথবা ওই model-এর জন্য maker যে value documented করেছে সেটা দিন।
budget_tokens-সহ thinking-এ 400Claude model শুধু adaptive thinking মানেthinking: {"type": "adaptive"} আর output_config.effort ব্যবহার করুন।
max_tokens বা temperature-এ 400OpenAI reasoning model এমন পথে, যেখানে gateway এগুলো বদলায় নাChat Completions-এ gateway বদলে দেয়; Messages বা Responses-এ model-এর নিজের parameter-এর নাম ব্যবহার করুন।
উত্তর ফাঁকা, finish_reason: "length"thinking পুরো output limit খেয়ে ফেলেছেmax_tokens বা max_completion_tokens বাড়ান, অথবা effort কমান।
response-এ reasoning text নেইmodel সেটা দেখায় না, display omitted, অথবা পথের মাঝে সেটা বাদ পড়েছেClaude model-এ display: "summarized" দিন, অথবা উপরের translate-এর টেবিলটা দেখুন।
Claude ছাড়া অন্য model-এ Messages-এ thinking block আসে নাmodel OpenAI format-এ চলে আর reasoning_content বাদ পড়ছেreasoning পড়তে Chat Completions ব্যবহার করুন।
উত্তরের চেয়ে বিল অনেক বেশিthinking token আসলে output tokeneffort বা budget কমান, অথবা ছোট model নিন।
লম্বা non-streaming call-এ 504 upstream_timeoutmodel upstream-এর অপেক্ষার সময়ের চেয়ে বেশি ভেবেছেresponse stream করুন।
Claude-এ tool loop thinking-block error দিয়ে ভাঙছেthinking block অপরিবর্তিত অবস্থায় ফেরত পাঠানো হয়নি/v1/messages-এ assistant-এর পুরো content আবার পাঠান, thinking ও redacted_thinking block সহ।

এই পাতাটা কি কাজে লেগেছে?

এখনো আটকে আছেন? Support ticket খুলুন

আপনার agent set up করতে সাহায্য লাগবে?

Connection tester দিয়ে সংযোগ পরীক্ষা করে নিন, অথবা একটা API key তৈরি করুন।