本地 LLM 推理架構:Ollama、llama.cpp、GGUF 與效能測試
這次用 Qwen3:4B 跑本地推理,最重要的收穫是看懂整套系統:上層有 Agent 和 API,中間是 Ollama 與推理 runtime,底下則是 GGUF 模型、量化設定和實際硬體。幾次簡單測試也讓我看到,回答時間除了受 generation 速度影響,也和輸出長度及 thinking 內容的多寡有關。
我有一臺 2024 年的電腦,配備 AMD Ryzen 8040 系列處理器和 64GB RAM。因為一些原因,它現在處於半退休狀態。我一直在想,這臺規格仍然不差的電腦,還能拿來做什麼?
我平常會使用 ChatGPT,也用過它的 API,卻從來沒有親手在本機跑過 LLM。Ollama、GGUF、量化與 GPU offloading 這些名詞看過不少,真正連在一起時,我仍然說不清楚它們各自負責哪一層。
於是我決定用這臺電腦跑本地模型。ChatGPT 建議先試 Qwen3:4B,我就從這個模型開始。
實際動手之後,我想弄懂的問題逐漸變得具體:
當我在本地輸入一句 prompt 之後,整個 AI 系統到底經過了哪些層,最後才把答案送回來?
Ollama:本地模型執行平台
最初我對 Ollama 的理解很簡單。
我以為它就像是一個模型管理器:
- 執行
ollama pull - 把模型下載下來
- 使用
ollama run指令啟動模型並進入互動模式 - 模型就可以在本地回答問題
從使用者角度來看,這個理解並沒有完全錯。
Ollama 的確幫我們處理了許多事情,包括:
- 下載和管理模型
- 啟動本地推理服務
- 選擇模型設定
- 提供 HTTP API
- 管理模型載入與記憶體
- 將底層推理細節包裝成比較簡單的使用方式
Ollama 像是一個位於上層的本地模型執行平台。
它把模型檔案、推理引擎、參數設定、API 服務和模型生命週期包裝在一起,讓使用者不需要直接面對底層的複雜度。
llama.cpp:常用的底層推理技術之一
llama.cpp 是一個用 C/C++ 實作的本地大型語言模型推理專案。
llama.cpp 是 Ollama 常用的底層推理技術之一,也是理解 GGUF 本地推理生態的重要入口。
它負責的是更底層的工作,例如:
- 載入模型權重
- 將文字轉換成 token
- 建立與管理 KV cache
- 執行 Transformer 的 forward pass
- 使用 CPU 或 GPU 進行矩陣運算
- 逐一產生新的 token
- 控制 sampling,例如 temperature、top-p 和 top-k
換句話說,Ollama 比較像是一個已經整合好的播放器,而 llama.cpp 則是可能在播放器內部負責解碼與處理資料的核心技術之一。
使用 Ollama 時,我通常不需要直接操作 llama.cpp。
但理解 llama.cpp 的存在,讓我第一次看見了 Ollama 包裝之下的那一層。
我也開始明白,當模型速度慢、GPU 使用率低,或者記憶體不足時,問題不一定只是「模型不好」。
它可能發生在不同地方:
- 模型太大
- 量化格式不適合
- GPU VRAM 不足
- 只有部分 layer 被 offload 到 GPU
- 其餘計算仍然由 CPU 執行
- context 太長,KV cache 佔用太多記憶體
- prompt processing 和 token generation 的瓶頸不同
- 推理引擎沒有充分支援目前的硬體
這使我開始從「選模型」轉向「理解系統」。
GGUF:模型的檔案格式
另一個我這週經常看到的詞是 GGUF。
一開始看到像這樣的名稱:
Qwen3-4B-Q4_K_M.gguf
我很容易把整串名稱都當成模型名稱。
但後來我才拆解出來:
Qwen3是模型家族4B大約代表參數規模Q4_K_M是一種量化方式.gguf是模型檔案格式
GGUF 是一種用來儲存模型權重與相關 metadata 的檔案格式,常被 llama.cpp 生態系統使用。
它可以包含:
- 模型權重
- tokenizer 資訊
- 模型架構資訊
- context 相關設定
- 特殊 token
- 量化後的 tensor 資料
所以可以把這幾個概念分開:
Qwen3 是模型,GGUF 是儲存和發布模型的格式,llama.cpp 是可載入並執行它的推理技術之一,而 Ollama 則是在更上層管理和提供服務的平台。
量化的目的,是讓大型模型能在有限硬體上實際執行
為了讓大型模型可以在一般電腦上執行,模型通常會經過量化。
模型原始權重可能使用 FP16 或 BF16 儲存,而量化會使用較少的 bit 表示權重,例如 8-bit、6-bit、5-bit 或 4-bit。
這樣做的主要目的,是降低:
- 模型檔案大小
- RAM 使用量
- VRAM 使用量
- 記憶體頻寬需求
例如,同樣是一個 4B 模型,FP16 和 4-bit 量化版本所需要的記憶體可能差異很大。
但是量化並不是免費的。
量化程度越高,通常越有可能損失一部分模型精度。不同量化方法在速度、記憶體和品質之間,也會有不同的平衡。
因此,Q4_K_M 代表了一種工程上的選擇:
我願意犧牲多少精度,來換取更低的記憶體需求和更高的本機執行可行性?
這也是本地模型和雲端模型很不一樣的地方。
使用雲端 API 時,我通常只需要選擇模型名稱。
但在本地環境中,我還必須思考:
- 使用哪個模型大小
- 使用哪種量化
- context window 設定多大
- 有多少 layer 放到 GPU
- CPU 與 GPU 如何分工
- 系統記憶體是否足夠
- 速度和品質之間如何取捨
完整的本地推理流程
下面這張圖先把整個本地 AI 系統分成幾個主要層次:
flowchart TB
U[使用者] --> A[聊天介面或 Agent<br/>Hermes / OpenClaw]
A --> API[OpenAI-compatible API]
API --> O[Ollama<br/>模型管理與服務層]
O --> R[推理 Runtime<br/>例如 llama.cpp]
R --> M[Qwen3 模型<br/>GGUF / Quantized Weights]
subgraph H[本地硬體]
CPU[CPU]
GPU[GPU]
RAM[RAM]
VRAM[VRAM]
end
M --> R
CPU --> R
GPU --> R
RAM --> R
VRAM --> R
從上層的 Agent 到底層的 CPU 和 GPU,每一層負責的工作都不同。Ollama 並不是模型本身,而是連接 API、推理引擎、模型檔案與硬體資源的服務層。
現在,我對本地推理流程的理解大致可以分成幾層。
第一層:應用程式或 Agent
最上層是使用模型的應用程式,例如聊天介面、程式設計 Agent,或者 OpenClaw。
這一層通常負責:
- 組合 system prompt
- 保留對話歷史
- 呼叫工具
- 管理 Agent loop
- 將請求送到模型 API
- 解析模型回傳的內容
Agent 不負責實際的神經網路推理,它只需要知道應該向哪一個 endpoint 發送請求。
第二層:API 相容層
下一層可能是一個 OpenAI-compatible API,例如:
http://localhost:11434/v1/chat/completions
這層的作用,是讓原本連接 OpenAI 或 Codex 的應用程式,可以用類似的請求格式連接本地模型。
例如請求中可能包含:
- model
- messages
- temperature
- tools
- stream
- max_tokens
這也是為什麼我可以嘗試把 Hermes Agent 原本連接的遠端模型,改成連接本機上的 Ollama。
不過,「API 格式相容」不代表所有能力都完全相同。
一個系統可能支援 Chat Completions API,但不一定完整支援 Responses API、tool calling、reasoning 欄位或其他 Codex 行為。
所以除了 endpoint 能不能連通之外,還要確認上層 Agent 所期待的協定和功能。
第三層:模型管理與服務層
這一層可以是 Ollama。
它接收 HTTP 請求,找到指定的模型;如果模型尚未載入記憶體,Ollama 會先完成載入,再管理推理工作,最後把結果以 API 回應的形式傳回去。已經駐留記憶體的模型則可以直接處理新的請求。
它將底層複雜度隱藏起來,讓上層應用程式不需要知道模型檔案實際放在哪裡,也不需要自己管理推理程序。
第四層:推理引擎
再往下,是負責執行模型計算的推理引擎,例如採用 llama.cpp 技術的 runtime。
sequenceDiagram
participant User as 使用者
participant Agent as Agent / 聊天介面
participant Ollama as Ollama API
participant Runtime as 推理 Runtime(例如 llama.cpp)
participant Model as Qwen3 / GGUF
participant Hardware as CPU / GPU
User->>Agent: 輸入 Prompt
Agent->>Agent: 組合 System Prompt 與對話歷史
Agent->>Ollama: 發送 Chat Completions 請求
alt 模型尚未駐留記憶體
Ollama->>Runtime: 載入模型
Runtime->>Model: 讀取模型權重與 Tokenizer
end
Ollama->>Runtime: 傳送 Prompt 與推理設定
Runtime->>Runtime: 將 Prompt Tokenize
rect rgb(235, 235, 235)
Note over Runtime,Hardware: Prompt Evaluation
Runtime->>Hardware: 處理所有輸入 Token
Hardware-->>Runtime: 回傳模型計算結果
Runtime->>Runtime: 建立 KV Cache
end
loop 每次產生一個新 Token
Runtime->>Hardware: 執行 Transformer Forward Pass
Hardware-->>Runtime: 回傳 Logits
Runtime->>Runtime: Sampling 選擇下一個 Token
Runtime->>Runtime: 更新 Context 與 KV Cache
Runtime-->>Ollama: 串流輸出 Token
Ollama-->>Agent: 回傳部分內容
Agent-->>User: 顯示產生中的答案
end
這一層主要會:
- 將 prompt tokenize
- 處理輸入 token
- 建立 attention 所需要的 KV cache
- 執行模型每一層的計算
- 算出下一個 token 的機率分布
- 根據 sampling 規則選出 token
- 將新 token 加回輸入
- 重複計算,直到完成回答
這裡也可以區分兩種工作。
第一種是 prompt evaluation,也就是處理一開始送入的所有輸入 token。
第二種是 token generation,也就是模型一個 token、一個 token 地產生答案。
兩者的效能特性並不完全一樣。
第五層:模型與權重
最底下才是模型本身。
例如 Qwen3 4B 的架構、參數和 tokenizer。
模型可能以 GGUF 格式儲存,並且已經經過某種量化。
模型決定了它具備什麼能力,而量化與推理設定則影響它在目前硬體上的實際表現。
第六層:硬體
最後,所有計算仍然需要落到實際硬體上:
- CPU
- GPU
- RAM
- VRAM
- 記憶體頻寬
- PCIe 資料傳輸
如果 GPU 無法容納完整模型,推理引擎可能只把部分 layer 放到 GPU,其他 layer 留在 CPU。
這並不代表模型完全不能執行,但速度可能比預期慢很多。
所以「模型是否支援我的 GPU」其實不是一個單純的是非題。
更準確的問題應該是:
這個模型在目前的推理引擎、量化格式、offloading 設定和硬體資源下,能以什麼速度執行,又能維持多少品質?
我在寫這篇文章的時候,剛好是 2026 年 7 月 17 日,也是半導體股票大跌的一天。
可是我發現,以我們目前硬體的狀況,要在一般個人電腦上跑出接近最前沿雲端模型能力的本地模型,其實還有相當長的一段距離。未來無論是晶片運算能力、記憶體頻寬、功耗,還是整體硬體架構,都還需要繼續進步。
繼續 ALL IN 半導體。
簡單實測
理解整套架構後,我們也用 Qwen3:4B 做了幾次簡單測試。模型透過 Ollama 執行,運算以 CPU 為主,context 設為 4096;我們重複送出相同問題,觀察總時間、輸出 token 數量和 generation 速度。這些結果主要用來了解這臺電腦的實際表現,不算完整、可重現的 benchmark。
Ollama API 會回傳幾個重要的時間與 token 統計欄位:
total_duration:整個請求花費的時間prompt_eval_count:模型處理的輸入 token 數量prompt_eval_duration:模型處理輸入 prompt 的時間eval_count:模型產生的 token 數量;在這次使用的 Ollama 與 Qwen3 組合中,觀察到的數值包含 thinking 內容與最終回答eval_duration:模型產生輸出 token 的時間
本文的 prompt processing 與 generation 速度,是用各自的 token 數除以時間換算出的 tokens per second。
最明顯的現象是,即使 generation 速度相近,回答時間仍可能從約 7 秒增加到 47.6 秒。差異主要來自輸出長度:較短的一次 eval_count 約為 142,較長的一次則為 918;在這次測試中,這些數值也涵蓋 thinking 內容。因此,判斷本地模型是否夠快,除了 tokens per second,還要看模型最後產生了多少內容。
結語:我開始學的不是某一個工具,而是一套系統
我一開始只是想善用這臺半退休的電腦,找一個適合目前 GPU 的模型。如果 Qwen3 4B 跑得不理想,我就想換一個。實際動手之後,我才發現,現階段更值得學的是整套系統如何運作,至於哪個模型最好,可以晚一點再決定。
現在遇到「模型跑不起來」或「模型很慢」時,我可以沿著架構逐層排查:Agent 組出的請求是否正確、API 協定是否相容、Ollama 有沒有載入模型、推理引擎是否使用 GPU、量化版本是否適合,以及瓶頸究竟來自硬體還是過長的模型輸出。
當我再次輸入一段 prompt 時,我開始能想像,這段文字如何被轉換成 token,如何穿過 API、推理服務和模型層,如何在 CPU 與 GPU 上被計算,最後再一個 token、一個 token 地變成答案。
而當模型花了很長時間回答時,我也開始知道,應該進一步觀察:究竟是硬體真的很慢,還是模型只是想得太多。
這或許才是我真正開始理解本地 AI 系統的第一步。