如何測量本機 LLM 的每秒 token 數?
租用 GPU 只有在輸出吞吐量超過成本門檻時才划算。用並行數掃描正確測量 tokens per second,再比較每小時 GPU 與按 token 計費成本。
每秒 token 數決定 GPU 是否划算
每秒 token 數是伺服器產生輸出文字的速率,也是決定租用 GPU 是否比按 token 支付 API 費用更便宜的數值。GPU 伺服器無論忙碌或閒置,都會按小時計費。託管 API 則按 token 計費。因此,只有在付費的大部分時間內維持足夠高的輸出速率,GPU 才具成本優勢。
這表示你需要實際測量結果,而不是採用其他地方讀到的數值。本頁定義值得記錄的 4 個數值,接著提供產生這些數值的命令,以及將結果換算成成本決策的方法。
為什麼公開的每秒 token 數不是你的實際數值
DigitalOcean 在 2026 年 7 月公布了單張 NVIDIA H200 在 vLLM 下使用 llama3.3-70b-instruct FP8(8 位元浮點數)時的吞吐量數據。這些數據具有參考價值,但不代表你的實際數值。
The data behind this chart
[
{
"config": "H200, one stream",
"tok_s": "47"
},
{
"config": "H100, saturated",
"tok_s": "236"
},
{
"config": "H200, saturated",
"tok_s": "2,036"
},
{
"config": "H200, saturated, in+out",
"tok_s": "4,071.6"
}
]上表的每一列都直接引自該頁面,其中兩列是該頁提供範圍的下限,因此應將這兩列視為最低值。表中的數據都不是我們實測的結果。
先看最後兩列。標題數值是 4,071.6 tok/s,但僅計算輸出的速率是 2,036 tok/s。標題數值會將輸入與輸出 token 合併計算。該測試使用 1,024 個輸入 token 和 1,024 個輸出 token,因此標題數值幾乎有一半是輸出速率。這個區分很重要,因為計費依據是輸出,而輸出也是較慢的部分。Prefill(讀取提示)會一次處理所有輸入 token。Decode(產生答案)則一次產生一個 token。總吞吐量的標題數值,會將低成本與高成本的部分平均計算。
接著看第一列。同一張 H200 每次只服務一個請求時,速率是 47 tok/s,因此在相同硬體上,滿載數值高出 40 倍以上。這個差距是因為單一步驟的 decode 大部分時間都在等待 GPU 從記憶體讀取資料,而並行請求可以填補這段閒置時間。第二列的 236 tok/s 是同一模型在單張 H100 上的數值,受到 KV cache(key-value cache,即服務中對話為每個請求保留在卡上的記憶體)限制。80 GB 顯示卡能為 70B 模型容納的並行請求較少,因此較早達到飽和。
只要更換模型,或調整輸入與輸出的比例,上述每個數值都會變動。公開數據可用來建立預期,但不能直接用來編列預算;磁碟與網路上的 VPS 誠實基準測試 也適用相同原則。
四個重要數字
- 首個 token 時間 TTFT。 從送出請求到收到第一個輸出 token 之間的延遲。這包括 prefill 時間與佇列時間。使用者會直接感受到這項數值。
- 每個串流每秒輸出 token 數。 回應開始產生後,單一回應的輸出速度。速度超過約 20 tok/s 後,已經比多數人的閱讀速度快,因此再提升速度帶來的效益有限。
- 飽和狀態下的總輸出吞吐量。 伺服器滿載時,所有並行串流的輸出總和。這是容量指標,也是實際影響 GPU 成本的數值。
- 並行處理下的 p50 與 p99 TTFT。 p50 是所有請求中位數的延遲。p99 是 100 個請求中有 99 個低於此值的延遲。佇列造成的影響一定會先反映在 p99。
伺服器負載較低時,前兩項通常較佳。伺服器忙碌時,第三項通常較佳。這些指標彼此牽制,因此沒有任何單一數值能完整描述 serving 伺服器。
測量前先固定輸入與輸出長度
吞吐量取決於網路流量的形態。包含 4,000 個 token 的提示詞,搭配 50 個 token 的回答,屬於以 prefilling 為主的工作。包含 200 個 token 的提示詞,搭配 2,000 個 token 的回答,則屬於以 decoding 為主的工作。同一台伺服器在這兩種情況下回報的每秒 token 數會有很大差異。因此,請固定一組比例,將其記在每個測量數值旁,且不要比較不同比例的結果。輸入 1,024、輸出 1,024 是合理的預設值,因為有數家廠商會以這個比例發布數據。如果你知道實際流量,請使用實際流量。
也要固定輸出長度。模型在產生 60 個 token 後遇到 stop token 時,執行時間較短,看起來會比較快,因為 TTFT 佔執行時間的比例較高。vLLM benchmark client 中的 --ignore-eos flag 會讓每個請求都精確產生指定數量的 token,確保兩次執行結果可比較。模型選擇對這些數值的影響大於任何 flag:將 Qwen 3 模型配置在單張 VPS GPU 上 說明了這項選擇的記憶體考量。
先測量單一串流
先從最簡單的情況開始。這是合理性檢查,也是上限值。Ollama 會輸出自己的計時資訊。
ollama run llama3.1:8b --verbose "Write 200 words about disk scheduling."要查看的欄位是 eval rate,代表每秒輸出的 token 數。prompt eval rate 是 prefill 速率,load duration 是將模型載入 VRAM 所花的時間。冷啟動後的第一次呼叫中,load duration 會很大,因此 total duration 會產生誤導。請執行命令兩次,並讀取第二次的結果。Ollama 預設會在模型閒置五分鐘後將其卸載,因此兩次執行之間若間隔太久,就會再次回到冷啟動情況。
API 也會提供相同欄位,而且更容易進行腳本化處理。
curl -s http://127.0.0.1:11434/api/generate -d '{
"model": "llama3.1:8b",
"prompt": "Write 200 words about disk scheduling.",
"stream": false
}' | jq '{eval_count, eval_duration,
tok_s: (.eval_count / (.eval_duration / 1000000000))}'eval_duration 的單位是奈秒,因此除以 1,000,000,000 即可換算成秒。這正是 Ollama API 文件對每秒 token 數所建議的換算方式。若伺服器尚未啟動,使用 Ollama 在 VPS 上自行託管 LLM 說明了安裝方式與 systemd 單元。
TTFT 需要使用串流請求,curl 可以替你測量這段時間。
curl -s -o /dev/null -N \
-w 'ttfb=%{time_starttransfer}s total=%{time_total}s\n' \
http://127.0.0.1:8000/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{"model":"Qwen/Qwen3-8B",
"messages":[{"role":"user","content":"Write 200 words about disk scheduling."}],
"stream":true,"max_tokens":256}'time_starttransfer 是回應本文第一個位元組抵達的時間點。在串流 chat completion 中,這個位元組屬於第一個 server-sent event;該事件可能是第一個內容 token,也可能是在其前送出的僅包含角色資訊的 delta。因此,請將這個數值視為約略的 TTFT,誤差約為一個事件。對同一台伺服器上的兩次執行結果而言,這已足以進行比較。
單一串流的數據會從兩方面高估這台機器的表現。TTFT 會是可能達到的最佳值,因為前方沒有其他請求排隊。每個串流的速率也會是可能達到的最佳值,因為整張卡只服務一個請求。這兩者都無法說明這台機器能承載多少負載。
如何執行並行掃描?
掃描會在逐步增加的並行數下,執行固定的工作負載,並記錄每個步驟的結果。vLLM 已提供此功能的用戶端,而且使用 OpenAI API,因此也能對 Ollama 及其他相容 OpenAI API 的服務執行。
vllm bench serve \
--backend openai-chat \
--base-url http://127.0.0.1:8000 \
--endpoint /v1/chat/completions \
--model Qwen/Qwen3-8B \
--dataset-name random \
--random-input-len 1024 \
--random-output-len 1024 \
--ignore-eos \
--num-prompts 160 \
--max-concurrency 16 \
--percentile-metrics ttft,tpot,itl,e2el \
--metric-percentiles 50,99--max-concurrency 會限制處於執行中的請求數量,也是要掃描的變數。--num-prompts 是送出的請求總數,因此應維持在並行數的約 10 倍,以取得穩定的平均值。摘要會在 Time to First Token 標題下輸出 Output token throughput (tok/s): 與 Total token throughput (tok/s):,接著輸出 Mean TTFT (ms):、Median TTFT (ms): 和 P99 TTFT (ms):。
輸出中沒有每個串流的速率,但只需再做一次除法即可取得。Mean TPOT (ms): 是第一個輸出 token 之後,每個輸出 token 的平均耗時,因此每個 token 需要 25 ms,就代表每個串流每秒輸出 40 個 token。將輸出吞吐量除以並行數,也會得到相同結果。
接著重複執行,並儲存每次的結果。
for C in 1 4 16 32 64 128; do
vllm bench serve \
--backend openai-chat \
--base-url http://127.0.0.1:8000 \
--endpoint /v1/chat/completions \
--model Qwen/Qwen3-8B \
--dataset-name random \
--random-input-len 1024 \
--random-output-len 1024 \
--ignore-eos \
--num-prompts $(( C * 10 )) \
--max-concurrency "$C" \
--percentile-metrics ttft,tpot,itl,e2el \
--metric-percentiles 50,99 \
--save-result --result-filename "sweep-c$C.json"
done讀取已儲存的 JSON 檔案
每次執行都會寫入一個檔案,因此可以一次從所有檔案擷取需要的欄位。
for f in sweep-c*.json; do
jq -r --arg f "$f" \
'[$f, .output_throughput, .total_token_throughput,
.median_ttft_ms, .p99_ttft_ms] | @tsv' "$f"
doneoutput_throughput 是每秒輸出的 token 數。total_token_throughput 會將輸入 token 也納入計算,因此在輸入與輸出比例為 1:1 時,數值接近兩倍。p99_ttft_ms 存在的原因是 --metric-percentiles 包含 99;如果要求未指定的百分位數,jq 會輸出 null。
實際上,並行度掃描會顯示什麼?
The data behind this chart
[
{
"label": "1 stream",
"per_stream_tok_s": 92,
"total_tok_s": 92,
"ttft_p50_ms": 48,
"ttft_p99_ms": 61
},
{
"label": "4 streams",
"per_stream_tok_s": 88,
"total_tok_s": 352,
"ttft_p50_ms": 71,
"ttft_p99_ms": 96
},
{
"label": "16 streams",
"per_stream_tok_s": 71,
"total_tok_s": 1136,
"ttft_p50_ms": 152,
"ttft_p99_ms": 244
},
{
"label": "32 streams",
"per_stream_tok_s": 54,
"total_tok_s": 1728,
"ttft_p50_ms": 287,
"ttft_p99_ms": 498
},
{
"label": "64 streams",
"per_stream_tok_s": 34,
"total_tok_s": 2176,
"ttft_p50_ms": 611,
"ttft_p99_ms": 1240
},
{
"label": "128 streams",
"per_stream_tok_s": 18,
"total_tok_s": 2304,
"ttft_p50_ms": 1490,
"ttft_p99_ms": 3820
}
]這 6 列資料示範了在具備合理硬體規模、可租用的 GPU 主機上,掃描結果可能呈現的形狀。這些資料不是您伺服器的測量結果,也不是供應商提供的數據。請執行上方的迴圈,並替換成您自己的數值。
請注意這個形狀,因為可泛用的是形狀,而不是特定數值。在單一串流下,整台主機每秒產生 92 個 token,p99 TTFT 為 61 ms。在 128 streams 個串流下,總吞吐量提高到每秒 2304 個 token,增加 25 倍;但每個串流的速度降至每秒 18 個 token,p99 TTFT 則升至 3820 ms。總吞吐量會上升,是因為批次處理將原本等待記憶體的閒置時間轉為有效工作。單一串流的速度會下降,是因為相同的計算資源現在由多個串流共用。
最後一次加倍最能說明問題。串流數從 64 增加到 128 時,總吞吐量增加不到 6%,但 p99 TTFT 約增加 3 倍。這表示 KV cache 已滿,請求開始排隊,而不是直接執行。實用的運作點更早出現:在 32 個串流下,主機仍能達到每秒 1728 個 token,相當於峰值的 75%;每個串流的速度為每秒 54 個 token,p99 TTFT 為 498 ms。請將此點回報為您的容量。曲線峰值並不是可用來服務使用者的數值。
Ollama 與 vLLM 衡量的不是同一件事
對預設的 Ollama 伺服器執行這組測試時,總量幾乎不會變動。OLLAMA_NUM_PARALLEL 的預設值是 1,因此一次只會執行一個請求,其餘請求都會等待。佇列會使 p99 TTFT 上升,但總輸出量維持不變。在進行任何測量前,先提高這個值。
sudo systemctl edit ollama.service[Service]
Environment="OLLAMA_NUM_PARALLEL=8"使用 sudo systemctl restart ollama 重新啟動,然後確認模型仍能容納。每個平行插槽都會分配自己的 context window,因此 Ollama 文件指出,4 個平行請求搭配 2K context 時,會配置 8K。將插槽數提高到一定程度後,模型會超出 VRAM。檢查 ollama ps:如果 PROCESSOR 欄顯示類似 48%/52% CPU/GPU 的內容,表示模型有一部分位於 CPU,此時隨著並行數增加,吞吐量會下降而不是上升。超過平行插槽數後,請求會排入 OLLAMA_MAX_QUEUE 佇列;其預設值為 512,超過後伺服器會回應 503。
vLLM 使用 continuous batching,因此會在插槽釋出時,將新請求加入正在執行的批次。其曲線會持續上升,直到 KV cache 用盡。Ollama 針對單一模型、單台機器與低設定成本進行最佳化。因此,兩個引擎對同一組測試會得出不同結果;這正是 Ollama 與 vLLM 作為 serving engine 的比較 的主題。記錄產生每個數值的引擎與版本。
測量錯誤指標的 5 種情況
- 用戶端距離伺服器很遠。 從筆記型電腦透過網際網路進行基準測試時,每次 TTFT 都會加入你的往返時間,因此實際測到的是家用網路連線。請在與伺服器相同的區域執行用戶端。
- 模型尚未預熱。 第一次請求需要載入權重;使用 vLLM 時,也可能需要執行 graph capture。請先送出一批預熱請求,再捨棄測試結果。
- 由 prefix caching 代為處理。 vLLM 預設啟用自動 prefix caching,因此反覆送出相同提示時,測量的是快取,而不是 prefill;TTFT 會降至實際值的一小部分。
--dataset-name random可避免這個問題,因為每個提示都不同。若要確認這點,請使用--no-enable-prefix-caching啟動伺服器。 - 輸出內容太短。 若答案只有 32 個 token,TTFT 會主導每次請求,因此 tokens per second 實際上描述的是 prefill。請搭配實際的輸出長度使用
--ignore-eos。 - 回報的並行數為 1。 這是表格上最有利的數字,而且與成本無關。
將測得的數值轉換為決策
使用 sweep 得到的飽和輸出吞吐量,而不是單一串流速率,並將其與每 token 定價比較。損益平衡點只需一次除法:
break_even_tok_s = (price_per_hour / price_per_million_output_tokens) * 1000000 / 3600以 DigitalOcean 在 2026 年 7 月的價格計算。其 H200 dedicated inference endpoint 每小時為 $4.47,serverless 對應方案則是每 1 百萬 tokens $0.65。因此,4.47 除以 0.65 等於每小時 6.88 百萬 tokens,再除以 3,600 秒,約為每秒 1,910 個輸出 tokens。價格來自 DigitalOcean。除法則是我們計算的。
決定結果的關鍵是 持續。如果每天只有 2 小時在飽和狀態下達到每秒 1,910 個 tokens,就不能稱為持續每秒 1,910 個 tokens,因為其餘 22 小時也要付費。DigitalOcean 對較便宜的 $3.44 每小時 GPU Droplet 所計算的自有損益平衡點,是 72.2 percent 的持續平均使用率;低於此數值時,每 token 定價較划算。通常使自架服務失去優勢的不是 tokens 處理速度慢,而是 GPU 閒置時數。
因此,決策需要兩項輸入。sweep 會提供上限。你的流量模式則會決定實際取得該上限的比例。將兩者相乘,再前往 GPU VPS 與每 token API 的損益平衡點,即可依你的用量判斷結果。
FAQ
自架 LLM 的每秒 token 數達到多少才算理想?
這個問題有兩個答案,因為這項指標有兩種用途。若只有一個人閱讀輸出內容,每個串流每秒輸出約 20 個 token 已經快於閱讀速度,再高也沒有幫助。若考量成本,重要的是滿載時的總輸出吞吐量;所謂理想值,是能超過損益平衡點的數值。以每百萬個 token $0.65,以及每小時成本 $4.47 的主機計算,依 2026 年 7 月的價格,損益平衡點約為每秒持續輸出 1,910 個 token。大型模型的單一串流無法達到這個數值,因此才需要批次處理。
為什麼我增加並行請求後,Ollama 的吞吐量仍維持不變?
OLLAMA_NUM_PARALLEL 的預設值為 1,因此伺服器會讓每個模型一次處理一個請求,其餘請求則排入佇列,最多達到 OLLAMA_MAX_QUEUE(預設為 512),超過後回傳 503。總輸出量維持不變,但 p99 TTFT 上升。這表示問題在佇列,而不是 GPU 已滿載。請在 systemd drop-in 中設定這個變數並重新啟動,然後檢查 ollama ps,因為每個並行插槽都會增加配置的 context,可能導致部分模型載入 CPU。
我應該測量首個 token 的時間,還是每秒 token 數?
兩者都要測量,因為負載增加時,這兩項數值會朝相反方向變化。TTFT 反映使用者感受到的等待時間;滿載輸出吞吐量則反映實際成本。請在每個並行度階段記錄 p50 與 p99 TTFT,然後選擇 p99 TTFT 仍在可接受範圍內的最高並行度。將該並行度下的吞吐量視為容量,不要採用曲線最高點的最大值。
每秒 token 數越高,單一 token 的成本就一定越低嗎?
不一定。單一 token 的成本,是每小時價格除以該主機在一小時內實際產出的 token 數。因此,即使伺服器速度很快,但一天大部分時間都閒置,單一 token 的成本仍會很高。關鍵在使用率,而不是峰值速度。此外也要確認單位:標示的總 token 吞吐量包含輸入 token,因此在輸入與輸出比例為 1:1 時,該數值接近你實際付費之輸出速率的 2 倍。