本地 LLM 推理運算量設定與效能影響解析
解析本地 LLM 推理運算量(Reasoning effort)機制。說明如何透過聊天模板調整思考長度,並分析高運算量對 VPS 硬體效能、生成時間及上下文佔用的實際成本影響。
本地 LLM 的推理運算量變化機制
推理運算量(Reasoning effort)是一項設定,用於指示模型在回答前需思考的時間長度。此設定僅會改變推理區段的長度,不會影響其他部分。磁碟上的權重在各層級皆相同,量化(quantisation)方式亦無差異,且答案皆源自相同的向前傳遞(forward pass)。變動的僅是模型在正式回答前,於自身暫存區(scratchpad)所消耗的 token 數量。
此區別至關重要,原因在於這些 token 的歸屬。在使用託管 API 時,推理 token 會反映在帳單上。但在您自有的 VPS 上,這些 token 的代價體現在您 CPU 或 GPU 的生成時間,以及上下文視窗(context window)內的空間佔用。若將模型設為最高運算量,模型可能會在輸出第一個字之前,將大部分的輸出額度用於推理;在自架硬體上,這意味著回應時間可能從 2 秒拉長至 2 分鐘。
層級的運作位置:聊天模板而非權重
思考模型在輸出最終答案前,會先產生一段推理內容,通常以 <think> 與 </think> 標籤包覆。努力程度(effort level)是一項由模型聊天模板寫入提示詞的指令。該模板是隨模型發布的 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 上代價更高
輸出 Token。 推理 Token 屬於生成內容。它們與答案內容同樣經過解碼迴圈,且受限於硬體效能。假設任務產生 200 個答案 Token 與 4,000 個推理 Token,系統總共生成 4,200 個 Token,但使用者僅能看到其中 200 個。解碼速率取決於記憶體頻寬與 您選擇的量化方式,因此唯一能控制的變數僅剩 Token 總數。
實際等待時間。 使用者必須等待「答案」的第一個 Token 出現,因為在此之前螢幕僅顯示空白或載入圖示。由於推理內容會優先輸出,等待時間約等於推理 Token 總數除以解碼速率,再加上提示詞處理時間。若推理長度加倍,等待時間也會隨之加倍。
上下文。 推理 Token 與其他 Token 一樣會佔用上下文視窗。若開啟 preserve_thinking,第一輪的暫存區塊在第五輪時仍存在於提示詞中,導致提示詞處理速度隨輪次增加而變慢,且視窗會從兩端同時被填滿。調高 num_ctx 以容納內容 會消耗 KV 快取記憶體;在沒有 GPU 的 VPS 上,這會佔用您可能不足的系統 RAM。
何時該提高層級,何時該保持較低層級
若工作內容中,錯誤的中間步驟會導致最終結果失效,則應提高層級。例如:多步驟算術與單位換算、跨多個檔案的編輯規劃、需要編譯的程式碼,以及必須同時滿足多項條件的約束問題。在這些情況下,草稿區(scratchpad)正在執行實際運算,延長草稿區是捕捉模型原本可能犯錯的低成本方式。
若答案已存在於輸入內容中,且任務僅為搬移資料,則應保持較低層級。資料提取、分類、標記、翻譯、改寫、摘要與格式化皆屬此類。此時推理區段多半只是在重述任務,反而會讓模型有空間推翻正確的第一直覺。
對於任何互動式任務,也應保持較低層級。在聊天視窗或編輯器中,您身處於迴圈內,因此能快速獲得並由您修正的答案,優於需要長時間等待的答案。這正是 將程式碼代理指向本機模型 背後真正的權衡考量:代理程式會進行多次小型呼叫,而每一次呼叫都會被課徵推理稅。
如何在 llama.cpp 中設定層級
llama.cpp 會將變數直接寫入模板,這使其成為能確保層級確實送達的執行環境。請將 -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 的詞彙表而非模型本身,因此請僅傳入該清單中列出的名稱:若模板未定義該層級,可能會在請求時引發模板錯誤。--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 是另一種機制。它會以 token 數量限制推理區段,並以 0 立即結束該區段,或以 -1 保持無限制,而非要求模型規劃較短的推理過程。這兩個旗標皆為全伺服器通用。llama-server 不支援將 reasoning_effort 作為單次請求的欄位,因此若要同時提供兩種運算層級,必須在不同埠上執行兩個處理程序。
vLLM 在符合 OpenAI 規範的請求主體中,針對單次請求公開了相同的變數:
{"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 會要求模型提供其支援的最高層級。對於支援此功能的模型,思考(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}推理過程會回傳至 message.thinking,而答案則回傳至 message.content,系統已為您完成拆分。在互動式 ollama run 工作階段中,/set think 與 /set nothink 可切換此功能,無需重新啟動。
請注意其中的差異。Ollama 的詞彙為 low、medium、high 與 max。Qwen3.8 的模板則定義了 low、medium 與 xhigh。必須有某種機制將兩者進行對應,且 Ollama 模型在其標籤內封裝了模板,而非使用原始儲存庫中的 Jinja 檔案,因此您的層級設定是否能成功傳遞至模型,取決於該封裝的模板。請勿預設它一定會生效。測量過程大約需要一分鐘。
如何衡量層級是否確實生效
在多個層級上發送相同的提示詞,並將 temperature 設為 0,接著比較 Token 數量。此處 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 包含所有生成的 Token(含推論過程),因此兩個層級之間的差距幾乎全為推論內容。thinking_chars 可直接提供分割結果。兩件事應成立:數值會隨層級變動,且較低層級的答案應保持正確。若 eval_count 在三次執行中皆處於雜訊範圍內,代表該層級被忽略;此時的解決方案是確保執行環境確實傳遞了該參數,而非更換層級名稱。
總時間僅反映部分狀況,因此請透過串流並在第一個非空的 content 區塊處停止,以衡量至第一個答案 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 與 max 執行。兩者差異即為您所付出的等待時間。在 llama.cpp 中,相同的數值會包含在回應內,無需進行 Shell 算術運算:
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
}'請在您自己的機器上執行此操作。公開的效能比較數據是在非您的硬體上測得的,而您的解碼速率才是將 Token 數量轉換為秒數的關鍵。在您自己的伺服器上測量每秒 Token 數 可提供該數值:推論 Token 數除以您的解碼速率,即為您剛增加的等待時間。
常見問題與故障排除
回答被截斷,或 content 為空但 thinking 已滿。 這是因為推理過程耗盡了生成限制。Ollama 的 num_predict 會限制包含推理在內的總生成長度,且推理優先於回答,因此若將限制設為 512 個 token 且設定高強度推理,可能會在回答開始前就達到上限。Ollama 會針對該回應回報 "done_reason": "length"。請調高限制或降低推理強度。num_predict 如何計算 token 詳細說明了此互動機制。
調整等級後沒有變化。 各等級的 token 數量完全相同。這代表執行環境未傳遞該變數,或是模板未讀取到該變數。請檢查執行環境實際使用的模板,而非原始儲存庫中的模板。使用 --jinja 與 --chat-template-kwargs 的 llama.cpp 會手動寫入該變數,適合作為對照組:若該等級在 llama.cpp 中有效但在其他環境無效,則代表模型本身正常,是其他執行環境遺漏了該變數。
等級名稱被拒絕。 若在請求時發生模板錯誤,或伺服器運作正常但首則訊息即失敗,通常代表您傳入了模板未定義的等級,例如對一個模型卡僅列出 low、medium 與 xhigh 的模型傳入 high。
多輪對話中每一輪的速度都變慢。 舊的推理內容被保留在歷史紀錄中。若模型支援,請將 preserve_thinking 設為 false,或從您回傳的訊息中移除 thinking 欄位。否則,提示詞處理量會隨對話輪數增加,而回答長度卻維持不變。
在您認為簡單的任務上,低強度設定導致品質下降。 部分提取任務並非單純的提取。若輸入內容需要單位轉換或依規則排序,這屬於推理任務,只是輸出較短。請針對該次呼叫調高等級,而非調整整個伺服器的設定。
同時執行兩個層級
llama.cpp 會在啟動時固定層級,因此若要同時執行編輯器與夜間批次作業,需在兩個連接埠上分別執行兩個處理程序,並各自設定 --reasoning-effort。除非將作業錯開執行,否則兩個處理程序意味著記憶體中會有兩份權重副本。在單一 VPS 上,較經濟的做法通常是為即時互動需求提供低負載伺服器,並針對背景作業排程執行高負載運算。當多位使用者共用同一個本機模型時會發生什麼事 的說明同樣適用於此:推理 token 屬於解碼運算,因此提高運算強度會導致有效併發數下降,下降幅度約與 token 數量的增加比例相當。
FAQ
我應該預設使用哪種推理強度等級?
請從模型提供的最低等級開始,僅在觀察到任務失敗時才調高。部分推理模型預設啟用高強度,而 Qwen3.8-27B 在 2026 年 8 月時預設為 xhigh(其最高等級)。該預設值是為了在基準測試表中獲得亮眼數據,但基準測試表不會計算時間成本。在您自己的硬體上,您需要支付時間成本,因此應將較高等級視為針對特定任務的選擇,而非每個請求都繼承的預設設定。
推理 Token 會佔用我的 Context window 嗎?
會。它們是輸出中的普通 Token,與其他內容一同佔用 Context window。它們是否會在下一輪對話中保留,取決於執行環境與模型。Qwen3.8 的說明文件記載了 preserve_thinking(預設開啟),它會將先前的推理過程保留在歷史紀錄中,因此長對話會累積所有產生的草稿內容。將其設為 false,或在重播訊息時移除 thinking 欄位,即可停止 Prompt 處理量的持續增長。
為什麼更改思考等級後,Token 數量沒有變化?
該設定未正確傳遞至 Chat template。等級是一個模板變數,僅在執行環境傳遞該變數且封裝的模板讀取它時才會生效。部分執行環境會使用自帶的模板取代原始儲存庫中的 Jinja 檔案,導致變數在無任何錯誤訊息的情況下被丟棄。您可以透過將 temperature 設為 0,並分別以最低與最高等級發送相同的 Prompt 來驗證,接著比較 eval_count。若兩者數量在誤差範圍內一致,代表該等級設定已被忽略。
較低的推理強度會降低模型準確度嗎?
這取決於任務類型,建議進行實測而非預設。若答案已存在於輸入內容中(例如提取或重寫),較短的草稿通常不會造成影響。若必須先完成正確的中間步驟才能得出最終結果(例如多步驟算術或必須編譯的程式碼),較短的草稿確實會降低準確度。請從您的實際工作負載中建立 20 個 Prompt,將 temperature 設為 0 並以兩種等級執行,接著計算錯誤答案的數量。該數據僅適用於您的工作負載,任何公開的基準測試表都無法提供此資訊。