स्थानिक LLM मध्ये reasoning effort किती ठेवावे?
reasoning effort मुळे स्थानिक LLM च्या weights किंवा quantisation मध्ये बदल होत नाही. scratchpad tokens, CPU/GPU वेळ आणि context window वरील खरा खर्च कसा मोजाल ते जाणून घ्या.
स्थानिक LLM मध्ये reasoning effort मुळे काय बदलते
reasoning effort ही अशी setting आहे जी मॉडेलने उत्तर देण्यापूर्वी किती वेळ विचार करावा हे ठरवते. यामुळे reasoning segment ची लांबी बदलते; त्याशिवाय काहीही बदलत नाही. डिस्कवरील weights प्रत्येक स्तरावर समान असतात, quantisation समान असते आणि उत्तर त्याच forward pass मधून तयार होते. प्रथम स्वतःच्या scratchpad मध्ये मॉडेल किती tokens वापरते, एवढाच बदल होतो.
हे tokens कुठे वापरले जातात, यामुळे हा फरक महत्त्वाचा ठरतो. hosted API मध्ये reasoning tokens चे शुल्क invoice वर दिसते. तुमच्या मालकीच्या VPS वर त्याची किंमत तुमच्या स्वतःच्या CPU किंवा GPU वरील generation time आणि context window मधील व्यापलेली जागा यांमध्ये मोजली जाते. मॉडेल highest effort वर ठेवले, तर उत्तरातील पहिला शब्द दिसण्यापूर्वी ते output चा बहुतांश भाग reasoning साठी वापरू शकते. self-hosted hardware वर यामुळे दोन सेकंदांच्या reply ऐवजी दोन मिनिटे लागू शकतात.
स्तर कुठे ठरतो: weights मध्ये नव्हे, तर chat template मध्ये
Thinking model अंतिम उत्तर देण्यापूर्वी reasoning segment तयार करण्यासाठी प्रशिक्षित केलेले असते. हा segment सामान्यतः <think> आणि </think> tags मध्ये गुंडाळलेला असतो. Effort level हे model च्या chat template कडून prompt मध्ये लिहिले जाणारे instruction असते. हा template model सोबत वितरित केलेली Jinja file असते. ती reasoning_effort सारखा variable वाचते आणि प्रत्येक value साठी वेगळी system-level line तयार करते. त्या line नुसार scratchpad लहान किंवा मोठा करण्यासाठी model ला प्रशिक्षित केलेले असते.
यातून दोन गोष्टी स्पष्ट होतात. Level names हे तुमच्या runtime चे नसून model चे असतात. त्यामुळे एका model च्या card मधील name दुसऱ्या model साठी निरर्थक असू शकते. तसेच chain मधील कोणत्याही घटकाने model चा chat template generic template ने बदलला, तर variable render होत नाही आणि setting मूकपणे निष्प्रभ ठरते.
2026-08-20 रोजी तपासल्यावर, Qwen3.8-27B model card मध्ये तीन effort levels नमूद केले आहेत: low, medium आणि xhigh. xhigh हे default आहे. high उपलब्ध नाही. Thinking हे enable_thinking ने सुरू किंवा बंद केले जाते. ते default ने on असते. Card मध्ये preserve_thinking देखील नमूद केले आहे. ते default ने on असते आणि मागील turns मधील reasoning conversation history मध्ये ठेवते. याउलट, gpt-oss मध्ये low, medium आणि high वापरले जातात. इतर अनेक model families boolean स्वीकारतात आणि त्यापेक्षा अधिक पर्याय देत नाहीत. तुम्ही वापरलेल्या exact version साठी model card वाचा, कारण ही names standard नाहीत. VPS वर 27B model चालवणे हा आधीचा टप्पा आहे. हे पृष्ठ model उत्तर देऊ लागल्यानंतर कोणती settings करावीत याबद्दल आहे.
VPS वर high effort साठी जास्त खर्च का येतो
Output tokens. Reasoning tokens आणि output tokens एकाच decode loop मधून निर्माण होतात. ते तुमच्या hardware च्या क्षमतेनुसार समान tokens per second वेगाने तयार होतात. समजा एखाद्या task मध्ये 200 output tokens आणि 4,000 reasoning tokens तयार होतात. अशा वेळी एकूण 4,200 tokens तयार झाले, पण वाचकाला त्यापैकी फक्त 200 tokens दिसले. तुमचा decode rate memory bandwidth आणि तुम्ही निवडलेल्या quantisation वर ठरतो. त्यामुळे उरलेला नियंत्रित करता येणारा घटक म्हणजे token count.
Wall clock. एखादी व्यक्ती answer मधील पहिल्या token ची वाट पाहते. त्यापूर्वी blank screen किंवा collapsed spinner दिसतो. Reasoning आधी तयार होते. त्यामुळे प्रतीक्षा साधारणपणे reasoning token count ला तुमच्या decode rate ने भागल्यावर मिळणाऱ्या वेळेइतकी, तसेच prompt processing साठी लागणाऱ्या वेळेइतकी असते. Reasoning ची लांबी दुप्पट केली, तर ही प्रतीक्षा दुप्पट होते.
Context. इतर कोणत्याही token प्रमाणे reasoning tokens देखील context window मध्ये जागा व्यापतात. preserve_thinking सुरू असल्यास, turn one मधील scratchpad turn five च्या prompt मध्ये अजूनही असतो. त्यामुळे window दोन्ही बाजूंनी भरत असताना प्रत्येक turn नंतर prompt processing अधिक धीमे होते. तो ठेवण्यासाठी num_ctx वाढवणे KV cache memory वापरते. GPU नसलेल्या VPS वर ही system RAM असते, जी कदाचित उपलब्ध नसेल.
स्तर कधी वाढवायचा आणि कधी कमी ठेवायचा
चुकीची मधली पायरी अंतिम परिणाम बिघडवू शकते अशा कामांसाठी स्तर वाढवा: अनेक टप्प्यांची अंकगणितीय गणना आणि एकक रूपांतरण, अनेक फाइल्समध्ये कराव्या लागणाऱ्या संपादनाचे नियोजन, compile होणे आवश्यक असलेला code आणि एकाच वेळी अनेक अटी पूर्ण करणाऱ्या constraint समस्या. अशा कामांमध्ये scratchpad प्रत्यक्ष काम करते. त्यामुळे थोडा अधिक तपशीलवार विचार केल्यास model कडून अन्यथा होणारी चूक पकडणे कमी खर्चात शक्य होते.
उत्तर आधीच input मध्ये दिलेले असेल आणि काम फक्त ते पुढे रूपांतरित करण्याचे असेल, तेव्हा स्तर कमी ठेवा. Extraction, classification, tagging, translation, rewriting, summarising आणि formatting या सर्व कामांचा यात समावेश होतो. Reasoning segment मुख्यतः task पुन्हा मांडतो. त्यामुळे model ला योग्य पहिल्या निष्कर्षापासून स्वतःच दूर जाण्यासाठी अनावश्यक वाव मिळतो.
Interactive कामांसाठीही स्तर कमी ठेवा. Chat box किंवा editor मध्ये तुम्ही प्रक्रियेत सहभागी असता. त्यामुळे प्रतीक्षा करावी लागणाऱ्या धीम्या उत्तरापेक्षा तुम्ही लगेच दुरुस्त करू शकणारे जलद उत्तर अधिक उपयुक्त ठरते. local model कडे coding agent निर्देशित करण्यामागील खरा तडजोडीचा मुद्दा हाच आहे: agent अनेक लहान calls करतो आणि reasoning tax प्रत्येक call वर आकारला जातो.
llama.cpp मध्ये स्तर कसा सेट करायचा
llama.cpp हे चल थेट template मध्ये लिहिते. त्यामुळे हे चल runtime पर्यंत पोहोचल्याची खात्री करता येते. -m मध्ये तुमच्याकडे आधीपासून असलेल्या GGUF चा path द्या.
llama-server -m ./qwen3.8-27b-Q4_K_M.gguf \
--jinja \
--reasoning-effort medium \
--reasoning-format deepseek \
-c 32768 \
--host 127.0.0.1 --port 8080--jinja मॉडेलचा स्वतःचा chat template वापरते आणि सध्याच्या builds मध्ये ती default ने enabled असते. --reasoning-effort मध्ये default, minimal, low, medium, high, xhigh किंवा max स्वीकारले जातात. default चा अर्थ template चे स्वतःचे default तसेच ठेवणे असा आहे. ही यादी मॉडेलची नसून llama.cpp ची vocabulary आहे. त्यामुळे card मध्ये दिलेलेच नाव वापरा. Template मध्ये परिभाषित नसलेला स्तर दिल्यास request च्या वेळी template error येऊ शकतो. --reasoning-format deepseek reasoning ला message.content मधून काढून message.reasoning_content मध्ये ठेवते. त्यामुळे पुढील section मध्ये या विभाजनाचे मोजमाप करता येते.
Reasoning लहान करण्याऐवजी ते पूर्णपणे बंद करायचे असल्यास template variable स्वतः सेट करा:
llama-server -m ./qwen3.8-27b-Q4_K_M.gguf --jinja \
--chat-template-kwargs '{"enable_thinking": false}'--reasoning-budget ही वेगळी यंत्रणा आहे. ती reasoning segment ची मर्यादा tokens मध्ये ठरवते. 0 दिल्यास तो segment त्वरित संपतो, तर -1 दिल्यास त्यावर कोणतीही मर्यादा राहत नाही. यामुळे मॉडेलला लहान reasoning segment तयार करण्यास सांगितले जात नाही. दोन्ही flags संपूर्ण server साठी लागू होतात. llama-server reasoning_effort ला per-request field म्हणून स्वीकारत नाही. त्यामुळे एकाच वेळी दोन effort levels serve करण्यासाठी दोन ports वर दोन processes चालवावे लागतात.
vLLM मध्ये OpenAI-compatible body च्या आत, प्रत्येक request साठी हेच variable देता येते:
{"model": "Qwen/Qwen3.8-27B",
"messages": [{"role": "user", "content": "Summarise this changelog in two lines."}],
"chat_template_kwargs": {"reasoning_effort": "medium"}}Ollama मध्ये स्तर कसा सेट करायचा
Ollama मध्ये /api/chat आणि /api/generate वर स्वतःचे think फील्ड असते. त्यात true, false किंवा low, medium, high आणि max यांपैकी एक मूल्य स्वीकारले जाते. max मुळे मॉडेलने उपलब्ध करून दिलेला सर्वोच्च स्तर मागितला जातो. विचारक्षमता समर्थित असलेल्या मॉडेल्समध्ये ती पूर्वनिर्धारितपणे सुरू असते.
ollama run qwen3.8:27b --think=low "Draft a one line commit message for a README typo fix"{"model": "qwen3.8:27b",
"messages": [{"role": "user", "content": "Which HTTP status code means the request body was too large?"}],
"think": "low",
"stream": false}तर्क message.thinking मध्ये आणि उत्तर message.content मध्ये मिळते. ते तुमच्यासाठी आधीच वेगळे केलेले असतात. परस्परसंवादी ollama run सत्रात /set think आणि /set nothink वापरून सत्र रीस्टार्ट न करता विचारक्षमता सुरू किंवा बंद करता येते.
आता ही विसंगती लक्षात घ्या. Ollama मध्ये low, medium, high आणि max हे स्तर वापरले जातात. Qwen3.8 च्या template मध्ये low, medium आणि xhigh हे स्तर परिभाषित केले आहेत. एका प्रणालीतील स्तर दुसऱ्या प्रणालीतील स्तराशी मॅप करणे आवश्यक आहे. Ollama मॉडेलमध्ये मूळ repository मधील Jinja फाइलऐवजी त्याच्या tag मध्ये पॅकेज केलेले template असते. त्यामुळे तुमचा स्तर मॉडेलपर्यंत पोहोचतो की नाही हे त्या पॅकेज केलेल्या template वर अवलंबून असते. ते कार्य केले असे गृहीत धरू नका. हे मोजण्यासाठी सुमारे एक मिनिट लागते.
प्रत्यक्षात level लागू झाला आहे का हे कसे मोजावे
temperature ला 0 ठेवून तोच prompt एकापेक्षा अधिक level वर पाठवा. त्यानंतर token counts ची तुलना करा. येथे jq body तयार करते, त्यामुळे quotes हाताने escape करण्याची गरज नाही.
for level in low medium max; do
body=$(jq -n --arg lvl "$level" '{
model: "qwen3.8:27b",
messages: [{role: "user", content: "A pump fills a 4500 litre tank in 25 minutes. A second pump is 40 percent slower. How long do both together take? Answer in minutes."}],
think: $lvl,
stream: false,
options: {temperature: 0, num_ctx: 8192}
}')
echo "== $level"
curl -s http://localhost:11434/api/chat -d "$body" | jq '{
thinking_chars: (.message.thinking // "" | length),
answer_chars: (.message.content | length),
eval_count: .eval_count,
seconds: (.total_duration / 1e9),
tok_per_sec: (.eval_count / (.eval_duration / 1e9))
}'
doneeval_count मध्ये reasoning सहित निर्माण झालेले प्रत्येक token समाविष्ट असते. त्यामुळे दोन levels मधील फरक जवळजवळ संपूर्णपणे reasoning मुळे असतो. thinking_chars हा विभागणीचा तपशील थेट देते. दोन गोष्टी खऱ्या असल्या पाहिजेत: levels बदलल्यावर numbers बदलले पाहिजेत आणि lower level वरही answer योग्य राहिले पाहिजे. तिन्ही runs मध्ये eval_count मधील फरक noise च्या मर्यादेतच असल्यास level दुर्लक्षित केला जात आहे. अशा वेळी वेगळे level name वापरण्याऐवजी तो level पास करणारा runtime वापरा.
Total time ही फक्त अर्धी माहिती आहे. त्यामुळे streaming वापरून आणि पहिला non-empty content chunk मिळताच थांबून पहिल्या answer token पर्यंतचा वेळ मोजा. यासाठी jq आणि bc आवश्यक आहेत.
start=$(date +%s.%N)
curl -sN http://localhost:11434/api/chat -d '{
"model": "qwen3.8:27b",
"messages": [{"role": "user", "content": "Explain what a reverse proxy does, in three sentences."}],
"think": "low",
"stream": true
}' |
while IFS= read -r line; do
if [ -n "$(printf '%s' "$line" | jq -r '.message.content // ""')" ]; then
echo "first answer token after $(echo "$(date +%s.%N) - $start" | bc)s"
break
fi
doneहे low वर run करा आणि पुन्हा max वर run करा. तुम्ही विकत घेत असलेला wait म्हणजे या दोन वेळांमधील फरक. llama.cpp मध्ये हेच numbers response मध्ये परत मिळतात; shell arithmetic ची गरज नसते:
curl -s http://localhost:8080/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{"model": "local", "temperature": 0,
"messages": [{"role": "user", "content": "A pump fills a 4500 litre tank in 25 minutes. A second pump is 40 percent slower. How long do both together take?"}]}' | jq '{
reasoning_chars: (.choices[0].message.reasoning_content // "" | length),
answer_chars: (.choices[0].message.content | length),
predicted_n: .timings.predicted_n,
tok_per_sec: .timings.predicted_per_second
}'हे तुमच्या स्वतःच्या box वर करा. प्रकाशित effort comparison तुमच्या मालकीच्या नसलेल्या hardware वर मोजले गेले होते. तुमचा decode rate token count चे seconds मध्ये रूपांतर करणारा घटक आहे. तुमच्या स्वतःच्या server वर tokens per second मोजणे हा घटक देते: reasoning tokens ला तुमच्या decode rate ने भागल्यावर तुम्ही नुकताच वाढवलेला wait मिळतो.
काय बिघडते
उत्तर मध्येच थांबते किंवा content रिकामे असते, तर thinking भरलेले असते. reasoning मुळे generation limit संपली आहे. Ollama चे num_predict reasoning धरून संपूर्ण generation ची मर्यादा ठरवते. reasoning आधी येत असल्यामुळे high effort वर 512 tokens ची मर्यादा ठेवल्यास उत्तर सुरू होण्यापूर्वीच response संपुष्टात येऊ शकतो. त्या response साठी Ollama "done_reason": "length" नोंदवते. मर्यादा वाढवा किंवा effort कमी करा. num_predict tokens कसे मोजते यामध्ये या परस्परसंवादाचे सविस्तर वर्णन आहे.
Level बदलल्याने काहीही फरक पडत नाही. प्रत्येक level वर token counts समान असतात. Runtime variable पाठवत नाही किंवा template ते वाचत नाही. तुमचा runtime प्रत्यक्षात वापरत असलेला template तपासा; मूळ repository मधील template तपासू नका. llama.cpp मध्ये --jinja आणि --chat-template-kwargs वापरून variable स्वतः लिहावा लागतो, त्यामुळे तो चांगला control ठरतो. तेथे level कार्यरत असेल आणि इतरत्र नसेल, तर model ठीक आहे आणि दुसरा runtime variable टाकून देत आहे.
Level चे नाव नाकारले जाते. Request च्या वेळी template error येणे किंवा server अन्यथा निरोगी असताना पहिल्या message वर failure येणे याचा अर्थ सहसा तुम्ही template मध्ये परिभाषित नसलेला level पाठवला आहे. उदाहरणार्थ, model card मध्ये फक्त low, medium आणि xhigh दिलेले असताना high पाठवणे.
Multi-turn chats प्रत्येक turn ला मंद होतात. जुने reasoning history मध्ये ठेवले जात आहे. Model ते समर्थित करत असल्यास preserve_thinking ला false करा किंवा परत पाठवत असलेल्या messages मधून thinking field काढून टाका. अन्यथा प्रत्येक turn ला prompt processing वाढत जाते, परंतु answers ची लांबी तशीच राहते.
सोपे वाटलेले task low effort वर केल्यास quality कमी होते. काही extraction प्रत्यक्षात extraction नसते. Input मध्ये unit conversion किंवा क्रमाने rule लागू करणे आवश्यक असल्यास ते कमी output असलेले reasoning task असते. संपूर्ण server साठी level वाढवण्याऐवजी त्या एका call साठी level वाढवा.
एकाच वेळी दोन पातळ्यांवर चालवणे
llama.cpp सुरुवातीला level निश्चित करते. त्यामुळे editor आणि nightly batch job दोन्ही सेवा देणाऱ्या मशीनवर दोन ports वर दोन processes चालवावे लागतात आणि प्रत्येक process साठी स्वतंत्र --reasoning-effort आवश्यक असते. दोन processes म्हणजे memory मध्ये weights च्या दोन प्रती ठेवाव्या लागतात, जोपर्यंत jobs वेगवेगळ्या वेळी चालवले जात नाहीत. एका VPS वर सामान्यतः अधिक सोयीची रचना अशी असते: वापरकर्ता ज्या कामाची प्रतीक्षा करत आहे त्यासाठी low effort server आणि कोणीही निरीक्षण करत नसलेल्या कामासाठी नियोजित higher effort run. अनेक वापरकर्ते एकाच स्थानिक model चा वापर करतात तेव्हा काय होते हे येथेही लागू होते: reasoning tokens साठी decode work लागते. त्यामुळे effort वाढवल्यास token count जितक्या प्रमाणात वाढतो, त्याच प्रमाणात तुमची effective concurrency साधारणपणे कमी होते.
FAQ
मी default म्हणून कोणती reasoning effort level वापरावी?
मॉडेलने उपलब्ध करून दिलेल्या सर्वात कमी level पासून सुरुवात करा आणि ज्या tasks मध्ये अपयश दिसले आहे त्यांच्यासाठीच level वाढवा. अनेक thinking models उच्च default level सह release होतात. August 2026 पर्यंत Qwen3.8-27B चे default xhigh, म्हणजे त्याची सर्वोच्च level, आहे. Benchmark tables मध्ये चांगले दिसावे म्हणून हा default निवडलेला असतो; benchmark table वेळेचे शुल्क आकारत नाही. तुमच्या स्वतःच्या hardware वर मात्र seconds मोजावे लागतात. त्यामुळे प्रत्येक request ला लागू होणारी setting ठेवण्याऐवजी higher level प्रति task स्वतंत्रपणे निवडलेली असावी.
Reasoning tokens माझ्या context window मध्ये मोजले जातात का?
होय. ते output मधील सामान्य tokens असतात आणि इतर सर्व सामग्रीसोबत context window मध्ये राहतात. पुढील turn मध्ये ते टिकतात की नाही हे runtime आणि model वर अवलंबून असते. Qwen3.8 च्या card मध्ये preserve_thinking default ने on असल्याचे नमूद केले आहे. त्यामुळे earlier reasoning history मध्ये जतन राहते आणि दीर्घ conversation मध्ये model ने तयार केलेले प्रत्येक scratchpad साठत जाते. ते false वर set करा किंवा replay करत असलेल्या messages मधून thinking field काढून टाका. त्यामुळे prompt processing वाढत राहणे थांबते.
Thinking level बदलल्यावर माझ्या token counts मध्ये फरक का पडत नाही?
ही setting chat template पर्यंत पोहोचत नाही. Level हा template variable आहे. त्यामुळे runtime तो pass करत असेल आणि packaged template तो read करत असेल तरच तो कार्य करतो. काही runtimes original repository मधील Jinja file वापरण्याऐवजी model सोबत स्वतःचा template release करतात. अशा वेळी variable कुठेही error न दाखवता drop होतो. temperature 0 ठेवून समान prompt सर्वात कमी आणि सर्वात जास्त level वर पाठवा आणि eval_count ची तुलना करून हे पडताळा. Counts मध्ये noise पेक्षा जास्त फरक नसेल, तर level ignore होत आहे.
Lower reasoning effort मुळे model कमी अचूक होते का?
हे task वर अवलंबून असते. गृहीत धरण्याऐवजी याचे मोजमाप करणे योग्य आहे. Input मध्ये answer आधीच उपलब्ध असेल, जसे extraction किंवा rewriting मध्ये, तर shorter scratchpad मुळे सामान्यतः काहीही बदलत नाही. Final answer देण्यापूर्वी intermediate step अचूक असणे आवश्यक असेल, जसे multi-step arithmetic किंवा compile होणे आवश्यक असलेल्या code मध्ये, तर shorter scratchpad मुळे accuracy कमी होते. तुमच्या प्रत्यक्ष workload मधील twenty prompts चा set तयार करा, ते दोन levels वर temperature 0 ठेवून run करा आणि wrong answers मोजा. ही संख्या तुमच्या workload साठी विशिष्ट असेल. कोणतीही published table ती संख्या तुम्हाला देऊ शकत नाही.