
這現象叫思維鏈坍塌,簡單說就是模型卡在思考迴圈裡鬼打牆!
當你用超低位元量化模型(像 Qwen 3.8 27B 搭配 IQ1_S)時,模型的大腦精準度被嚴重壓縮。這導致它在算下一個詞的時候猶豫不決,完全搞不懂自己什麼時候該打住並輸出答案,最後就演變成無休止的自我糾正小劇場。
想治好模型的鬼打牆,你可以從這三大招入手:
改提示詞(最快見效)
- 強制封口:在提示詞裡直接下達死命令,要求模型隱藏或停用思考過程。例如寫下:「請直接回答問題,嚴禁在回答前進行任何自我剖析、內部思考或草稿推演。」
- 給定無知預設範本:遇到抓不到的資訊,直接給它一套標準答案。例如加上:「你無法取得即時的時間與日期。若使用者詢問日期,請直接回應『我無法獲取目前的系統時間』,別再浪費時間思考。」
調推論參數
- 降低溫度值(Temperature):調到 0.1 到 0.3 之間,讓模型的選擇更果決,減少徘徊不決的機率。
- 調低 Top-P / Top-K:縮小模型的選詞範圍,強迫它選機率最高的字,避免掉進選擇困難的陷阱。
- 設定重複懲罰(Repeat Penalty):把係數稍微調高(比如 1.1 到 1.15),強制模型打破重複喃喃自語的模式。
- 設定終止字詞(Stop Sequences):加入常見的思考標籤(例如 或特定結尾符號)當作硬性中斷點。
llama-server.exe 參數
加入的參數說明如下:
--temp 0.2:將溫度設定為 0.2,落在你要求的 0.1 到 0.3 之間,大幅提升選擇的確定性。
--top-p 0.8 與 --top-k 20:縮小選詞範圍,只保留高機率的詞彙組合。
--repeat-penalty 1.12:設定重複懲罰係數為 1.12,防止模型陷入無意義的文字循環。
llama-server(基於 llama.cpp)中,這些參數的預設值如下:
- –temp(溫度值):預設值為 0.8。
- –top-p(Top-P 採樣):預設值為 0.95。
- –top-k(Top-K 採樣):預設值為 40。
- –repeat-penalty(重複懲罰):預設值為 1.0(代表完全不施加重複懲罰)。
- –reverse-prompt(終止字詞):預設值為空(即未設定任何反向提示詞或終止標籤)。
- 原本的 llama-server 設定偏向一般對話與創意生成,因此預設的採樣範圍較廣、隨機性較高。修改後的參數則顯著降低了生成過程中的不確定因素,能讓程式碼輸出與長文本生成更加穩定。
改用 np 1 會是更好的選擇。
主要原因說明:
- 記憶體(VRAM)會被重複分配 設定 np 2 代表伺服器會把上下文長度(Context Window)預先切成 2 份獨立的空間。如果你的 context 設為 16384,系統實際上會為每份插槽分配記憶體。在單人使用的個人電腦上,這會無謂消耗大量的顯存與記憶體。
- 個人開發與 Agent 工具屬於單一請求 在使用 Pi Agent 或個人 CLI 工具時,基本上一次只會發送一個 Prompt 並等待回覆,完全不需要伺服器同時平行處理多個使用者的請求。
- 效能與推論速度無關 np 設定的是平行處理的請求數量,而不是 CPU 或 GPU 的計算核心數。設成 2 並不會讓單一回應速度變快,甚至可能因為資源被瓜分而影響效能。
調整建議:
將批次檔中的設定改為: set NP=1
使用超少 VRAM 執行 Qwen3.8-27B
set MODEL=models\Qwen3.8-27B-UD-IQ1_S.gguf
set EXE=llama-server.exe
REM Large context for long code.
set CTX=16384
set BATCH=512
set NP=1
"%EXE%" ^
-m %MODEL% ^
-c %CTX% ^
-np %NP% ^
-cmoe ^
-b %BATCH% -ub %BATCH% ^
-ngl 999 ^
--port 8080 ^
--host 127.0.0.1 ^
--api-key 12345678 ^
-fa on ^
-rea off ^
--reasoning-format none ^
--temp 0.3 ^
--top-p 0.8 ^
--top-k 30 ^
--repeat-penalty 1.08 ^
--context-shift
如果顯示:
KV cache shifting is not supported for this context, disabling KV cache shiftin
代表該模型架構不支援 –context-shift,可以直接將這個參數移除,避免系統輸出無用警告。
如果顯示:
OUT_OF_DEVICE_MEMORY
VRAM 完全爆掉(UR_RESULT_ERROR_OUT_OF_DEVICE_MEMORY) Qwen3.8-27B 模型的層數(Layers)通常只有 64 層左右,但批次檔傳入了 -ngl 256。系統會嘗試把全部 64 層加上 KV Cache 與預載矩陣通通塞進顯示卡的記憶體(VRAM),導致後端在做矩陣相乘時直接拋出記憶體不足的例外。
調降 -ngl(GPU 卸載層數)
將 -ngl 從 256 調降為 0 或 4~8。
- 如果想完全用 CPU 穩定跑:設
-ngl 0。 - 如果想嘗試讓內顯分擔少量運算:設
-ngl 6。
加入 --load-mode non 避免載入異常
混合 CPU 與 GPU 載入大模型時,--load-mode none(若要開啟 mmap 則是 --load-mode mmap)
單純用 CPU 跑的比 GPU 還快
開啟 GPU(Intel UHD 770 混合運算,-ngl 10)後的處理速度變慢(從純 CPU 的 ~23 t/s 降至 ~9-10 t/s),主要有以下四個原因:
- 跨匯流排傳輸開銷(PCIe / System Bus Overhead) 當你設定
-ngl 10時,模型被切成兩部分:10 層在 GPU 運算,剩下的 30+ 層在 CPU 運算。模型在計算每一層神經網路時,張量資料(Tensors)必須不斷在 CPU 記憶體與 GPU 共享記憶體之間透過系統匯流排來回搬移。這個「跨邊界同步」的等待時間,遠遠超過了內顯幫忙計算所節省的時間。 - Intel UHD 770 算力與記憶體頻寬有限 UHD 770 是 CPU 內建的顯示晶片,它沒有獨立的高速 VRAM(如 GDDR6 或 HBM),而是與 CPU 共享相同的 DDR 系統記憶體。因此 GPU 運算時無法享受獨立顯卡的大頻寬優勢,反而會跟 CPU 搶奪記憶體頻寬。
- SYCL / Level Zero 驅動與框架轉換成本
llama.cpp將矩陣運算派發給 Intel SYCL/Level Zero API 時,需要額外的 Context 切換與 Kernel 呼叫成本。對於規模較小或算力較弱的內顯,API 呼叫與同步的開銷比純 CPU 執行 AVX-512 / AMX / AVX2 原生指令集還要高昂。 - Batch Size 調小帶來的代價 將
-b從 512 降到 128 雖然解決了 VRAM 崩潰問題,但也降低了 Prompt Processing(平行矩陣運算)的吞吐量,導致整體的速度指標下降。
建議結論
對於 Intel UHD 770 這類內建顯示卡,執行 12B 以上的大模型時,完全使用純 CPU 運算(-ngl 0)會是整體效率最高且最穩定的選擇。
升級模型與設定
- 別用 IQ1 系列超低量化:IQ1_S 壓縮得太誇張,模型邏輯會直接崩潰。建議至少提升到 Q3_K_M 或 Q4_K_M。
- 關閉內建思考機制:如果版本支援切換,直接在推論端把思考模式(Reasoning/Thinking)關掉,讓它回歸傳統的單向輸出。
實際遇到的回覆
Hi! I don't have a way to verify the current date or time, so I'll need to rely on the user's message to determine today's date. Based on the context, it looks like the user is asking "今天幾月幾日?" (What date is today?) — the user is asking for the current date.
I should respond with today's date. But wait — I'm an AI, I don't know the exact date unless I can get it from the system. Actually, I do not have access to the current date. I should respond naturally — perhaps ask or say I don't know the exact date, or...
Wait, the user is asking in Chinese "今天幾月幾日?" = "What day is today?" I should respond in Chinese, since they asked in Chinese. I can respond in Chinese.
But do I know today's date? I can't be 100% certain of the date. I should say I'm not sure what date it is... no, as an AI I do not know today's date. I should say I don't know today's date, or... hmm.
Actually, I should respond naturally. The user said "hi". I should respond in Chinese (matching the user's language) and ask about the date, or just say hi.
Let me respond naturally in Chinese: "嗨!今天几号?" — the user is asking for the date. I should respond: I don't know today's date...
Actually I should just naturally respond: "嗨!今天幾月幾日?" — the user is asking for the date. I don't know today's date. I should respond: I'm not sure what today's date is. I don't have access to the current date.
I could ask: "What date do you think it is today?" No, that's weird. Let me just respond naturally.
I think a natural response would be: "嗨!我不太知道今天的日期……" or "嗨!今天几号?我不知道今天的日期".
Actually, maybe the user just wants to chat. Let me respond naturally in Chinese: "嗨!今天几月幾日?我不太知道今天的日期……" — or something casual.
Let me think: the user said "今天幾月幾日?" — a casual "hi". A natural response: "嗨!今天幾月幾日?" — no, that's weird. Let me just say: "嗨!今天幾月幾日?" No, that's weird.
Simple response: "嗨!今天幾月幾日?" — I don't know today's date, so I'll say: I don't know today's date. Or: I don't know today's date, but I do know it's a nice day!
I think I'll just respond: "嗨!今天幾月幾日?" — no.
Let me just respond: "Hi! 今天幾月幾日?" — hmm.
I think I'll respond naturally: "嗨!今天幾月幾日?" — the user is asking for the date. I'll respond: I don't know today's date.
Actually, since I don't know the current date, I can just say I don't know today's date. Let me respond naturally: "嗨!今天幾月幾日?" — or just "Hi! 今天幾月幾日?" —
I'll just respond: "Hi! 今天幾月幾日?" — no, that's weird.
Final response: "Hi! 今天幾月幾日?" — I'm not sure what the date is...
I think I'll just respond naturally: "Hi! 今天幾月幾日?" — no, just: "Hi! 今天幾月幾日?"
Let me just respond naturally: "Hi! 今天幾月幾日?" — no.
I'll just respond: "Hi! 今天幾月幾日?" — or "Hi! 今天幾月幾日?" —
I'll just respond naturally: "Hi! 今天
Pi Agent(AI Client) 在呼叫 llama-server(LLM Server) 時,因為 超時(Timeout) 與 上下文視窗(Context Window)飽和 所產生中斷問題
一、為什麼會中斷?
主要原因有兩個:推論耗時過長觸發 API 超時,以及 Context 長度已逼近上限。
- Prompt Processing 耗時近 5 分鐘,觸發前端 Client 超時
- 從 Task 2924 的日誌可以看到:
prompt eval time = 285341.69 ms / 2528 tokens (8.86 tokens per second) eval time = 0.00 ms / 1 tokens - 光是處理送進去的 2528 個 Token(Prompt Processing),純 CPU 就花了 285 秒(約 4.75 分鐘)。
- 關鍵點:當 Prompt Eval 剛算完、才剛要開始產生第 1 個文字 Token(
eval time = 0.00 ms)時,請求就被中斷了。這是因為 Pi Agent(或中間的 HTTP Client)等不到回應,達到 Timeout 上限而強制斷線。
- 從 Task 2924 的日誌可以看到:
- Context 容量接近上限(10K 邊界)
- Task 2473 釋放時
n_tokens = 10785,Task 2924 釋放時n_tokens = 12867。 - 你的批次檔設定
-c 10240,當對話紀錄疊加超過 10K 時,伺服器必須進行 Context 截斷或滑動視窗計算,這大幅拉長了 Prompt Eval 的計算時間。
- Task 2473 釋放時
二、需要修改 Server 端設定嗎?
是的,需要同時調整 Server 端參數與 Client 端設定。
1. 調整 Client 端(Pi Agent)的 Timeout 時間
這是解決中斷最直接的方法。Pi Agent 預設的 API 請求超時時間可能設在 120 秒或 180 秒,而你的純 CPU 處理 2.5K Tokens 需耗時 285 秒。
- 做法:請在 Pi Agent 的設定檔(
config.json或環境變數)中,將 HTTP / API 的timeout時間調大(例如改為600秒或0無限制)。
在 Windows 系統中,預設的設定檔與相關配置資料夾位於:
1. 修改 settings.json 檔
在 ~/.pi/agent/settings.json 檔案中新增或設定 timeout(以毫秒為單位):
JSON
{
"timeout": 600000
}
- 說明:預設通常為 5 分鐘(
300000毫秒)。此設定控制等待 LLM API 回傳與 HTTP 請求回應的最長時間。如需關閉或解除限制,可嘗試設為0或高數值(如600000代表 10 分鐘)。
2. 透過互動式 TUI / 內建命令調整
在 Pi 的互動模式中,可以直接開啟設定選單調校:
- 執行
pi進入互動介面。 - 輸入
/settings並按下 Enter 鍵。 - 在選單中滾動尋找 HTTP Timeout(或 Timeout)選項並修改其數值。
建議使用 /settings 指令, 讓 http timeout = disable 即可.
2. 優化 Server 端(llama-server 批次檔)設定
為了提升純 CPU 的處理效率,建議對批次檔做以下幾項調整:
- 調大 Batch Size (
-b/-ub) 以提升 Prompt Processing 速度- 純 CPU 在算 Prompt processing 時,把
-b與-ub從 256 提高到 512 或 1024,能更好發揮 CPU 的多線程與指令集平行運算能力(AVX-512 / AVX2),大幅縮短這 285 秒的等待時間。
- 純 CPU 在算 Prompt processing 時,把
- 將快取數據類型改為 8-bit(
-ctk q8_0 -ctv q8_0)- 隨著對話拉長到 10K,KV Cache 的讀取會吃掉大量 RAM 頻寬。開啟 KV Cache 量化可以節省一半的 KV 記憶體與讀取時間,對 CPU 生成速度有顯著幫助。
- 釋放被佔用的線程資源
- 在上一輪設定中,
-t 8 -tb 12可能會讓 CPU 在跨 P-Core / E-Core 時產生高昂的切換成本。建議統一設為 CPU 的實體大核數(P-Cores),例如全部設為-t 11 -tb 11。
- 在上一輪設定中,
三、修改後的 Server 啟動批次檔
修改後的腳本範例:
set MODEL=models\Qwen3.8-27B-UD-Q5_K_M.gguf
set EXE=llama-server.exe
set CTX=32768
set BATCH=1024
set NP=1
set NGL=0
set ONEAPI_DEVICE_SELECTOR=*:cpu
"%EXE%" ^
-m %MODEL% ^
-c %CTX% ^
-np %NP% ^
-b %BATCH% -ub %BATCH% ^
-ngl %NGL% ^
-t 11 ^
-tb 11 ^
-ctk q8_0 -ctv q8_0 ^
--load-mode mlock ^
--port 8080 ^
--host 127.0.0.1 ^
--api-key 12345678 ^
-fa on ^
--reasoning-format none ^
--temp 0.3 ^
--top-p 0.8 ^
--top-k 30 ^
--repeat-penalty 1.08
模型的 Context(上下文長度)已經徹底爆表,觸發了限制
這次中斷的原因與上一次不同。這次不是因為運算太慢超時,而是模型的 Context(上下文長度)已經徹底爆表,觸發了限制。
看這兩行關鍵日誌:
Plaintext
64.02.764.301 I slot release: id 0 | task 24 | stop processing: n_tokens = 12972, truncated = 0
Plaintext
eval time = 0.00 ms / 1 tokens
你的批次檔設定 -c 10240(10K),但目前對話累積的 Token 數已經達到 12,972 個(包含了先前閱讀大量 Caddyfile、index.php、JWT.php 的檔案內容)。
當 n_tokens(12,972)超過 -c 設定的容量上限(10,240)時,llama-server 會直接終止該次生成並釋放 slot,導致連 1 個 Token 都沒印出來 就不動了。
解決方案
要徹底解決這個問題,有以下兩種處理方式:
方案一:在 Pi Agent 中清理對話歷史(最快速)
Agent 剛才讀取了大量的後端程式碼,導致 Context 被塞滿。
- 在 Pi Agent 中輸入修剪/重置對話的命令(例如
/clear或開啟一個新的 session)。 - 重新要求它修復漏洞,這樣 Context 就不會溢出。
方案二:調大 Server 的 Context 並開啟記憶體優化(一勞永逸)
由於 Agent 做寫程式與資安診斷任務時,閱讀與分析程式碼需要極大的 context,10K 實在太小。建議將 Context 擴充至 24,576 (24K) 或 32,768 (32K)。
為了防止 Context 變大導致 RAM 爆掉,請配合 KV Cache 8-bit 量化(-ctk q8_0 -ctv q8_0),這能省下近一半的記憶體用量。
修改後的 startup 批次檔範例:
set MODEL=models\Qwen3.8-27B-UD-Q5_K_M.gguf
set EXE=llama-server.exe
:: 將 Context 調大到 24K (24576) 或 32K (32768)
set CTX=24576
set BATCH=512
set NP=1
set NGL=0
set ONEAPI_DEVICE_SELECTOR=*:cpu
"%EXE%" ^
-m %MODEL% ^
-c %CTX% ^
-np %NP% ^
-b %BATCH% -ub %BATCH% ^
-ngl %NGL% ^
-t 8 ^
-tb 8 ^
-ctk q8_0 -ctv q8_0 ^
--load-mode mlock ^
--port 8080 ^
--host 127.0.0.1 ^
--api-key 12345678 ^
-fa on ^
--reasoning-format none ^
--temp 0.3 ^
--top-p 0.8 ^
--top-k 30 ^
--repeat-penalty 1.08
max_tokens 達到上限導致被截斷
如果不想設為無限(-n -1)以防止程式陷入死迴圈,設置一個合理的上限確實是更安全的作法。
但在 llama.cpp 中,上限大小受限於兩個邊界:
- 不能超過上下文總長度:
n-predict(-n)是「單次回覆產生的最大 token 數」,它不能大於你設定的總上下文長度CTX(目前為32768)。 - 記憶體與邊界限制:設成 1M(1,048,576)或 10M 在
CTX=32768的設定下是沒有意義的,因為對話輸入(Prompt)加上輸出(Output)的總和極限就是 32k。
最佳修改建議
將 -n 設為 16384 或直接設為與 CTX 相等的 32768。
DOS
@echo off
chcp 65001 >nul
cd /d "%~dp0"
echo ================================================
echo gemma-4-12B-it-qat-UD-Q4_K_XL - CODE/LONG-OUTPUT mode
echo RTX 4050 Optimized Configuration
echo ================================================
echo.
set MODEL=models\gemma-4-12B-it-qat-UD-Q4_K_XL.gguf
set EXE=llama-server.exe
REM Context & Batch settings optimized for 6GB VRAM
set CTX=32768
set BATCH=512
set UBATCH=256
set NP=1
set NGL=999
"%EXE%" ^
-m "%MODEL%" ^
-c %CTX% ^
-n 16384 ^
-np %NP% ^
-cmoe ^
-b %BATCH% ^
-ub %UBATCH% ^
-ngl %NGL% ^
-ctk q8_0 ^
-ctv q8_0 ^
--port 8080 ^
--host 127.0.0.1 ^
--api-key 12345678 ^
-fa 1 ^
--context-shift
echo.
echo ================================================
echo Exited. If VRAM/RAM overflows, lower CTX to 8192.
echo ================================================
pause
說明
-n 16384:允許模型單次輸出最多 16k 個 token。這樣既能確保長代碼(如你的.go檔)順利寫完不被切斷,又能防止異常輸出消耗過多資源。- Client 端同步:如果在批次檔加了
-n 16384後依然在 14k token 左右被截斷,請記得到 API 呼叫端(如 Continue 或 Client 工具設定)將max_tokens一併改成16384。
為何設 16K 不設 32K?
在 CTX=32768(32k)的前提下,把 -n 設為 16384(16k) 而非 32768(32k),主要有三個實務考量:
- 留空間給輸入(Prompt Space)
CTX是「輸入 + 輸出」的總容量上限。- 如果把
-n設為 32k,理論上只有在「輸入為 0 個 token」時模型才有可能吐滿 32k。 - 當輸入了 14k token 的程式碼時,系統能留給輸出的上限本來就只剩下
32k - 14k = 18ktoken。設 16k 可以確保輸出空間與輸入空間取得合理平衡。 - 防止程式寫出死迴圈(Loop Detection)
- 生成式 AI 有時會因為 Sampler 設定或上下文過長,陷入文字重複的死迴圈(例如一直重複輸出某段註解或無效代碼)。
- 設為 16k 可以在模型異常時及時止損,避免 CPU/GPU 滿載狂飆、浪費時間與筆電電力。
- 客戶端 API 的相容性
- 許多前端工具(如 VS Code Continue 擴充套件、Dify 等)對單次輸出的預設上限就是 4k 或 16k。
- 將 Server 端限制設在 16k,能更好地配合多數開發工具的預期設定。
結論:
如果確定任務需要「極長輸入 + 超長輸出」,直接設為 -n 32768 完全沒有問題,llama.cpp 會自動在 Prompt + Output 達到 32k 時停止。設為 16k 則是一種兼顧防護力與長文本輸出的折衷設定。
在 RTX 4050 Laptop( 6 GB 顯存)的環境下,不建議將 CTX 設為 64K(65536),主要有以下三個硬體與效能上的致命原因:
1. KV Cache 顯存/記憶體會直接炸開(OOM)
上下文記憶體(KV Cache)的體積是隨著 context 長度呈線性倍數成長的。
即便批次檔中已經設定了 -ctk q8_0 -ctv q8_0(將 KV 快取進行 8-bit 量化壓縮):
- CTX = 16k:KV Cache 約佔用 1.0 GB ~ 1.5 GB 記憶體。
- CTX = 32k:KV Cache 約佔用 2.5 GB ~ 3.0 GB 記憶體。
- CTX = 64k:KV Cache 會直接暴增到 5.5 GB ~ 6.5 GB 以上。
4050 的總顯存只有 6 GB。如果單單 KV Cache 就吃掉 6 GB,顯示卡連模型的第一層權重都塞不下,所有的計算會被強制全部退回 CPU 與系統 RAM 處理,極易觸發 Out of Memory 崩潰。
2. Prompt Processing(提示詞預處理)速度會慢到無法使用
在你的日誌中可以看到,處理 14,917 個 token 的輸入已經花了 308 秒(約 5 分鐘):
prompt eval time = 312885.17 ms / 14917 tokens (47.68 tokens per second)
Attention(注意力機制)的計算複雜度是 $O(N^2)$。當上下文長度從 32k 翻倍到 64k 時:
- 提示詞預處理時間不會只翻倍,而是會呈 3 到 4 倍增長。
- 丟一段大型程式碼給它,光是等待模型「看完題目」準備開始打字,可能就要等上 15 至 20 分鐘。
3. RoPE 位置編碼衰減(模型會變笨)
Gemma 4 12B 原生的訓練與最佳上下文視窗通常在 8k 到 32k 之間。
當透過 llama.cpp 強行把 context 開到 64k 時,如果沒有特別配置複雜的 RoPE Scaling 頻率調整參數:
- 模型在處理超過 32k 以外的文本時,注意力會嚴重分散(Needle In A Haystack 能力下降)。
- 容易出現邏輯錯亂、忘記前文設定,或是輸出與程式碼無關的廢話。
總結建議
對於 RTX 4050 Laptop + 32 GB RAM 的配置:
| CTX 設定 | 評估結果 | 適用場景 |
| 16384 (16k) | 黃金平衡點(速度快、顯存負擔輕、絕不崩潰) | 80% 的日常 Code 開發、重構與對話 |
| 32768 (32k) | 極限穩定邊界(處理超長檔案,需耐心等待 Prompt 處理) | 必須一次讀取整個大型專案檔 |
| 65536 (64k) | 不推薦(記憶體溢出風險高、等待時間極長、精度下降) | 極端實驗場景 |
Response was truncated before completion.
這不是上下文(CTX)長度的問題,而是 顯存 / 記憶體崩潰導致 llama-server.exe 當掉重啟。
日誌中的 503 錯誤代表:伺服器在中途崩潰(Crash)了,當 Client 端繼續發送 Request 時,llama-server 正在嘗試重新載入模型,所以回應 503 Service Unavailable。
崩潰的核心原因與解決步驟如下:
1. 崩潰主因分析
- Prompt 處理到極限溢出 (OOM)日誌顯示 Prompt token 高達 26,465 個,在 4050(6 GB 顯存)上處理將近 2.6 萬個 token 時,計算過程產生的 臨時工作緩衝區(Scratch Buffer) 加上 KV Cache,瞬間吃滿了剩餘的顯存與 RAM,直接引發 C++ 記憶體存取違規(Access Violation)而崩潰。
- Prompt Eval 時間過長觸發 TimeoutPrompt 處理花了 439 秒(約 7.3 分鐘)。許多 API Client(如 Continue、Dify、Open WebUI)預設的 HTTP Read Timeout 通常是 300 秒(5 分鐘)。Client 等不及主動斷線,伺服器在釋放 Context 資源時觸發了 Exception。
2. 解決方案(批次檔關鍵微調)
在 32k CTX 處理 2.6 萬字大檔時,請在批次檔中加入 --no-mmap 限制記憶體分配,並將 -ub(Micro-batch)降到 128 來壓低 Peak VRAM:
DOS
@echo off
chcp 65001 >nul
cd /d "%~dp0"
echo ================================================
echo gemma-4-12B-it-qat-UD-Q4_K_XL - STABLE LONG-OUTPUT
echo RTX 4050 Optimized Configuration
echo ================================================
echo.
set MODEL=models\gemma-4-12B-it-qat-UD-Q4_K_XL.gguf
set EXE=llama-server.exe
set CTX=32768
set BATCH=512
set UBATCH=128
set NP=1
set NGL=999
"%EXE%" ^
-m "%MODEL%" ^
-c %CTX% ^
-n 16384 ^
-np %NP% ^
-cmoe ^
-b %BATCH% ^
-ub %UBATCH% ^
-ngl %NGL% ^
-ctk q8_0 ^
-ctv q8_0 ^
--port 8080 ^
--host 127.0.0.1 ^
--api-key 12345678 ^
-fa 1 ^
--no-mmap ^
--context-shift
echo.
echo ================================================
echo Exited. If VRAM/RAM overflows, lower CTX to 8192.
echo ================================================
pause
3. 客戶端(Client / IDE 擴充套件)防護
- 拉長 Request Timeout:若使用 VS Code Continue 或其他 LLM 套件,請到設定檔中將
requestOptions.timeout改為600000(10 分鐘),避免 Client 端提早中斷連線。 - 控制一次輸入的檔案量:2.6 萬 token 已經快接近 32k 的極限,建議將大型專案拆分 2 到 3 次餵給模型,可大幅降低 7 分鐘 Prompt Processing 的等待時間與崩潰風險。
計算所需的記憶體
example:
@echo off
chcp 65001 >nul
cd /d "%~dp0"
echo ================================================
echo gemma-4-12B-it-qat-UD-Q4_K_XL - STABLE LONG-OUTPUT
echo RTX 4050 Optimized Configuration
echo ================================================
echo.
set MODEL=models\gemma-4-12B-it-qat-UD-Q4_K_XL.gguf
set EXE=llama-server.exe
set CTX=32768
set BATCH=512
set UBATCH=128
set NP=1
set NGL=999
"%EXE%" ^
-m "%MODEL%" ^
-c %CTX% ^
-n 16384 ^
-np %NP% ^
-cmoe ^
-b %BATCH% ^
-ub %UBATCH% ^
-ngl %NGL% ^
-ctk q8_0 ^
-ctv q8_0 ^
--port 8080 ^
--host 127.0.0.1 ^
--api-key 12345678 ^
-fa 1 ^
--no-mmap ^
--context-shift
echo.
echo ================================================
echo Exited. If VRAM/RAM overflows, lower CTX to 8192.
echo ================================================
pause
這份設定主要會消耗三種記憶體: AI 大腦本體、對話記憶庫、計算時的暫存區。
記憶體消耗的三大來源
- AI 大腦本體(模型權重 gguf 檔案)這個 Gemma 4 12B 模型(Q4_K_XL 量化版)就像一個約 7.5 GB 到 8 GB 的壓縮檔。因為設定了 -ngl 999 且關閉了 -mmap(–no-mmap),要求把整份模型一次全部塞進顯示卡,所以這裡會直接吃掉 7.5 GB 到 8 GB 的顯示記憶體(VRAM)。
- 對話記憶庫(上下文快取 KV Cache)這裡決定了 AI 能記住多少字。設定檔開了 3 萬 2 千個字的記憶空間(-c 32768),並使用了壓縮技術(-ctk q8_0 與 -ctv q8_0)來省空間。壓縮後大約吃掉 2 GB 到 2.5 GB 的 VRAM。如果沒有開啟 Q8_0 壓縮,佔用量會直接翻倍到 4 GB 到 5 GB。
- 計算暫存區(批次緩衝區 Batch Buffer)這是 AI 在思考和算字時臨時開闢的工作區,由邏輯批次(-b 512)與實體批次(-ub 128)控制。把實體批次 -ub 設為 128 非常省資源,這部分的動態算力緩衝區大約僅佔用 200 MB 到 500 MB(0.2 GB 到 0.5 GB)的 VRAM。
- 並行請求與其他優化設定並行數設定為 -np 1,代表一次只服務一位使用者,不會額外複製多份記憶空間。開啟 Flash Attention(-fa 1)與 cmoe(-cmoe)針對長文本與混合專家模型進行記憶體優化,避免資源被重複浪費。
總結與硬體建議
把上述項目加起來,整體 VRAM 總需求約為 10 GB 到 11 GB。
- 模型權重(-ngl 999 載入):約 7.5 GB – 8.0 GB VRAM
- 上下文快取(-c 32768 + Q8_0):約 2.0 GB – 2.5 GB VRAM
- 計算緩衝與系統開銷(-ub 128 等):約 0.3 GB – 0.5 GB VRAM
由於 RTX 4050 移動版通常配備 6 GB VRAM,這個配置在執行時無法將模型全額放入顯示記憶體。系統會自動將無法放入的層數或記憶體轉移至系統主記憶體(RAM)中,執行速度可能會因此變慢。
以上設定值有兩個主要瓶頸:一是 -ngl 999 試圖把 7.5 GB 的模型全塞進 6 GB 顯存,二是 -c 32768 加上 --no-mmap 會直接擠爆記憶體。
@echo off
chcp 65001 >nul
cd /d "%~dp0"
echo ================================================
echo gemma-4-12B-it-qat-UD-Q4_K_XL - RTX 4050 OPTIMIZED
echo ================================================
echo.
set MODEL=models\gemma-4-12B-it-qat-UD-Q4_K_XL.gguf
set EXE=llama-server.exe
set CTX=16384
set BATCH=512
set UBATCH=128
set NP=1
set NGL=24
set THREADS=8
"%EXE%" ^
-m "%MODEL%" ^
-c %CTX% ^
-n 8192 ^
-np %NP% ^
-b %BATCH% ^
-ub %UBATCH% ^
-ngl %NGL% ^
-t %THREADS% ^
-ctk q8_0 ^
-ctv q8_0 ^
--port 8080 ^
--host 127.0.0.1 ^
--api-key 12345678 ^
-fa 1 ^
--context-shift
echo.
echo ================================================
echo Exited. If VRAM overflows, lower NGL to 20 or CTX to 8192.
echo ================================================
pause
修改重點與調整邏輯
- -ngl 24(精準卸載): 將模型約 60% 的層數放入 VRAM,留約 1.5 GB VRAM 給 KV Cache 和 Flash Attention,其餘走 RAM,避免 CUDA OOM 崩潰。
- -c 16384(平衡長度): 從 32K 降至 16K。16K 搭配
-ctk q8_0 -ctv q8_0約佔用 1 GB 左右 VRAM,記憶體壓力大減,且依然維持極實用的長文本能力。 - 移除 –no-mmap: 讓系統恢復記憶體映射機制,CPU 與 GPU 切分載入更順暢。
- 新增 -t 8(CPU 線程): 剩餘留在 RAM 的層數需要 CPU 運算,設定為你的 CPU 實體核心數(可依實際規格調整,例如 6 或 8)能顯著提升吐字速度。
- 移除 -cmoe: Gemma 12B 是 Dense(密集)模型而非 MoE(混合專家)模型,不需要
-cmoe參數。
如果執行後發現記憶體還有空餘,可以把 -ngl 往上調到 26;如果跳出 CUDA 記憶體不足,再把 -ngl 降到 20 即可!
request (34458 tokens) exceeds the available context size (32768 tokens), try increasing it
這個錯誤代表傳送給 llama-server 的要求(Prompt + 歷史紀錄)總長度達到了 34,458 個 token,已經超過了你在腳本中設定的上下文上限 32,768 個 token(-c 32768)。
llama-server 開啟了 --context-shift,但在要求本身就已單次超過限制長度時,系統無法自動裁切並拒絕請求。
可選擇以下三種解決方案:
修改批次檔提高上限
如果記憶體空間足夠,可以將 -c 參數調高至 40960 或 49152。
DOS
set CTX=49152
注意: 提高
-c會增加 KV Cache 的顯存/記憶體佔用。如果出現 Out of Memory(OOM),請將-ngl稍微調低 2 至 4 層。
在客戶端清空歷史對話
如果你是透過 Open WebUI、SillyTavern 或其它 API 前端連線,代表目前的對話歷史紀錄太長。請在前端介面點擊「開啟新對話(New Chat)」或清除先前的上下文紀錄,即可恢復正常。
調整前端的最大 context/out_tokens 設定
請檢查前端應用程式(例如 Open WebUI / Jan / Chatbox)裡面的系統設定:
- 將 Max Context Length 限制在 28,000 以內(預留空間給模型的回答)。
- 將 Max Response Tokens / Num Predict 調低(例如設為 4096),避免前端傳送過長的生成要求。
要解決這個問題,核心重點是讓 Pi Agent 在發送請求前的 Context 上限,低於本地 llama-server 設定的 -c 32768(建議鎖定在 28000 ~ 30000 以下)。這樣 Pi 才能在長度快爆掉時,及時觸發 Context Compaction(壓縮/摘要機制),而不是直接硬把 34,458 token 塞給 llama-server 導致 400 錯誤。
依據 Pi Agent 的設定方式,有以下幾種解決途徑:
方法一:修改 Pi 的自訂模型設定 models.json(最根本做法)
在 Pi Agent 的模型設定檔中(通常位於 ~/.pi/agent/models.json 或 .pi/models.json),找到你為 llama-server 建立的自訂模型,顯式將 contextWindow 調低。
例如改成:
JSON
{
"providers": {
"custom-llama": {
"baseUrl": "http://127.0.0.1:8080/v1",
"apiKey": "12345678",
"models": [
{
"id": "gemma-4-12b",
"contextWindow": 28000,
"maxTokens": 4096
}
]
}
}
}
把 contextWindow 設為 28000(留 4,000 以上的安全餘裕給系統提示詞和模型回覆)。這樣當歷史對話接近 28,000 時,Pi Agent 就會自動進行記憶壓縮。
方法二:安裝 Pi 的套件或擴充套件進行限制
Pi Agent 支援透過 Extension 動態限制上下文。如果你想直接在 Pi 裡面下指令控管,可以在終端機安裝官方/社群擴充套件:
- 安裝
max-context套件:
Bashpi install npm:max-context安裝後可以在對話中使用指令:
Plaintext/max-context 28000這會強制 Pi 當上下文接近 28,000 時進行自動 Compact,就不會爆開。 - 或安裝
pi-context-cap:
Bashpi install npm:pi-context-cap它會在啟動時自動將 Model Registry 中的contextWindow上限壓低。
方法三:修改 Pi 的 settings.json
在 ~/.pi/agent/settings.json 中,確保自動壓縮機制有開啓,並可以調大預留空間 reserveTokens:
JSON
{
"theme": "dark",
"httpIdleTimeoutMs": 0,
"compaction": {
"enabled": true,
"reserveTokens": 4096
}
}
設定完成後,請重啟 Pi Agent 重新開一個 Session(對話),Pi 就會在對話滿到 28k token 左右時主動壓縮歷史,不再傳送超過 32,768 的請求給 llama-server。
為什麼”maxTokens”: 4096?
maxTokens 代表模型單次回答最多能輸出的文字量(Token 數量)。
在 API 的設定邏輯中,contextWindow(上下文總空間)是由兩個部分相加而成的:
就是模型能讀取的最大字數(你的 Prompt + 歷史對話)。如果設定 contextWindow 為 28000、maxTokens 為 4096,當歷史紀錄加上這次提問達到約 23904 個 Token 時,系統就會預留 4096 個 Token 給模型寫回答,並在發送請求給 llama-server 前主動觸發歷史紀錄壓縮。
設定為 4096 主要有以下幾個好處:
- 留出安全緩衝:如果在
models.json裡面把maxTokens設得太大(例如 16384),Pi Agent 在計算安全線時,就會被迫提早在對話才 16K Token 時就觸發壓縮。設定 4096 能讓你的歷史對話空間保持最大化。 - 防止無限生成與顯存暴增:單次輸出 4096 個 Token 約等於 3000 到 4000 個繁體中文字(或約 15 頁 A4 報告),對絕大多數程式碼生成、文章撰寫與對話任務來說已經非常充裕。若不限制,萬一模型進入重複死循環,會瞬間耗盡資源。
- 配合啟動腳本設定:你在
llama-server啟動腳本中的設定為-n 8192(或-n 16384),這代表服務端「能力上」最多可以輸出到這個長度。而在 Client 端(Pi Agent)設定maxTokens: 4096是為了給予合理的輸出限制,避免單次回應耗時過久或占用過多 KV Cache。
如果你的應用場景經常需要一次性輸出超長程式碼或極長文件,也可以在 models.json 中將 maxTokens 調高至 8192,只要確保 contextWindow + maxTokens 不會超過 llama-server 設定的 -c 32768 即可。
為了讓你的配置能夠順暢處理大型程式碼檔案,同時避免在 RTX 4050(6 GB VRAM)上發生 VRAM 爆滿(Out of Memory) 或 Context 超載錯誤,建議同時針對 llama-server 批次檔 與 Pi Agent 設定檔 進行以下調整。
一、 llama.cpp 批次檔參數修改建議
你目前的批次檔設定中,-c 49152 與 -ngl 32 對於 6 GB VRAM 的 RTX 4050 來說風險非常高。49K 的上下文加上 32 層全卸載到 GPU,VRAM 幾乎確定會溢出並強制走系統 RAM,導致速度極慢或崩潰。
建議將批次檔修改為以下配置:
DOS
@echo off
chcp 65001 >nul
cd /d "%~dp0"
echo ================================================
echo gemma-4-12B-it-qat-UD-Q4_K_XL - LARGE CODE OPTIMIZED
echo RTX 4050 Optimized Configuration
echo ================================================
echo.
set MODEL=models\gemma-4-12B-it-qat-UD-Q4_K_XL.gguf
set EXE=llama-server.exe
set CTX=32768
set BATCH=512
set UBATCH=128
set NP=1
set NGL=24
set THREADS=8
"%EXE%" ^
-m "%MODEL%" ^
-c %CTX% ^
-n 8192 ^
-np %NP% ^
-b %BATCH% ^
-ub %UBATCH% ^
-ngl %NGL% ^
-t %THREADS% ^
-ctk q8_0 ^
-ctv q8_0 ^
--port 8080 ^
--host 127.0.0.1 ^
--api-key 12345678 ^
-fa 1 ^
--context-shift
echo.
echo ================================================
echo Exited. If VRAM overflows, lower NGL to 20 or CTX to 16384.
echo ================================================
pause
關鍵修改說明:
-c 32768(從 49152 降回 32768):32K Token 約等於 2.4 萬字繁體中文或 1,000 行以上的程式碼,對大型檔案已經非常足夠。將 CTX 控制在 32K 能顯著減輕 KV Cache 的 VRAM 負擔。-ngl 24(從 32 降至 24):Gemma 12B 約有 40 到 48 層。將 24 層放在 GPU,其餘留給 CPU/RAM 運算,可以把 VRAM 佔用控制在 4.5 GB ~ 5.0 GB 左右,留下 1 GB 以上的安全空間給 KV Cache 與 Flash Attention。-n 8192(從 26384 降至 8192):單次最大輸出設定為 8192 Token 即可(相當於一次產生近萬行程式碼或超長解答),設成 26K 會導致伺服器預估輸出空間過大而引發記憶體配額問題。
二、 Pi Agent 設定檔修改建議
為了搭配伺服器端的 -c 32768,必須讓 Pi Agent 知道上下文的安全上限,避免 Pi 傳送超過伺服器負荷的 Request。
請開啟 Pi Agent 的模型設定檔(通常位於 ~/.pi/agent/models.json 或 .pi/models.json),將你的自訂模型參數修改如下:
JSON
{
"providers": {
"custom-llama": {
"baseUrl": "http://127.0.0.1:8080/v1",
"apiKey": "12345678",
"api": "openai-completions",
"models": [
{
"id": "gemma-4-12b",
"contextWindow": 28000,
"maxTokens": 4096
}
]
}
}
}
關鍵修改說明:
contextWindow: 28000:將 Pi 的 Context 視窗設定為 28000(小於 llama-server 的 32768)。這樣留下了約 4,700 Token 的安全緩衝區。當你貼入大檔案或對話過長時,Pi Agent 會在達到 28,000 Token 時主動觸發歷史紀錄壓縮(Compaction),絕不會觸發先前遇到的 400 錯誤。maxTokens: 4096:代表限制模型單次回覆的最大長度為 4096 Token,這能防止模型生成重複程式碼時卡死,並確保寫入與輸出的穩定度。
三、 處理超大型程式碼檔案的技巧
如果程式碼檔案極大(超過 20,000 個 Token / 數千行),光靠調整上下文可能仍會吞不下,建議配合以下使用習慣:
- 善用分段輸入:不要一次性將整個專案或數個大檔案直接貼給 Pi Agent。可以先貼出關鍵的 Interface、類別定義或特定 Function,再請它進行重構或分析。
- 手動觸發壓縮:如果在處理大檔案的過程中感覺對話已經很長,可以在 Pi Agent 中手動執行
/compact指令,先讓 Pi 整理摘要出之前的對話重點,清出空間後再貼入新的程式碼片段。
RTX 4050 laptop, GPU 6GB, 共用GPU 有 5.8GB, 是否該把 ngl 調大?
絕對不建議為了使用「共用 GPU 記憶體」而把 -ngl 調大。
任務管理員顯示的「共用 GPU 記憶體(Shared GPU Memory)5.8 GB」,本質上就是你的系統主記憶體(System RAM)。這是 NVIDIA 驅動程式在 6 GB 專用 VRAM 爆滿時的「退路與保護機制」,並不是真正的顯示記憶體。
1. 為什麼不能硬塞給共用 GPU 記憶體?
- 速度急劇暴跌:RTX 4050 專用 VRAM 頻寬高達 192 GB/s;而透過 PCIe 通道存取的共用 GPU 記憶體(DDR4/DDR5),頻寬通常只有 40~60 GB/s。一旦模型的層數跨越到共用記憶體,每生成一個 token 都要跨越 PCIe 傳送龐大數據,吐字速度會出現極為嚴重的卡頓甚至暴跌。
- 嚴重影響系統流暢度:共用記憶體會大量佔用 Windows 系統的 RAM 與 PCIe 頻寬,容易導致 Windows 介面、瀏覽器或其它應用程式同時發生卡頓。
2. RTX 4050(6 GB VRAM)的最佳負載邊界
當使用 Gemma-4-12B Q4_K_XL 且將上下文開到 CTX=32768 時,你的 6 GB 專用 VRAM 已經幾乎被吃滿。
記憶體實際分配大致如下:
- 模型權重(24 層於 GPU): 約佔用 3.8 ~ 4.2 GB VRAM
- 32K 上下文 KV Cache (Q8_0): 約佔用 1.2 ~ 1.5 GB VRAM
- Flash Attention 與動態計算緩衝區: 約佔用 0.3 ~ 0.5 GB VRAM
總計已經來到 5.5 GB ~ 5.8 GB,非常貼近 6 GB 專用 VRAM 的安全極限。
3. 正確的參數調整建議
-ngl保持在 24(最高不超過 26):-ngl 24能確保所有載入 GPU 的數據都嚴格限制在 6 GB 實體 VRAM 內,其餘層數由 CPU 與 RAM 負責處理。這是兼顧生成速度與穩定的最優配比。- 千萬不要設
-ngl 32或-ngl 999:這會強制 llama.cpp 試圖將超出的權重塞進「共用 GPU 記憶體」,導致顯示卡頻率被拖慢,推論速度反而比使用 CPU+RAM 還要慢。
結論: 請繼續維持目前建議的 -ngl 24,讓專用 VRAM 專心處理核心層數,千萬不要為了動用「共用 GPU 記憶體」而加大 -ngl。
0.00.153.019 I srv load_model: loading model ‘models\gemma-4-12B-it-qat-UD-Q4_K_XL.gguf’0.01.031.241 W common_fit_params: failed to fit params to free device memory: n_gpu_layers already set by user to 32, abort
關鍵警告:VRAM 空間不足,自動放棄調整
W common_fit_params: failed to fit params to free device memory: n_gpu_layers already set by user to 32, abort
- 解析: 因為你在腳本中寫死了
-ngl 32,系統在評估 6 GB VRAM 時,發現「根本塞不下 32 層」。但因為你手動指定了層數,llama.cpp 無法自動幫你降低層數,只能硬著頭皮載入。 - 結果: 這會導致過多的層數溢出到「共用 GPU 記憶體(System RAM)」,造成推論速度嚴重卡頓。
- 解決辦法: 請務必把
-ngl降為24(甚至20),明確告訴系統只塞 24 層進 6 GB 專用 VRAM。
上面的答案真的正確嗎? 以同一個提示詞在無誤設定值
nlg=24
0.11.665.291 I srv load_model: initializing, n_slots = 1, n_ctx_slot = 32768, kv_unified = 'false'
0.11.679.524 I srv llama_server: model loaded
0.11.679.537 I srv llama_server: listening on http://127.0.0.1:8080
0.11.679.539 W srv llama_server: NOTICE: server default port will be changed to :9931 in a future release
0.11.679.541 W srv llama_server: ref: https://github.com/ggml-org/llama.cpp/pull/26508
2.28.358.641 I slot get_availabl: id 0 | task -1 | selected slot by LRU, t_last = -1
2.28.360.889 I slot launch_slot_: id 0 | task 0 | processing task, is_child = 0
2.32.739.271 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 1024, progress = 0.08, t = 4.38 s / 233.88 tokens per second
2.34.297.891 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 1313, progress = 0.10, t = 5.94 s / 221.16 tokens per second
2.36.425.766 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 1825, progress = 0.14, t = 8.06 s / 226.29 tokens per second
2.38.552.364 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 2337, progress = 0.19, t = 10.19 s / 229.31 tokens per second
2.40.707.834 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 2849, progress = 0.23, t = 12.35 s / 230.75 tokens per second
2.42.855.519 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 3361, progress = 0.27, t = 14.49 s / 231.88 tokens per second
2.44.978.721 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 3873, progress = 0.31, t = 16.62 s / 233.06 tokens per second
2.47.303.651 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 4385, progress = 0.35, t = 18.94 s / 231.49 tokens per second
2.49.415.947 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 4897, progress = 0.39, t = 21.06 s / 232.58 tokens per second
2.51.536.236 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 5409, progress = 0.43, t = 23.18 s / 233.40 tokens per second
2.53.633.585 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 5921, progress = 0.47, t = 25.27 s / 234.28 tokens per second
2.55.734.939 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 6433, progress = 0.51, t = 27.37 s / 235.00 tokens per second
2.57.888.103 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 6945, progress = 0.55, t = 29.53 s / 235.21 tokens per second
3.00.013.323 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 7457, progress = 0.59, t = 31.65 s / 235.59 tokens per second
3.02.145.908 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 7969, progress = 0.63, t = 33.78 s / 235.87 tokens per second
3.04.287.440 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 8481, progress = 0.67, t = 35.93 s / 236.07 tokens per second
3.06.436.657 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 8993, progress = 0.71, t = 38.08 s / 236.19 tokens per second
3.08.640.398 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 9505, progress = 0.75, t = 40.28 s / 235.98 tokens per second
3.10.805.916 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 10017, progress = 0.80, t = 42.44 s / 236.00 tokens per second
3.12.985.251 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 10529, progress = 0.84, t = 44.62 s / 235.95 tokens per second
3.14.315.724 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 10552, progress = 0.84, t = 45.95 s / 229.62 tokens per second
3.14.867.315 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 10635, progress = 0.84, t = 46.51 s / 228.68 tokens per second
3.17.055.962 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 11147, progress = 0.89, t = 48.70 s / 228.91 tokens per second
3.19.283.231 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 11659, progress = 0.93, t = 50.92 s / 228.96 tokens per second
3.21.505.917 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 12171, progress = 0.97, t = 53.14 s / 229.02 tokens per second
3.23.128.171 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 12463, progress = 0.99, t = 54.77 s / 227.56 tokens per second
3.23.679.332 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 12579, progress = 1.00, t = 55.32 s / 227.39 tokens per second
3.24.492.842 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 12591, progress = 1.00, t = 56.13 s / 224.31 tokens per second
3.34.848.536 I slot print_timing: id 0 | task 0 | prompt eval time = 56584.11 ms / 12595 tokens ( 4.49 ms per token, 222.59 tokens per second)
3.34.848.548 I slot print_timing: id 0 | task 0 | eval time = 9898.23 ms / 49 tokens ( 206.21 ms per token, 4.85 tokens per second)
3.34.848.550 I slot print_timing: id 0 | task 0 | total time = 66482.34 ms / 12644 tokens
3.34.848.553 I slot print_timing: id 0 | task 0 | graphs reused = 95
3.34.861.451 I slot release: id 0 | task 0 | stop processing: n_tokens = 12643, truncated = 0
3.36.344.746 I slot get_availabl: id 0 | task -1 | selected slot by LCP similarity, f_sim_best = 0.997 (> 0.100 thold), f_keep = 0.999
3.36.345.354 I slot launch_slot_: id 0 | task 79 | processing task, is_child = 0
3.48.294.821 I slot print_timing: id 0 | task 79 | prompt eval time = 2555.49 ms / 35 tokens ( 73.01 ms per token, 13.70 tokens per second)
3.48.294.828 I slot print_timing: id 0 | task 79 | eval time = 9393.93 ms / 49 tokens ( 195.71 ms per token, 5.11 tokens per second)
3.48.294.830 I slot print_timing: id 0 | task 79 | total time = 11949.42 ms / 84 tokens
3.48.294.831 I slot print_timing: id 0 | task 79 | graphs reused = 142
3.48.295.889 I slot release: id 0 | task 79 | stop processing: n_tokens = 12708, truncated = 0
3.48.883.888 I slot get_availabl: id 0 | task -1 | selected slot by LCP similarity, f_sim_best = 0.991 (> 0.100 thold), f_keep = 0.999
3.48.884.406 I slot launch_slot_: id 0 | task 130 | processing task, is_child = 0
4.02.911.486 I slot print_timing: id 0 | task 130 | prompt eval time = 1060.78 ms / 119 tokens ( 8.91 ms per token, 112.18 tokens per second)
4.02.911.492 I slot print_timing: id 0 | task 130 | eval time = 12966.25 ms / 64 tokens ( 205.81 ms per token, 4.86 tokens per second)
4.02.911.493 I slot print_timing: id 0 | task 130 | total time = 14027.03 ms / 183 tokens
4.02.911.494 I slot print_timing: id 0 | task 130 | graphs reused = 204
4.02.912.197 I slot release: id 0 | task 130 | stop processing: n_tokens = 12875, truncated = 0
在nbl=32 設定值, 反而 token 輸出更多.
0.11.247.014 I cmn init: llama threadpool init, n_threads = 8
0.11.708.585 I srv load_model: initializing, n_slots = 1, n_ctx_slot = 32768, kv_unified = ‘false’
0.11.719.733 I srv llama_server: model loaded
0.11.719.744 I srv llama_server: listening on http://127.0.0.1:8080
0.11.719.747 W srv llama_server: NOTICE: server default port will be changed to :9931 in a future release
0.11.719.749 W srv llama_server: ref: https://github.com/ggml-org/llama.cpp/pull/26508
0.19.794.187 I slot get_availabl: id 0 | task -1 | selected slot by LRU, t_last = -1
0.19.794.444 I slot launch_slot_: id 0 | task 0 | processing task, is_child = 0
0.23.261.643 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 1024, progress = 0.08, t = 3.47 s / 295.34 tokens per second
0.24.512.009 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 1313, progress = 0.10, t = 4.72 s / 278.32 tokens per second
0.26.187.768 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 1825, progress = 0.14, t = 6.39 s / 285.46 tokens per second
0.27.881.669 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 2337, progress = 0.18, t = 8.09 s / 288.98 tokens per second
0.29.591.197 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 2849, progress = 0.22, t = 9.80 s / 290.81 tokens per second
0.31.294.120 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 3361, progress = 0.26, t = 11.50 s / 292.27 tokens per second
0.32.971.017 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 3873, progress = 0.30, t = 13.18 s / 293.93 tokens per second
0.34.653.474 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 4385, progress = 0.34, t = 14.86 s / 295.11 tokens per second
0.36.360.070 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 4897, progress = 0.38, t = 16.57 s / 295.61 tokens per second
0.38.162.684 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 5409, progress = 0.42, t = 18.37 s / 294.48 tokens per second
0.40.018.180 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 5921, progress = 0.46, t = 20.22 s / 292.78 tokens per second
0.41.816.396 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 6433, progress = 0.50, t = 22.02 s / 292.12 tokens per second
0.43.483.995 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 6945, progress = 0.54, t = 23.69 s / 293.17 tokens per second
0.45.187.034 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 7457, progress = 0.58, t = 25.39 s / 293.67 tokens per second
0.47.036.932 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 7969, progress = 0.62, t = 27.24 s / 292.52 tokens per second
0.48.737.307 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 8481, progress = 0.66, t = 28.94 s / 293.03 tokens per second
0.50.440.491 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 8993, progress = 0.70, t = 30.65 s / 293.45 tokens per second
0.52.155.480 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 9505, progress = 0.74, t = 32.36 s / 293.72 tokens per second
0.53.866.976 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 10017, progress = 0.78, t = 34.07 s / 293.99 tokens per second
0.55.606.238 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 10529, progress = 0.82, t = 35.81 s / 294.01 tokens per second
0.56.688.545 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 10552, progress = 0.83, t = 36.89 s / 286.01 tokens per second
0.57.110.883 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 10635, progress = 0.83, t = 37.32 s / 285.00 tokens per second
0.58.859.668 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 11147, progress = 0.87, t = 39.07 s / 285.34 tokens per second
1.00.605.512 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 11659, progress = 0.91, t = 40.81 s / 285.68 tokens per second
1.02.421.587 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 12171, progress = 0.95, t = 42.63 s / 285.52 tokens per second
1.04.162.420 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 12637, progress = 0.99, t = 44.37 s / 284.82 tokens per second
1.04.615.403 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 12753, progress = 1.00, t = 44.82 s / 284.53 tokens per second
1.05.255.757 I slot print_timing: id 0 | task 0 | prompt processing, n_tokens = 12765, progress = 1.00, t = 45.46 s / 280.79 tokens per second
1.22.659.375 I slot print_timing: id 0 | task 0 | n_gen = 100, tg = 5.81 t/s, tg_3s = 5.87 t/s
1.25.707.350 I slot print_timing: id 0 | task 0 | n_gen = 118, tg = 5.82 t/s, tg_3s = 5.91 t/s
1.28.771.953 I slot print_timing: id 0 | task 0 | n_gen = 137, tg = 5.87 t/s, tg_3s = 6.20 t/s
1.31.844.867 I slot print_timing: id 0 | task 0 | n_gen = 156, tg = 5.91 t/s, tg_3s = 6.18 t/s
1.34.973.303 I slot print_timing: id 0 | task 0 | n_gen = 175, tg = 5.93 t/s, tg_3s = 6.07 t/s
1.38.131.635 I slot print_timing: id 0 | task 0 | n_gen = 194, tg = 5.94 t/s, tg_3s = 6.02 t/s
1.41.180.046 I slot print_timing: id 0 | task 0 | n_gen = 213, tg = 5.96 t/s, tg_3s = 6.23 t/s
1.44.038.718 I slot print_timing: id 0 | task 0 | prompt eval time = 45822.72 ms / 12769 tokens ( 3.59 ms per token, 278.66 tokens per second)
1.44.038.724 I slot print_timing: id 0 | task 0 | eval time = 38421.51 ms / 231 tokens ( 167.05 ms per token, 5.99 tokens per second)
1.44.038.725 I slot print_timing: id 0 | task 0 | total time = 84244.23 ms / 13000 tokens
1.44.038.726 I slot print_timing: id 0 | task 0 | graphs reused = 276
1.44.056.373 I slot release: id 0 | task 0 | stop processing: n_tokens = 12999, truncated = 0
之前的分析確實是不夠準確的。直接看數據比較,事實證明在你的硬體環境下,設定 ngl=32 的表現全面超越了 ngl=24。
數據對比
Prompt 處理速度(Prompt Processing)
ngl=24:約 222.59 tokens/second(耗時 56.58 秒)ngl=32:約 278.66 tokens/second(耗時 45.82 秒,提升了約 25%)
文字生成速度(Text Generation / Eval time)
ngl=24:約 4.85 tokens/second(每 token 206.21 ms)ngl=32:約 5.99 tokens/second(每 token 167.05 ms,提升了約 23.5%)
為什麼會出現這個結果?
先前過於低估了共用顯示記憶體與 PCIe 傳輸的實際效率。
- GPU 計算單元優勢顯著:將更多的模型層數(32 層 vs 24 層)交給 GPU 算力單元去運算,所獲得的矩陣計算加速,遠遠超過了數據透過 PCIe 或記憶體傳輸帶來的延遲開銷。
- 記憶體管理機制運作良好:當前的系統與驅動程式在處理溢出至 Shared GPU Memory 的權重時,併發存取的效能優於純 CPU+RAM 計算,因此並沒有出現嚴重的卡頓。
調整建議
既然數據證明 ngl=32 的執行效率顯著優於 ngl=24,請直接保持 -ngl 32 的設定。
建議的批次檔參數組合:
DOS
@echo off
chcp 65001 >nul
cd /d "%~dp0"
echo ================================================
echo gemma-4-12B-it-qat-UD-Q4_K_XL - HIGH PERFORMANCE
echo ================================================
echo.
set MODEL=models\gemma-4-12B-it-qat-UD-Q4_K_XL.gguf
set EXE=llama-server.exe
set CTX=32768
set BATCH=512
set UBATCH=128
set NP=1
set NGL=32
set THREADS=8
"%EXE%" ^
-m "%MODEL%" ^
-c %CTX% ^
-n 8192 ^
-np %NP% ^
-b %BATCH% ^
-ub %UBATCH% ^
-ngl %NGL% ^
-t %THREADS% ^
-ctk q8_0 ^
-ctv q8_0 ^
--port 8080 ^
--host 127.0.0.1 ^
--api-key 12345678 ^
-fa 1
pause
以數據為準的調整思路非常正確,後續只需維持 Pi Agent 端 contextWindow: 28000 的搭配即可。
設到 ngl=64 會爆慢,是因為你跨過了系統記憶體分頁(Paging)與 PCIe 傳輸崩潰的臨界點。
這份 Gemma 12B 模型總共只有 48 層(Layers)。你設定 -ngl 64 代表要求把所有層數(全額)以及高達 32K 的 KV Cache 強制塞進 GPU。
這引發了連鎖災難反應:
- 超出專用 VRAM 太多(6GB vs 8GB+)原本
ngl=32時,溢出到共用記憶體(Shared GPU Memory)的資料量還在 Windows 驅動程式的高速快取緩衝範圍內。當你改成64(全部 48 層硬塞),顯示卡 6GB VRAM 會被 100% 擠爆。 - PCIe 匯流排徹底塞車模型所有的權重與 32K KV Cache(共約 8~10 GB)被迫全部擠在共用記憶體(RAM)裡面。每一層計算,GPU 都必須透過 PCIe 介面往返讀寫系統 RAM。頻寬直接從 192 GB/s 降到 40 GB/s 左右,形成了嚴重的傳輸瓶頸。
- 觸發 Windows 虛擬記憶體 Swap當共用 GPU 記憶體被吃滿,Windows 驅動程式會開始把記憶體資料寫入硬碟的分頁檔(Pagefile)。從 Log 看到 Prompt 處理速度一路從
146 t/s掉到82 t/s(ngl=32時有280 t/s),這是典型的記憶體分頁交換(Thrashing)現象。
最佳化總結
ngl=24:留太少給 GPU,算力沒發揮。ngl=32(最佳甜蜜點):GPU 負擔大部分層數,溢出量剛好在 PCIe 高速緩衝內,達成速度最大化。ngl=64(邊界崩潰):完全擠爆 VRAM 並壓垮系統記憶體與 PCIe 頻寬,導致效能暴跌。
CPU 大小核心數的差異
硬體環境:
裝置名稱 DESKTOP-4RTC35D
處理器 12th Gen Intel(R) Core(TM) i7-12700 (2.10 GHz)
已安裝記憶體(RAM) 32.0 GB (31.7 GB 可用)
系統類型 64 位元作業系統,x64 型處理器
根據你提供的規格,你的 CPU 是 Intel Core i7-12700(採用 Alder Lake 架構,混合大核心 P-Core 與小核心 E-Core)。
這顆處理器的詳細核心結構如下:
- 8 個 P-Core (效能大核心):支援超執行緒,共 16 執行緒。
- 4 個 E-Core (能效小核心):不支援超執行緒,共 4 執行緒。
- 總計:12 核心 / 20 執行緒。
在 llama.cpp 純 CPU 推理中,混用 E-Core 或開啟超執行緒會嚴重拉慢整體速度(因為大核心必須等待小核心完成計算,且快取命中率會下降)。針對你這顆 CPU,最佳的執行緒設定是僅使用 8 個 P-Core 的實體核心。
i7-12700 最佳化 Batch 腳本
請將 -t 與 -tb 調整為 8,並套用針對 Intel 12 代 CPU 的優化參數:
DOS
set MODEL=models\gemma-4-12b-it-Q5_K_S.gguf
set EXE=llama-server.exe
:: Context 與 Batch 調整
set CTX=24576
set BATCH=1024
set UBATCH=512
set NP=1
set NGL=0
:: 針對 i7-12700 的 8 個 P-Core 設定
set THREADS=8
:: 停用 SYCL / GPU 偵測,避免開頭 Warning 延遲
set GGML_SYCL_DISABLE=1
set ONEAPI_DEVICE_SELECTOR=*:cpu
set SYCL_DEVICE_FILTER=cpu
"%EXE%" ^
-m %MODEL% ^
-c %CTX% ^
-np %NP% ^
-n 16384 ^
-b %BATCH% -ub %UBATCH% ^
-ngl %NGL% ^
-t %THREADS% ^
-tb %THREADS% ^
-ctk q4_0 -ctv q4_0 ^
--port 8080 ^
--host 127.0.0.1 ^
--api-key 12345678 ^
-fa on ^
--reasoning-format none ^
--temp 0.65 ^
--top-p 0.85 ^
--top-k 35 ^
--repeat-penalty 1.02
調整後預期改進點
- 從
-t 11降至-t 8:排除小核心 (E-Core) 與超執行緒搶資源問題,生成的 Token 速度(t/s)預計可提升 10% ~ 20%。 -ctk q4_0 -ctv q4_0:將 KV Cache 降至 4-bit,節省記憶體頻寬耗損,對於 long context 時的性能更有幫助。-b 1024 -ub 512:充分發揮 i7-12700 的 AVX2 指令集,加快 Prompt 吞吐效率。
(註:若未來想要突破 CPU 推理的物理極限,建議將模型檔換成 Q4_K_M 規格,生成速度會再顯著提升。)
在 i7-12700 (8P+4E, 32GB RAM) 的純 CPU 環境下,強烈建議選擇 12B (Q4_K_M)。
不建議選擇 26B 的核心原因為記憶體頻寬瓶頸(生成速度)與記憶體容量極限:
12B vs 26B 規格與效能對比 (Q4_K_M)
| 評估項目 | 12B (Q4_K_M) (推薦) | 26B (Q4_K_M) (不建議) |
| 模型檔案大小 | 約 7.3 GB | 約 15.8 GB |
| 預估 RAM 總消耗 (含 24K CTX) | 約 10 – 12 GB | 約 19 – 22 GB |
| 預估生成速度 (Eval) | ~ 8.5 – 10.0 t/s (順暢) | ~ 3.5 – 4.5 t/s (明顯卡頓) |
| Prompt 處理速度 (PP) | ~ 20 – 30 t/s | ~ 8 – 12 t/s |
| 系統負擔與剩餘記憶體 | 剩餘 > 20 GB,可輕鬆開瀏覽器/其他工具 | 剩餘 < 10 GB,高機率觸發 Windows 分頁交換 (Paging) |
為什麼選擇 12B 才是最佳解?
- CPU 推理的本質是「記憶體頻寬」挑戰CPU 生成 Token 時,每產生一個字,都必須將整個模型從 DDR4/DDR5 RAM 完整讀取一次:
- 12B (7.3 GB):i7-12700 的雙通道 DDR4/DDR5 頻寬約 50–60 GB/s,讀取一次僅需 0.12 秒,故速度能達到 8~10 t/s(接近人類閱讀速度)。
- 26B (15.8 GB):模型大了一倍,讀取一次需要近 0.3 秒,生成速度會暴跌至 3~4 t/s,實際使用時會有明顯的逐字卡頓感。
- 24K 長 Context 的 RAM 壓力雖然你擁有 32GB RAM,但當 Context 設定為
24576時,KV Cache 與系統運作也會佔用大量記憶體:- 26B 模型光是載入模型加初始化 Context,就會吃掉近 20GB RAM。若背景同時開著 Chrome 或其他程式,實體記憶體可能吃滿,導致 Windows 開始使用硬碟 SWAP,速度會再降至 1 t/s 以下。
- 12B (Q4_K_M) 是目前的 CP 值黃金交叉點Gemma 2 / Gemma 4 12B 的能力已經超越舊款的 13B~20B 模型。換成 12B Q4_K_M 後,相較於你之前的 12B Q5_K_S,檔案減小約 1.2GB,速度能有感提升 20%~30%,且推理能力幾乎零損耗。
結論與建議腳本
請直接下載 Gemma-12B-Q4_K_M.gguf(或 Qwen 12B 等同級模型),並使用以下優化腳本執行:
DOS
set MODEL=models\gemma-4-12b-it-Q4_K_M.gguf
set EXE=llama-server.exe
set CTX=24576
set BATCH=1024
set UBATCH=512
set NP=1
set NGL=0
:: i7-12700 8 個 P-Core 最佳設定
set THREADS=8
set GGML_SYCL_DISABLE=1
set ONEAPI_DEVICE_SELECTOR=*:cpu
set SYCL_DEVICE_FILTER=cpu
"%EXE%" ^
-m %MODEL% ^
-c %CTX% ^
-np %NP% ^
-n 16384 ^
-b %BATCH% -ub %UBATCH% ^
-ngl %NGL% ^
-t %THREADS% ^
-tb %THREADS% ^
-ctk q4_0 -ctv q4_0 ^
--port 8080 ^
--host 127.0.0.1 ^
--api-key 12345678 ^
-fa on ^
--reasoning-format none ^
--temp 0.65 ^
--top-p 0.85 ^
--top-k 35 ^
--repeat-penalty 1.02
對於你的 i7-12700 + 32GB RAM 純 CPU 環境,建議選擇 UD-Q4_K_XL。
以下是這兩種量化格式的評比與原因:
量化格式比較表
| 評估項目 | Q4_K_M (標準 K-quant) | UD-Q4_K_XL (Uncensored / Unsloth Uncensored / Custom UD) |
| 檔案大小 | 7.12 GB | 7.37 GB (+250 MB) |
| 對 CPU 速度影響 | 極微小(差距小於 3%) | 極微小(生成速度約維持在 8–10 t/s) |
| 邏輯與長文本精度 | 良好 | 優異(針對重要權重層進行保護/微調) |
| 記憶體佔用 | 約 10.5 GB (含 24K CTX) | 約 10.8 GB (含 24K CTX,32GB RAM 完全無壓力) |
為什麼推薦 UD-Q4_K_XL?
- 體積僅多 250MB,CPU 速度幾乎零感差異CPU 推理的極限在於記憶體讀取頻寬。7.12 GB 與 7.37 GB 在 i7-12700 的雙通道 RAM 讀取下,每秒生成字數(t/s)的差異不到 0.3 t/s,體感完全一致。
- UD (Unsloth / Dynamic) 量化精度更高
UD(通常為 Unsloth Dynamic Quantization 或更高等級的混合權重保留)會對 LLM 中最關鍵的 Attention 層與 MLP 層保留更高的位元精度,降低了常規 4-bit 量化容易出現的「邏輯混亂」與「長文章丟失細節」問題。 - RAM 空間綽綽有餘你的 32GB 記憶體容量相當充足,增加這 250 MB 檔案大小完全不會擠壓到系統或 24K Context 的運作空間。
結論與建議腳本
直接使用 UD-Q4_K_XL 版本的檔案,運行命令與先前一致:
DOS
set MODEL=models\gemma-4-12b-it-UD-Q4_K_XL.gguf
set EXE=llama-server.exe
set CTX=32767
set BATCH=1024
set UBATCH=512
set NP=1
set NGL=0
:: 配合 i7-12700 實體大核心 P-Core
set THREADS=8
set GGML_SYCL_DISABLE=1
set ONEAPI_DEVICE_SELECTOR=*:cpu
set SYCL_DEVICE_FILTER=cpu
"%EXE%" ^
-m %MODEL% ^
-c %CTX% ^
-np %NP% ^
-n 16384 ^
-b %BATCH% -ub %UBATCH% ^
-ngl %NGL% ^
-t %THREADS% ^
-tb %THREADS% ^
-ctk q4_0 -ctv q4_0 ^
--port 8080 ^
--host 127.0.0.1 ^
--api-key 12345678 ^
-fa on ^
--reasoning-format none ^
--temp 0.65 ^
--top-p 0.85 ^
--top-k 35 ^
--repeat-penalty 1.02
如果只有整合顯卡 Intel UHD Graphics 770,建議直接選擇純 CPU 執行的版本(cpu-x64)。
透過 SYCL 讓 UHD 770 執行 12B 模型,速度反而會比 i7-12700 的 CPU 核心還要慢,而且還有系統不穩定的風險。
為什麼整合顯卡 UHD 770 不適合跑 GPU 推論
- 沒有獨立顯示記憶體(共享系統記憶體)不像獨立顯卡擁有高速的專用顯示記憶體(GDDR6),UHD 770 需要共享主系統記憶體。將模型卸載到內顯運算,資料依然會經過相同的記憶體通道,完全無法發揮 GPU 卸載帶來的效能優勢。
- 算力顯著不足UHD 770 僅配備 32 個執行單元(EUs),主要針對基本顯示與影片解碼設計。相較之下,i7-12700 的 8 個效能核心(P-Cores)支援高效能 AVX2 指令集,處理張量矩陣運算的速度遠比內顯快得多。
- 系統凍結與驅動程式崩潰(TDR)風險Windows 針對整合顯卡設有兩秒的超時回應限制(TDR)。進行龐大的矩陣相乘時,容易導致內顯驅動程式卡死,進而引發螢幕閃爍、應用程式崩潰或系統畫面凍結。
建議設定方式
要在現有機器上獲得最佳且最穩定的體驗:
- 下載版本:請使用
llama-bXXXX-bin-win-cpu-x64.zip編譯版本。 - 參數設定:保持
-ngl 0與-t 8(充分利用 8 個效能核心)。 - 模型選擇:維持使用
gemma-4-12b-it-UD-Q4_K_XL.gguf或Q4_K_M。
目前每秒 22 個 Token 以上的提示詞處理速度,已經非常接近 DDR4 或 DDR5 記憶體架構的物理極限。
從日誌記錄來看,模型的伺服器端( llama.cpp )其實已經成功處理了高達 50,082 個 Token 的 Prompt 並完成運算,但最終在前端( 如 Open WebUI 或介面客戶端 )卻跳出了 Response was truncated before completion 的截斷警告。
造成這個情況的原因有兩個:
1. 前端( API Client )的單次輸出上限( max_tokens )太小
日誌顯示模型在生成 267 個 Token 後就終止了( eval time = ... / 267 tokens ),代表您的前端發送請求時,預設的 max_tokens( 或 max_completion_tokens )被限制得太短,導致模型還沒講完就被強行在中途中斷。
2. 前端的 Context Window 設定與伺服器不一致
雖然 llama.cpp 伺服器端已經設定為大上下文,但前端介面( 例如之前設定檔中的 model.json )如果仍限制在 contextWindow: 28000 或 maxTokens: 4096,當總長度超過時,前端的邏輯機制會直接攔截並截斷回應。
解決方法
請依照以下設定進行調整:
步驟一:修改前端模型設定檔( model.json )
請將前端設定檔中的上限同步開大,並提高單次輸出的上限:
JSON
{
"id": "models\\Qwen3.8-27B-UD-IQ3_XXS.gguf",
"name": "Qwen3.8-27B-Local",
"contextWindow": 65536,
"maxTokens": 8192
}
步驟二:調整 llama.cpp 啟動參數
若要允許模型單次輸出長文本,建議在啟動 llama-server 時加上 -n( 或 --n-predict )參數,調整單次最大生成的 Token 數量:
Bash
llama-server.exe ^
-m "models\Qwen3.8-27B-UD-IQ3_XXS.gguf" ^
-ngl 22 ^
-c 65536 ^
-ctk q4_0 ^
-ctv q4_0 ^
--context-shift ^
-n 8192 ^
-t 8 ^
--port 8080
-n 8192:允許模型單次最多可以回應 8192 個 Token,避免生成到一半被伺服器端切斷。
在 Pi Agent( 或基於 Pi 視覺/終端開發的 Agent 介面 )中,要在不重啟 Agent 的情況下重載 model.json,主要有以下三種做法:
1. 使用熱重載斜線指令( Hot Reload Commands )
部分 Agent 介面內建了記憶體與設定檔重載的快捷指令,可以直接在聊天輸入框輸入並發送:
/reload 或 /reload-config
如果介面支援,這會強制 Agent 重新讀取專案目錄下的 model.json 並更新內部的 contextWindow 與 maxTokens 參數。
2. 透過內建 CLI 或指令選單重設( Menu / Options )
若您使用的是 Pi 相關的 CLI 互動選單,可以透過快速鍵或選單觸發重載:
- 切換模型( Model Switch ):輸入
/model或按下切換模型的快捷鍵,先切換到隨便另一個模型( 或重複選擇同一個模型 ),這個動作會觸發 Agent 重新讀取 JSON 配置。 - 清除 Session / Context:輸入
/clear或/reset。許多 Agent 只會在啟動新對話對話( New Session )時讀取最新的模型配置檔,清除舊對話紀錄能讓 Agent 套用新的contextWindow邊界。
3. 在不離開 Agent 情況下發送控制 API ( 適用於後端服務 )
如果您的 Pi Agent 是透過控制台運作,您可以使用內建的 Bash / CLI 執行能力,發送指令給後端或觸發內建的 reload 腳本,例如:
Bash
# 若 Agent 具備本地命令列執行權限,可發送信號給 Agent 進程
kill -HUP $(pgrep pi-agent)
小建議:修改完 model.json 後,最快驗證是否生效的方法是直接輸入 /clear 開起一個全新對話,然後輸入 /info 或 /status 查看當前 Agent 載入的上下文上限值。