Local LLM में reasoning effort सेटिंग कैसे काम करती है
Local LLM में reasoning effort सेटिंग का उपयोग करके मॉडल के सोचने के समय को नियंत्रित करें। जानें कि यह सेटिंग कैसे GPU पर generation time और context window को प्रभावित करती है।
Local LLM पर reasoning effort कैसे काम करता है
Reasoning effort एक ऐसी सेटिंग है जो मॉडल को यह बताती है कि उत्तर देने से पहले उसे कितनी देर तक सोचना है। यह केवल reasoning segment की लंबाई को बदलता है, और कुछ नहीं। डिस्क पर मौजूद weights हर स्तर पर समान रहते हैं, quantisation समान रहता है, और उत्तर एक ही forward pass से प्राप्त होता है। जो चीज बदलती है, वह यह है कि मॉडल पहले अपने scratchpad पर कितने tokens खर्च करता है।
यह अंतर महत्वपूर्ण है क्योंकि ये tokens कहाँ खर्च होते हैं, यह मायने रखता है। एक hosted API पर, reasoning tokens का बिल बनता है। आपके अपने VPS पर, इनकी कीमत आपके CPU या GPU पर generation time के रूप में और context window के भीतर जगह के रूप में चुकानी पड़ती है। यदि किसी मॉडल को उसके उच्चतम effort पर छोड़ दिया जाए, तो वह उत्तर का पहला शब्द आने से पहले अपने अधिकांश output को reasoning में खर्च कर सकता है। self-hosted hardware पर, यही अंतर दो सेकंड की प्रतिक्रिया और दो मिनट की प्रतिक्रिया के बीच का होता है।
लेवल कहाँ स्थित है: चैट टेम्पलेट, न कि वेट्स
एक थिंकिंग मॉडल को अंतिम उत्तर देने से पहले एक रीजनिंग सेगमेंट उत्सर्जित करने के लिए प्रशिक्षित किया जाता है, जिसे आमतौर पर <think> और </think> टैग्स में लपेटा जाता है। एफर्ट लेवल एक ऐसा निर्देश है जिसे मॉडल का चैट टेम्पलेट प्रॉम्प्ट में लिखता है। वह टेम्पलेट एक Jinja फाइल है जो मॉडल के साथ आती है। यह reasoning_effort जैसे वेरिएबल को पढ़ता है और प्रत्येक मान के लिए एक अलग सिस्टम-लेवल लाइन रेंडर करता है, और मॉडल को उस लाइन के जवाब में अपने स्क्रैचपैड को छोटा या लंबा करने के लिए प्रशिक्षित किया गया था।
इसके परिणामस्वरूप दो बातें सामने आती हैं। लेवल के नाम मॉडल के होते हैं, न कि आपके रनटाइम के, इसलिए एक मॉडल कार्ड का नाम दूसरे के लिए अर्थहीन हो सकता है। और यदि चेन में कुछ भी मॉडल के चैट टेम्पलेट को किसी जेनेरिक टेम्पलेट से बदल देता है, तो वेरिएबल कभी रेंडर नहीं होता और सेटिंग चुपचाप निष्प्रभावी हो जाती है।
2026-08-20 को जाँचे जाने पर, Qwen3.8-27B मॉडल कार्ड तीन एफर्ट लेवल को डॉक्यूमेंट करता है: low, medium और xhigh, जिसमें xhigh डिफॉल्ट है। इसमें high जैसा कुछ नहीं है। थिंकिंग को स्वयं enable_thinking के साथ स्विच किया जाता है, जो डिफॉल्ट रूप से ऑन रहता है, और कार्ड preserve_thinking को भी डॉक्यूमेंट करता है, जो डिफॉल्ट रूप से ऑन रहता है, और यह बातचीत के इतिहास में पहले के टर्न्स से रीजनिंग को बनाए रखता है। gpt-oss इसके बजाय low, medium और high का उपयोग करता है। कई अन्य परिवार केवल एक बूलियन स्वीकार करते हैं और कुछ नहीं। आपके द्वारा पुल किए गए सटीक वर्जन के लिए कार्ड पढ़ें, क्योंकि ये नाम कोई मानक नहीं हैं। VPS पर 27B मॉडल चलाना पहले आता है। यह पेज इस बारे में है कि उत्तर मिलने के बाद क्या सेट करना है।
VPS पर अधिक effort की लागत अधिक क्यों होती है
Output tokens. Reasoning tokens उत्पन्न किए गए tokens होते हैं। ये उसी decode loop से गुजरते हैं जिससे उत्तर गुजरता है, और उसी गति से चलते हैं जिस गति से आपका hardware उन्हें process कर सकता है। मान लीजिए कि एक कार्य 200 tokens का उत्तर और 4,000 tokens की reasoning उत्पन्न करता है। आपने कुल 4,200 tokens उत्पन्न किए और पाठक ने उनमें से केवल 200 देखे। आपकी decode दर memory bandwidth और आपके द्वारा चुने गए quantisation द्वारा निर्धारित होती है, इसलिए एकमात्र विकल्प token की संख्या को नियंत्रित करना है।
Wall clock. एक उपयोगकर्ता उत्तर के पहले token की प्रतीक्षा करता है, क्योंकि उससे पहले सब कुछ या तो खाली स्क्रीन होती है या एक घूमता हुआ spinner। Reasoning पहले emit की जाती है, इसलिए प्रतीक्षा का समय लगभग reasoning tokens की संख्या को आपकी decode दर से विभाजित करने पर प्राप्त होता है, जिसमें prompt processing का समय भी जुड़ता है। Reasoning की लंबाई दोगुनी करने पर यह प्रतीक्षा समय भी दोगुना हो जाता है।
Context. Reasoning tokens किसी भी अन्य token की तरह context window में जगह घेरते हैं। जब preserve_thinking चालू होता है, तो पहले turn का scratchpad पांचवें turn तक prompt में बना रहता है, इसलिए जैसे-जैसे window दोनों तरफ से भरती है, prompt processing हर turn पर धीमी होती जाती है। इसे रखने के लिए num_ctx बढ़ाना KV cache memory की खपत करता है, जो GPU के बिना किसी VPS पर system RAM होती है, जो शायद आपके पास अतिरिक्त न हो।
स्तर को कब बढ़ाएं और कब कम रखें
इसे उन कार्यों के लिए बढ़ाएं जहां गलत मध्यवर्ती चरण परिणाम को खराब कर सकते हैं: बहु-चरणीय अंकगणित और इकाई रूपांतरण, कई फाइलों में संपादन की योजना बनाना, ऐसा कोड जिसे कंपाइल होना है, और बाधा संबंधी समस्याएं जहां एक उत्तर को एक साथ कई शर्तों को पूरा करना होता है। इनमें scratchpad वास्तविक कार्य कर रहा होता है, और एक लंबा scratchpad उस त्रुटि को पकड़ने का एक सस्ता तरीका है जिसे मॉडल अन्यथा कर देता।
इसे तब कम रखें जब उत्तर पहले से ही इनपुट में मौजूद हो और कार्य केवल उसे स्थानांतरित करना हो। निष्कर्षण (extraction), वर्गीकरण (classification), टैगिंग, अनुवाद, पुनर्लेखन, सारांश और फॉर्मेटिंग सभी इसी श्रेणी में आते हैं। तर्क खंड (reasoning segment) मुख्य रूप से कार्य को दोहराता है, और यह मॉडल को अपनी सही पहली प्रवृत्ति को गलत साबित करने का अवसर देता है।
इसे किसी भी इंटरैक्टिव कार्य के लिए भी कम रखें। चैट बॉक्स या एडिटर में आप लूप में होते हैं, इसलिए एक तेज़ उत्तर जिसे आप सुधार सकें, उस धीमे उत्तर से बेहतर है जिसके लिए आपको प्रतीक्षा करनी पड़े। coding agent को local model पर पॉइंट करने के पीछे यही वास्तविक ट्रेड-ऑफ है: एक एजेंट कई छोटी कॉल करता है, और तर्क का शुल्क (reasoning tax) उनमें से प्रत्येक पर लगाया जाता है।
llama.cpp में level कैसे सेट करें
llama.cpp वेरिएबल को सीधे टेम्पलेट में लिखता है, जो इसे वह रनटाइम बनाता है जहाँ आप यह सुनिश्चित कर सकते हैं कि level पहुँच गया है। -m को उस GGUF की ओर निर्देशित करें जो आपके पास पहले से मौजूद है।
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 मॉडल के अपने चैट टेम्पलेट का उपयोग करता है और वर्तमान बिल्ड्स में डिफ़ॉल्ट रूप से सक्षम है। --reasoning-effort में default, minimal, low, medium, high, xhigh या max स्वीकार किए जाते हैं, जहाँ default का अर्थ है टेम्पलेट के अपने डिफ़ॉल्ट को वैसे ही रहने देना। यह सूची llama.cpp की शब्दावली है न कि मॉडल की, इसलिए केवल वही नाम पास करें जिसे कार्ड सूचीबद्ध करता है: यदि कोई level टेम्पलेट में परिभाषित नहीं है, तो अनुरोध के समय टेम्पलेट त्रुटि हो सकती है। --reasoning-format deepseek रीजनिंग को message.content से बाहर निकालकर message.reasoning_content में ले जाता है, जो इस विभाजन को अगले अनुभाग में मापने योग्य बनाता है।
थिंकिंग को छोटा करने के बजाय उसे बंद करने के लिए, टेम्पलेट वेरिएबल को स्वयं सेट करें:
llama-server -m ./qwen3.8-27b-Q4_K_M.gguf --jinja \
--chat-template-kwargs '{"enable_thinking": false}'--reasoning-budget एक अलग तंत्र है। यह रीजनिंग सेगमेंट को टोकन में सीमित करता है, जिसमें 0 इसे तुरंत समाप्त कर देता है और -1 इसे अप्रतिबंधित छोड़ देता है, बजाय इसके कि मॉडल को छोटी योजना बनाने के लिए कहा जाए। दोनों फ्लैग सर्वर-व्यापी हैं। llama-server reasoning_effort को प्रति-अनुरोध फ़ील्ड के रूप में स्वीकार नहीं करता है, इसलिए एक ही समय में दो effort levels सर्व करने का अर्थ है दो अलग-अलग पोर्ट पर दो प्रोसेस चलाना।
vLLM OpenAI-संगत बॉडी के भीतर, प्रति अनुरोध वही वेरिएबल एक्सपोज़ करता है:
{"model": "Qwen/Qwen3.8-27B",
"messages": [{"role": "user", "content": "Summarise this changelog in two lines."}],
"chat_template_kwargs": {"reasoning_effort": "medium"}}Ollama में level कैसे सेट करें
Ollama का अपना field, think, /api/chat और /api/generate पर मौजूद है। यह true, false, या low, medium, high और max में से किसी एक को स्वीकार करता है, जहाँ max मॉडल द्वारा प्रदान किए जाने वाले उच्चतम स्तर की मांग करता है। जिन मॉडल्स में यह सुविधा है, उनमें Thinking डिफ़ॉल्ट रूप से चालू रहती है।
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}Reasoning message.thinking में वापस आती है और उत्तर message.content में, जो आपके लिए पहले से ही अलग-अलग होते हैं। एक इंटरैक्टिव ollama run सत्र के भीतर, /set think और /set nothink इसे बिना रीस्टार्ट किए टॉगल करते हैं।
अब विसंगति पर ध्यान दें। Ollama की शब्दावली low, medium, high और max है। Qwen3.8 का टेम्प्लेट low, medium और xhigh को परिभाषित करता है। किसी चीज़ को एक से दूसरे पर मैप करना पड़ता है, और एक Ollama मॉडल अपने टैग के भीतर पैक किए गए टेम्प्लेट को ले जाता है, न कि मूल रिपॉजिटरी की Jinja फ़ाइल को, इसलिए यह कि आपका स्तर मॉडल तक पहुँचता है या नहीं, उस पैक किए गए टेम्प्लेट पर निर्भर करता है। यह न मानें कि यह काम कर गया। इसे मापने में लगभग एक मिनट का समय लगता है।
यह कैसे मापें कि लेवल वास्तव में लागू हुआ है या नहीं
एक ही प्रॉम्प्ट को एक से अधिक लेवल पर भेजें, जिसमें temperature को 0 पर रखें, और फिर टोकन काउंट की तुलना करें। यहाँ jq बॉडी बनाता है ताकि आपको मैन्युअल रूप से कोट्स को एस्केप न करना पड़े।
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 उत्पन्न होने वाले प्रत्येक टोकन को दर्शाता है, जिसमें रीजनिंग भी शामिल है, इसलिए दो लेवल के बीच का अंतर लगभग पूरी तरह से रीजनिंग का होता है। thinking_chars आपको सीधे स्प्लिट देता है। दो बातें सही होनी चाहिए: लेवल बदलने पर संख्याएं बदलनी चाहिए, और निचले लेवल पर उत्तर सही रहना चाहिए। यदि eval_count तीनों रन में शोर (noise) के भीतर ही रहता है, तो लेवल को अनदेखा किया जा रहा है। इसका समाधान एक ऐसा रनटाइम है जो इसे पास करे, न कि कोई अलग लेवल नाम।
कुल समय पूरी कहानी का केवल आधा हिस्सा है, इसलिए स्ट्रीमिंग करके और पहले नॉन-एम्प्टी content चंक पर रुककर पहले उत्तर टोकन तक के अंतराल को मापें। इसके लिए 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 पर चलाएं और फिर max पर दोबारा चलाएं। अंतर वह प्रतीक्षा समय है जिसे आप खरीद रहे हैं। llama.cpp पर वही संख्याएं रिस्पॉन्स के भीतर वापस आती हैं, जिसमें किसी शेल अरिथमेटिक की आवश्यकता नहीं होती:
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
}'इसे अपने स्वयं के बॉक्स पर करें। प्रकाशित प्रयास की तुलना ऐसे हार्डवेयर पर की गई थी जो आपका नहीं है, और आपका डिकोड रेट वह शब्द है जो टोकन काउंट को सेकंड में बदलता है। अपने स्वयं के सर्वर पर टोकन प्रति सेकंड मापना आपको वह शब्द देता है: रीजनिंग टोकन को आपके डिकोड रेट से विभाजित करने पर वह प्रतीक्षा समय मिलता है जिसे आपने अभी जोड़ा है।
क्या गलत होता है
उत्तर अधूरा है, या content खाली है जबकि thinking भरा हुआ है। जनरेशन लिमिट reasoning द्वारा समाप्त कर दी गई है। Ollama का num_predict पूरी जनरेशन को सीमित करता है, जिसमें reasoning भी शामिल है, और reasoning पहले आता है, इसलिए high effort पर 512 tokens की सीमा उत्तर शुरू होने से पहले ही प्रतिक्रिया को समाप्त कर सकती है। Ollama ऐसी प्रतिक्रिया पर "done_reason": "length" रिपोर्ट करता है। सीमा बढ़ाएं या effort कम करें। num_predict टोकन की गणना कैसे करता है इस इंटरैक्शन को विस्तार से कवर करता है।
लेवल बदलने से कुछ नहीं होता। टोकन की संख्या हर लेवल पर समान रहती है। या तो रनटाइम वेरिएबल को पास नहीं कर रहा है, या टेम्पलेट इसे पढ़ नहीं पा रहा है। उस टेम्पलेट की जांच करें जिसका उपयोग आपका रनटाइम वास्तव में कर रहा है, न कि वह जो मूल रिपॉजिटरी में है। --jinja और --chat-template-kwargs के साथ llama.cpp वेरिएबल को मैन्युअल रूप से लिखता है, इसलिए यह एक अच्छा कंट्रोल है: यदि लेवल वहां काम करता है और कहीं और नहीं, तो मॉडल ठीक है और दूसरा रनटाइम इसे ड्रॉप कर रहा है।
लेवल का नाम अस्वीकार कर दिया गया है। रिक्वेस्ट के समय टेम्पलेट एरर, या अन्यथा स्वस्थ सर्वर के साथ पहले मैसेज पर विफलता का मतलब आमतौर पर यह है कि आपने ऐसा लेवल पास किया है जिसे टेम्पलेट परिभाषित नहीं करता है, जैसे कि किसी ऐसे मॉडल को high पास करना जिसके कार्ड में केवल low, medium और xhigh सूचीबद्ध हैं।
मल्टी-टर्न चैट हर टर्न पर धीमी हो जाती है। पुरानी reasoning हिस्ट्री में रखी जा रही है। यदि मॉडल इसका समर्थन करता है तो preserve_thinking को false पर सेट करें, या आपके द्वारा वापस भेजे जाने वाले मैसेज से thinking फील्ड को हटा दें। अन्यथा, हर टर्न पर प्रॉम्प्ट प्रोसेसिंग बढ़ती जाती है जबकि उत्तरों की लंबाई समान रहती है।
किसी ऐसे कार्य पर क्वालिटी गिर जाती है जिसे आप सरल समझते थे। कुछ एक्सट्रैक्शन वास्तव में एक्सट्रैक्शन नहीं होते हैं। यदि इनपुट को यूनिट कन्वर्जन या किसी नियम को क्रम में लागू करने की आवश्यकता है, तो यह एक reasoning कार्य है जिसका आउटपुट छोटा होता है। पूरे सर्वर के लिए लेवल बढ़ाने के बजाय उस एक कॉल के लिए लेवल बढ़ाएं।
एक साथ दो स्तरों (levels) को चलाना
llama.cpp स्टार्टअप के समय ही स्तर (level) को निर्धारित कर देता है। इसलिए, यदि एक ही सर्वर पर editor और nightly batch job दोनों चलाने हों, तो दो अलग-अलग ports पर दो processes की आवश्यकता होगी, जिनमें से प्रत्येक का अपना --reasoning-effort होगा। दो processes का अर्थ है memory में weights की दो प्रतियां, जब तक कि आप इन कार्यों को अलग-अलग समय पर न चलाएं। एक VPS पर सस्ता विकल्प आमतौर पर यह होता है कि जिस काम के लिए कोई व्यक्ति प्रतीक्षा कर रहा है, उसके लिए एक low effort server रखा जाए, और जो काम कोई नहीं देख रहा है, उसके लिए एक scheduled higher effort run चलाया जाए। जब कई उपयोगकर्ता एक ही local model साझा करते हैं तो क्या होता है यह यहाँ भी लागू होता है: reasoning tokens का अर्थ है decode का काम, इसलिए effort बढ़ाने से आपकी प्रभावी concurrency (concurrency) लगभग उसी अनुपात में कम हो जाती है जिस अनुपात में token count बढ़ता है।
FAQ
मुझे डिफ़ॉल्ट रूप से किस reasoning effort level का उपयोग करना चाहिए?
सबसे निचले स्तर से शुरुआत करें और केवल उन कार्यों के लिए इसे बढ़ाएं जिनमें आप विफलता देखते हैं। कई thinking models उच्च डिफ़ॉल्ट के साथ आते हैं, और अगस्त 2026 तक Qwen3.8-27B डिफ़ॉल्ट रूप से अपने उच्चतम स्तर xhigh पर सेट रहता है। यह डिफ़ॉल्ट बेंचमार्क टेबल पर अच्छा दिखने के लिए चुना गया है, और बेंचमार्क टेबल समय के लिए शुल्क नहीं लेती है। अपने स्वयं के हार्डवेयर पर आप समय की कीमत चुकाते हैं, इसलिए उच्च स्तर को ऐसा विकल्प बनाएं जिसे आप प्रति कार्य चुनते हैं, न कि वह सेटिंग जिसे हर अनुरोध इनहेरिट करता है।
क्या reasoning tokens मेरी context window में गिने जाते हैं?
हाँ। ये आउटपुट में सामान्य टोकन हैं और बाकी सब चीजों के साथ context window में रहते हैं। क्या वे अगले टर्न पर वहां रहेंगे, यह रनटाइम और मॉडल पर निर्भर करता है। Qwen3.8 का कार्ड preserve_thinking को डॉक्यूमेंट करता है, जो डिफ़ॉल्ट रूप से ऑन रहता है और इतिहास में पिछली reasoning को बनाए रखता है, इसलिए एक लंबी बातचीत में इसके द्वारा उत्पादित हर scratchpad शामिल होता है। इसे false पर सेट करें, या उन संदेशों से thinking फ़ील्ड को हटा दें जिन्हें आप रिप्ले करते हैं, और प्रॉम्प्ट प्रोसेसिंग का बढ़ना रुक जाएगा।
thinking level बदलने से मेरे टोकन काउंट में कोई अंतर क्यों नहीं आता?
सेटिंग चैट टेम्पलेट तक नहीं पहुँच रही है। लेवल एक टेम्पलेट वेरिएबल है, इसलिए यह तभी काम करता है जब रनटाइम इसे पास करे और पैकेज्ड टेम्पलेट इसे पढ़े। कुछ रनटाइम मूल रिपॉजिटरी की Jinja फ़ाइल के बजाय मॉडल के साथ अपना स्वयं का टेम्पलेट शिप करते हैं, और फिर वेरिएबल को बिना किसी त्रुटि के हटा दिया जाता है। इसे साबित करने के लिए, temperature को 0 पर रखकर सबसे निचले और उच्चतम स्तर पर एक ही प्रॉम्प्ट भेजें और eval_count की तुलना करें। यदि काउंट्स शोर (noise) के भीतर मेल खाते हैं, तो लेवल को अनदेखा किया जा रहा है।
क्या कम reasoning effort मॉडल को कम सटीक बनाता है?
यह कार्य पर निर्भर करता है, और इसे मानने के बजाय मापना बेहतर है। जहाँ उत्तर पहले से ही इनपुट में मौजूद है, जैसे कि एक्सट्रैक्शन या रीराइटिंग, वहां छोटा scratchpad आमतौर पर कुछ नहीं बदलता है। जहाँ अंतिम चरण से पहले मध्यवर्ती चरण का सही होना आवश्यक है, जैसे कि मल्टी-स्टेप अंकगणित या ऐसा कोड जिसे कंपाइल होना है, वहां छोटे scratchpad के साथ सटीकता कम हो जाती है। अपने वास्तविक वर्कलोड से बीस प्रॉम्प्ट का एक सेट बनाएं, उन्हें temperature को 0 पर रखकर दो स्तरों पर चलाएं, और गलत उत्तरों की गिनती करें। वह संख्या आपके वर्कलोड के लिए विशिष्ट है, और कोई भी प्रकाशित टेबल आपको यह नहीं दे सकती है।