วิธีวัดค่า Tokens per second บน Local LLM อย่างแม่นยำ
การเช่า GPU จะคุ้มค่ากว่าจ่ายราย Token ก็ต่อเมื่อมีปริมาณงานสูงเกินเกณฑ์ เรียนรู้วิธีวัดค่า Tokens per second ด้วย Concurrency Sweep เพื่อคำนวณความคุ้มทุนที่แท้จริง
เหตุผลที่ tokens per second เป็นตัวตัดสินความคุ้มค่าของ GPU
Tokens per second คืออัตราการสร้างข้อความเอาต์พุตของเซิร์ฟเวอร์ และเป็นตัวเลขที่ใช้ตัดสินว่าการเช่า GPU นั้นประหยัดกว่าการจ่ายค่า API ต่อ token หรือไม่ โดย GPU จะถูกเรียกเก็บเงินเป็นรายชั่วโมงไม่ว่าจะมีการใช้งานหรือปล่อยว่างไว้ ในขณะที่ API ที่โฮสต์ไว้จะเรียกเก็บเงินตามจำนวน token ดังนั้น GPU จะคุ้มค่าก็ต่อเมื่อคุณรักษาอัตราการสร้างเอาต์พุตให้สูงเพียงพอตลอดระยะเวลาส่วนใหญ่ที่คุณต้องจ่ายเงิน
นั่นหมายความว่าคุณจำเป็นต้องมีการวัดผลจริง ไม่ใช่เพียงตัวเลขที่อ่านมาจากที่อื่น หน้านี้จะกำหนดตัวเลข 4 ค่าที่ควรบันทึกไว้ จากนั้นจะแสดงคำสั่งที่ใช้สร้างตัวเลขเหล่านั้น รวมถึงการคำนวณที่จะช่วยให้คุณตัดสินใจได้
เหตุใดตัวเลข tokens per second ที่เผยแพร่จึงไม่ใช่ตัวเลขของคุณ
DigitalOcean ได้เผยแพร่ตัวเลข throughput ในเดือนกรกฎาคม 2026 สำหรับ NVIDIA H200 หนึ่งตัวที่รัน llama3.3-70b-instruct ในรูปแบบ FP8 (8-bit floating point) บน vLLM ตัวเลขเหล่านี้มีประโยชน์แต่ไม่ใช่ตัวเลขของคุณ
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 ในขณะที่อัตราเฉพาะ output อยู่ที่ 2,036 tok/s หัวข้อข่าวนี้นับรวมทั้ง input token และ output token เข้าด้วยกัน การทดสอบนั้นใช้ input token 1,024 ตัวเทียบกับ output token 1,024 ตัว ดังนั้นเกือบครึ่งหนึ่งของหัวข้อข่าวคือ output การแบ่งส่วนนี้มีความสำคัญเพราะ output คือส่วนที่คุณถูกเรียกเก็บเงินและเป็นส่วนที่ช้ากว่า Prefill (การอ่าน prompt) จะประมวลผล input token ทั้งหมดในรอบเดียว Decode (การเขียนคำตอบ) จะสร้างทีละ token ตัวเลข throughput รวมจึงเป็นการเฉลี่ยระหว่างตัวเลขที่ถูกกับตัวเลขที่แพง
มาดูแถวแรก H200 ตัวเดิมที่ให้บริการทีละคำขอสร้างได้ 47 tok/s ดังนั้นตัวเลขเมื่อระบบทำงานเต็มประสิทธิภาพ (saturated) จึงสูงกว่าถึงกว่าสี่สิบเท่าบนฮาร์ดแวร์เดียวกัน ช่องว่างนี้เกิดขึ้นเพราะขั้นตอน decode หนึ่งครั้งทำให้ GPU ต้องรอหน่วยความจำเกือบตลอดเวลา และคำขอที่เข้ามาพร้อมกันจะช่วยเติมเต็มเวลาที่ว่างนั้น แถวที่สอง 236 tok/s คือ H100 หนึ่งตัวบนโมเดลเดียวกัน ซึ่งถูกจำกัดด้วย KV cache (key and value cache ซึ่งเป็นหน่วยความจำต่อคำขอที่การสนทนาที่กำลังให้บริการเก็บไว้บนการ์ด) การ์ดขนาด 80 GB รองรับคำขอพร้อมกันได้น้อยกว่าสำหรับโมเดลขนาด 70B จึงทำให้จุดอิ่มตัวต่ำกว่า
หากเปลี่ยนโมเดลหรือเปลี่ยนอัตราส่วน input ต่อ output ตัวเลขทุกตัวข้างต้นจะเปลี่ยนไป ตัวเลขที่เผยแพร่เป็นเพียงการตั้งความคาดหวัง ไม่ใช่การกำหนดงบประมาณของคุณ ซึ่งเป็นกฎเดียวกับที่ใช้ในการ ทำ benchmarking VPS อย่างตรงไปตรงมา สำหรับดิสก์และเครือข่าย
ตัวเลขสี่ค่าที่สำคัญ
- Time to first token, TTFT: ระยะเวลาตั้งแต่ส่งคำขอจนถึง token แรกปรากฏขึ้น เป็นผลรวมของเวลา prefill และเวลาในคิว ผู้ใช้งานจะสัมผัสถึงค่านี้ได้โดยตรง
- Output tokens per second, per stream: ความเร็วในการเขียนคำตอบหลังจากเริ่มประมวลผลแล้ว หากเกิน 20 tok/s จะถือว่าเร็วกว่าความเร็วในการอ่านของคนส่วนใหญ่ ดังนั้นความเร็วที่เพิ่มขึ้นหลังจากจุดนี้จึงมีผลน้อย
- Saturated total output throughput: ผลรวมของทุก stream ที่ทำงานพร้อมกันในขณะที่เซิร์ฟเวอร์รับโหลดเต็มที่ นี่คือค่าที่บ่งบอกถึงความสามารถในการรองรับ (capacity) และเป็นตัวเลขที่ใช้คำนวณความคุ้มค่าของ GPU
- p50 and p99 TTFT under concurrency: p50 คือค่ากลางของคำขอทั้งหมด ส่วน p99 คือค่าที่คำขอ 99 จาก 100 รายการทำได้ต่ำกว่าเกณฑ์นี้ ปัญหาการต่อคิวจะปรากฏให้เห็นในค่า p99 ก่อนเสมอ
ตัวเลขสองค่าแรกจะดีขึ้นเมื่อเซิร์ฟเวอร์มีโหลดน้อย ส่วนค่าที่สามจะดีขึ้นเมื่อเซิร์ฟเวอร์มีโหลดมาก ทั้งสองปัจจัยนี้ส่งผลกระทบซึ่งกันและกัน จึงไม่มีตัวเลขเพียงค่าเดียวที่สามารถอธิบายประสิทธิภาพของเซิร์ฟเวอร์ได้ทั้งหมด
แก้ไขความยาวของอินพุตและเอาต์พุตก่อนทำการวัด
Throughput ขึ้นอยู่กับลักษณะของ traffic งานที่มี prompt 4,000 token และคำตอบ 50 token ถือเป็นงานที่เน้น prefill ส่วนงานที่มี prompt 200 token และคำตอบ 2,000 token ถือเป็นงานที่เน้น decode เซิร์ฟเวอร์เครื่องเดียวกันจะรายงานค่า tokens per second ที่แตกต่างกันมากสำหรับงานทั้งสองรูปแบบนี้ ดังนั้นให้เลือกอัตราส่วนมาหนึ่งค่า เขียนกำกับไว้ข้างตัวเลขทุกตัวที่คุณบันทึก และห้ามนำค่าที่มาจากอัตราส่วนต่างกันมาเปรียบเทียบกัน ค่าอินพุต 1,024 และเอาต์พุต 1,024 เป็นค่าเริ่มต้นที่เหมาะสมเนื่องจากผู้ให้บริการหลายรายเผยแพร่ผลการทดสอบที่อัตราส่วนนี้ หากคุณทราบลักษณะ traffic จริงของคุณ ให้ใช้ค่า traffic จริงนั้น
กำหนดความยาวของเอาต์พุตให้คงที่ด้วย โมเดลที่หยุดทำงานหลังจากสร้างไป 60 token จะทำให้การรันสั้นลงและดูเหมือนว่าทำงานได้เร็วขึ้น เนื่องจาก TTFT จะกลายเป็นสัดส่วนที่ใหญ่ขึ้นของเวลาทั้งหมด แฟล็ก --ignore-eos ใน vLLM benchmark client จะทำให้ทุกคำขอสร้างผลลัพธ์ตามจำนวนที่ระบุไว้พอดี เพื่อให้การรันสองครั้งสามารถเปรียบเทียบกันได้ การเลือกโมเดลส่งผลต่อตัวเลขเหล่านี้มากกว่าการปรับแฟล็กใดๆ โดย การติดตั้งโมเดล Qwen 3 ลงบน GPU ของ VPS เครื่องเดียว จะครอบคลุมถึงประเด็นด้านหน่วยความจำในการเลือกโมเดลดังกล่าว
วัดผลจากสตรีมเดียวเป็นอันดับแรก
เริ่มต้นด้วยกรณีที่ง่ายที่สุด นี่คือการตรวจสอบความถูกต้องเบื้องต้นและเป็นค่าขีดจำกัดสูงสุด Ollama จะแสดงเวลาการทำงานของตัวเองออกมา
ollama run llama3.1:8b --verbose "Write 200 words about disk scheduling."บรรทัดที่ต้องอ่านคือ eval rate ซึ่งเป็นจำนวนโทเค็นที่สร้างได้ต่อวินาที prompt eval rate คืออัตราการประมวลผลคำสั่งเริ่มต้น (prefill rate) และ load duration คือเวลาที่ใช้ในการโหลดโมเดลเข้าสู่ VRAM ในการเรียกใช้งานครั้งแรกหลังจากเริ่มระบบใหม่ load duration จะมีค่าสูง ทำให้ total duration อาจทำให้เข้าใจผิดได้ ให้รันคำสั่งสองครั้งแล้วอ่านผลลัพธ์จากครั้งที่สอง Ollama จะยกเลิกการโหลดโมเดลที่ไม่ได้ใช้งานหลังจากผ่านไป 5 นาทีโดยค่าเริ่มต้น ดังนั้นการเว้นช่วงนานเกินไประหว่างการรันจะทำให้คุณกลับไปสู่กรณีเริ่มต้นใหม่
ฟิลด์ข้อมูลเดียวกันนี้สามารถดึงมาจาก 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 จะได้ค่าเป็นวินาที การหารดังกล่าวเป็นวิธีที่เอกสารประกอบ API ของ Ollama กำหนดไว้สำหรับการคำนวณโทเค็นต่อวินาที หากเซิร์ฟเวอร์ยังไม่พร้อมใช้งาน การติดตั้ง LLM ด้วยตนเองโดยใช้ Ollama บน VPS จะครอบคลุมขั้นตอนการติดตั้งและการตั้งค่า systemd unit
ค่า 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 คือช่วงเวลาที่ไบต์แรกของเนื้อหาการตอบกลับมาถึง ในการแชทแบบสตรีมมิ่ง ไบต์นั้นจะเป็นส่วนหนึ่งของเหตุการณ์แรกที่เซิร์ฟเวอร์ส่งมา (server-sent event) ซึ่งอาจเป็นโทเค็นเนื้อหาแรกหรือส่วนต่าง (delta) ของบทบาทที่ส่งมาก่อนหน้า ดังนั้นให้ถือว่าค่านี้คือ TTFT โดยบวกลบหนึ่งเหตุการณ์ ซึ่งมีความแม่นยำเพียงพอสำหรับการเปรียบเทียบการรันสองครั้งบนเซิร์ฟเวอร์เดียวกัน
ตัวเลขจากสตรีมเดียวนั้นแสดงศักยภาพของเครื่องสูงเกินจริงไปสองประการ ค่า TTFT จะเป็นค่าที่ดีที่สุดเท่าที่จะเป็นไปได้เพราะไม่มีคิวรออยู่ข้างหน้า และอัตราต่อสตรีมก็จะเป็นค่าที่ดีที่สุดเพราะการ์ดจอทั้งหมดกำลังให้บริการเพียงคำขอเดียว ทั้งสองค่านี้ไม่ได้บ่งบอกถึงขีดความสามารถในการรองรับงานจริงของเครื่อง
คุณจะทำการทดสอบ concurrency sweep ได้อย่างไร
การทำ sweep คือการรันภาระงาน (workload) ชุดหนึ่งซ้ำๆ โดยเพิ่มระดับ concurrency ขึ้นเรื่อยๆ เพื่อบันทึกผลลัพธ์ที่เกิดขึ้นในแต่ละขั้นตอน vLLM มี client สำหรับงานนี้มาให้ในตัว ซึ่งรองรับ OpenAI API ดังนั้นจึงสามารถใช้กับ Ollama หรือบริการอื่นที่เข้ากันได้กับ OpenAI ได้เช่นกัน
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 ใช้สำหรับจำกัดจำนวนคำขอที่กำลังประมวลผลอยู่ (requests in flight) และเป็นตัวแปรที่คุณต้องปรับเปลี่ยนในการทำ sweep ส่วน --num-prompts คือจำนวนคำขอทั้งหมดที่ส่งไป ดังนั้นควรตั้งค่าให้มีค่าประมาณ 10 เท่าของ concurrency เพื่อให้ได้ค่าเฉลี่ยที่เสถียร ข้อมูลสรุปจะแสดง Output token throughput (tok/s): และ Total token throughput (tok/s): ตามด้วย Mean TTFT (ms):, Median TTFT (ms): และ P99 TTFT (ms): ภายใต้หัวข้อ Time to First Token
ในผลลัพธ์ดังกล่าวไม่มีอัตราต่อ stream แสดงไว้โดยตรง แต่สามารถคำนวณได้ด้วยการหาร Mean TPOT (ms): คือเวลาเฉลี่ยต่อ output token หลังจาก token แรก ดังนั้นหากได้ 25 ms ต่อ token จะเท่ากับ 40 tokens ต่อวินาทีต่อ stream ซึ่งการนำ output throughput มาหารด้วย concurrency ก็จะได้ผลลัพธ์เดียวกัน
จากนั้นให้ทำซ้ำเป็นลูปและบันทึกผลการรันแต่ละครั้งไว้
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 คือจำนวน output tokens ต่อวินาที ส่วน total_token_throughput จะรวม input tokens เข้าไปด้วย ดังนั้นหากอัตราส่วนเป็น 1:1 ค่าที่ได้จะใกล้เคียงกับสองเท่า ส่วน p99_ttft_ms มีอยู่เพียงเพราะ --metric-percentiles รวมค่า 99 ไว้ด้วย หากคุณเรียกหา percentile ที่ไม่ได้ระบุไว้ jq จะแสดงค่า null ออกมา
การทำ concurrency sweep แสดงผลลัพธ์อะไรบ้าง
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 แถวนั้นเป็นเพียงตัวอย่างที่แสดงให้เห็นถึงรูปแบบที่เกิดขึ้นจากการทำ sweep บน GPU box ขนาดเล็กที่เช่าใช้งาน โดยเป็นตัวเลขที่มีขนาดใกล้เคียงกับความเป็นจริง ข้อมูลเหล่านี้ไม่ใช่การวัดผลจากเซิร์ฟเวอร์ของคุณและไม่ใช่ตัวเลขจากผู้ให้บริการ ให้คุณรันลูปด้านบนและแทนที่ด้วยข้อมูลของคุณเอง
จงอ่านรูปแบบของข้อมูล เพราะรูปแบบคือสิ่งที่นำไปประยุกต์ใช้ในภาพรวมได้ ในขณะที่มี 1 stream ทั้งระบบจะผลิตโทเค็นได้ 92 โทเค็นต่อวินาที โดยมีค่า p99 TTFT อยู่ที่ 61 มิลลิวินาที เมื่อถึงระดับ 128 streams ปริมาณรวมจะเพิ่มขึ้นเป็น 2304 โทเค็นต่อวินาที ซึ่งสูงกว่าเดิม 25 เท่า ในขณะที่แต่ละ stream จะลดลงเหลือ 18 โทเค็นต่อวินาที และค่า p99 TTFT จะเพิ่มขึ้นเป็น 3820 มิลลิวินาที ปริมาณงานรวมที่เพิ่มขึ้นเกิดจากการทำ batching ซึ่งเปลี่ยนช่วงเวลาที่หน่วยความจำว่างงานให้กลายเป็นงานที่มีประสิทธิภาพ ส่วนความเร็วต่อ stream ที่ลดลงเป็นเพราะทรัพยากรการประมวลผลถูกแบ่งใช้งานร่วมกัน
การเพิ่มจำนวนขึ้นเป็นสองเท่าในครั้งสุดท้ายคือจุดสังเกตสำคัญ การเพิ่มจาก 64 เป็น 128 streams ทำให้ปริมาณงานรวมเพิ่มขึ้นไม่ถึงร้อยละ 6 ในขณะที่ค่า p99 TTFT เพิ่มขึ้นประมาณ 3 เท่า ซึ่งหมายความว่า KV cache เต็มแล้วและคำขอต่างๆ กำลังเข้าคิวรอแทนที่จะได้รับการประมวลผล จุดปฏิบัติงานที่มีประสิทธิภาพควรอยู่ก่อนหน้านั้น คือที่ 32 streams ซึ่งระบบยังคงทำได้ 1728 โทเค็นต่อวินาที หรือคิดเป็นร้อยละ 75 ของจุดสูงสุด โดยได้ความเร็ว 54 โทเค็นต่อวินาทีต่อ stream และมีค่า p99 TTFT อยู่ที่ 498 มิลลิวินาที ให้รายงานจุดนั้นว่าเป็นขีดความสามารถของระบบคุณ จุดสูงสุดของกราฟเป็นตัวเลขที่คุณไม่สามารถนำมาใช้ให้บริการผู้ใช้งานจริงได้
Ollama และ vLLM ไม่ได้วัดผลด้วยเกณฑ์เดียวกัน
หากคุณรันการทดสอบ sweep กับเซิร์ฟเวอร์ Ollama ค่าเริ่มต้น ผลรวมที่ได้แทบจะไม่เปลี่ยนแปลง เนื่องจาก OLLAMA_NUM_PARALLEL ถูกตั้งค่าเริ่มต้นไว้ที่ 1 ทำให้มีเพียงหนึ่งคำขอที่ทำงานในขณะที่คำขออื่นต้องรอคิว ซึ่งคิวนี้เองที่ทำให้ค่า p99 TTFT เพิ่มสูงขึ้นในขณะที่ผลลัพธ์รวมยังคงที่ คุณควรปรับค่านี้ให้สูงขึ้นก่อนเริ่มทำการวัดผลใดๆ
sudo systemctl edit ollama.service[Service]
Environment="OLLAMA_NUM_PARALLEL=8"ให้รีสตาร์ทด้วย sudo systemctl restart ollama จากนั้นตรวจสอบให้แน่ใจว่าโมเดลยังคงโหลดได้พอดี แต่ละ parallel slot จะได้รับส่วนแบ่งของ context window ของตัวเอง ดังนั้นเอกสารของ Ollama จึงระบุว่า context ขนาด 2K ที่มี 4 parallel requests จะใช้พื้นที่รวม 8K หากคุณเพิ่มจำนวน slot มากเกินไป โมเดลจะล้นออกจาก VRAM ให้ตรวจสอบที่ ollama ps หากคอลัมน์ PROCESSOR แสดงค่าประมาณ 48%/52% CPU/GPU นั่นหมายความว่าส่วนหนึ่งของโมเดลถูกย้ายไปทำงานบน CPU ซึ่งจะทำให้ throughput ลดลงเมื่อคุณเพิ่ม concurrency แทนที่จะเพิ่มขึ้น หลังจากเต็มจำนวน parallel slots แล้ว คำขอจะถูกนำไปต่อคิวที่ OLLAMA_MAX_QUEUE ซึ่งมีค่าเริ่มต้นอยู่ที่ 512 หลังจากนั้นเซิร์ฟเวอร์จะตอบกลับด้วยสถานะ 503
vLLM ใช้กลไก continuous batching จึงสามารถรับคำขอใหม่เข้าสู่ batch ที่กำลังทำงานอยู่ได้ทันทีเมื่อมี slot ว่าง ทำให้กราฟประสิทธิภาพยังคงเพิ่มขึ้นเรื่อยๆ จนกว่า KV cache จะเต็ม Ollama ถูกปรับแต่งมาเพื่อเน้นการใช้งานหนึ่งโมเดลต่อหนึ่งเครื่องและติดตั้งได้ง่าย ดังนั้นเอนจินทั้งสองจึงให้ผลลัพธ์ที่แตกต่างกันในการทดสอบ sweep เดียวกัน ซึ่งเป็นประเด็นหลักของ การเปรียบเทียบ Ollama และ vLLM ในฐานะเอนจินสำหรับให้บริการ โปรดบันทึกว่าตัวเลขแต่ละชุดมาจากเอนจินใดและเวอร์ชันใดเสมอ
ห้าวิธีในการวัดผลที่ผิดพลาด
- ไคลเอนต์อยู่ไกลเกินไป การทำ Benchmarking จากแล็ปท็อปของคุณผ่านอินเทอร์เน็ตจะเพิ่มเวลา Round trip เข้าไปในทุกค่า TTFT ทำให้สิ่งที่คุณวัดคือความเร็วการเชื่อมต่อที่บ้านของคุณ ให้รันไคลเอนต์ในภูมิภาคเดียวกับเซิร์ฟเวอร์
- โมเดลยังไม่พร้อมทำงาน (Cold) คำขอแรกต้องเสียเวลาโหลด Weight และใน vLLM อาจต้องเสียเวลาทำ Graph capture ด้วย ให้ส่งชุดคำขอเพื่ออุ่นเครื่อง (Warmup) และทิ้งผลลัพธ์นั้นไป
- Prefix caching ช่วยตอบแทนคุณ vLLM เปิดใช้งาน Prefix caching อัตโนมัติเป็นค่าเริ่มต้น ดังนั้นการส่ง Prompt เดิมซ้ำๆ จะเป็นการวัดผลที่แคชแทนที่จะเป็น Prefill ทำให้ค่า TTFT ลดลงจนเหลือเพียงเศษเสี้ยวของความเป็นจริง
--dataset-name randomช่วยป้องกันปัญหานี้ได้เพราะทุก Prompt จะแตกต่างกัน เพื่อความมั่นใจให้เริ่มเซิร์ฟเวอร์ด้วย--no-enable-prefix-caching - ผลลัพธ์สั้นเกินไป หากคำตอบมีความยาวเพียง 32 token ค่า TTFT จะครอบงำผลลัพธ์ของแต่ละคำขอ และค่า Tokens per second ที่ได้จะเป็นเพียงการอธิบายความเร็วของ Prefill เท่านั้น ให้ใช้
--ignore-eosด้วยความยาวผลลัพธ์ที่สมจริง - คุณรายงานค่า Concurrency ที่ 1 นี่เป็นตัวเลขที่ดูดีที่สุดในตาราง แต่ไม่มีผลใดๆ ต่อการคำนวณต้นทุนจริง
เปลี่ยนตัวเลขที่วัดได้ให้เป็นการตัดสินใจ
ให้นำค่า throughput ขาออกสูงสุดที่วัดได้จากการทดสอบ (saturated output throughput) ไม่ใช่ความเร็วของสตรีมเดี่ยว มาเปรียบเทียบกับราคาต่อโทเค็น จุดคุ้มทุนสามารถคำนวณได้ด้วยการหาร:
break_even_tok_s = (price_per_hour / price_per_million_output_tokens) * 1000000 / 3600ลองคำนวณโดยใช้ราคาของ DigitalOcean ในเดือนกรกฎาคม 2026 โดย endpoint สำหรับการอนุมาน (inference) แบบ dedicated ที่ใช้ H200 มีราคา 4.47 ดอลลาร์ต่อชั่วโมง ในขณะที่แบบ serverless มีราคา 0.65 ดอลลาร์ต่อล้านโทเค็น ดังนั้น 4.47 หารด้วย 0.65 จะเท่ากับ 6.88 ล้านโทเค็นต่อชั่วโมง และเมื่อหารด้วย 3,600 วินาที จะได้ประมาณ 1,910 โทเค็นต่อวินาที ราคาเหล่านี้เป็นราคาของผู้ให้บริการ ส่วนการคำนวณเป็นของเรา
คำสำคัญที่ใช้ตัดสินใจเรื่องนี้คือ ความต่อเนื่อง (sustained) การทำความเร็วได้ 1,910 โทเค็นต่อวินาทีที่จุดอิ่มตัวเป็นเวลาสองชั่วโมงต่อวัน ไม่ได้หมายความว่าคุณได้ความเร็ว 1,910 โทเค็นต่อวินาทีอย่างต่อเนื่อง เพราะคุณต้องจ่ายค่าบริการสำหรับอีก 22 ชั่วโมงที่เหลือด้วย จุดคุ้มทุนของ GPU Droplet ที่ราคาถูกกว่าคือ 3.44 ดอลลาร์ต่อชั่วโมงของ DigitalOcean อยู่ที่การใช้งานเฉลี่ยต่อเนื่อง 72.2 เปอร์เซ็นต์ หากต่ำกว่านั้น ราคาแบบต่อโทเค็นจะคุ้มค่ากว่า ชั่วโมงที่ GPU ว่างงาน ไม่ใช่ความเร็วของโทเค็นที่ช้า คือสาเหตุที่ทำให้การ self-host มักจะไม่คุ้มทุน
ดังนั้น การตัดสินใจของคุณจึงมีปัจจัยนำเข้าสองประการ ผลการทดสอบจะให้ค่าเพดานสูงสุดแก่คุณ ส่วนรูปแบบการใช้งานจริงของคุณจะกำหนดสัดส่วนของเพดานนั้นที่คุณใช้จริง ให้นำตัวเลขมาคูณกัน จากนั้นนำผลลัพธ์ไปที่ จุดคุ้มทุนระหว่าง GPU VPS กับ API แบบต่อโทเค็น เพื่อดูคำตอบสำหรับปริมาณการใช้งานของคุณ
FAQ
ค่า tokens per second ที่เหมาะสมสำหรับ LLM ที่โฮสต์เองคือเท่าใด
คำตอบมีสองแง่มุมเนื่องจากตัวชี้วัดนี้ทำหน้าที่สองอย่าง สำหรับผู้ใช้ที่อ่านผลลัพธ์เพียงคนเดียว ความเร็วที่สูงกว่าประมาณ 20 tokens ต่อวินาทีต่อสตรีมถือว่าเร็วกว่าความเร็วในการอ่านแล้ว ดังนั้นการเพิ่มความเร็วให้มากกว่านี้จึงไม่มีประโยชน์ สำหรับด้านต้นทุน ตัวเลขที่สำคัญคือปริมาณ throughput รวมที่อิ่มตัว (saturated total output throughput) ซึ่งคำว่าเหมาะสมหมายถึงระดับที่ทำให้คุณถึงจุดคุ้มทุน เมื่อเทียบกับราคา $0.65 ต่อล้าน tokens บนเซิร์ฟเวอร์ที่มีต้นทุน $4.47 ต่อชั่วโมง จุดคุ้มทุนจะอยู่ที่ประมาณ 1,910 output tokens ต่อวินาทีอย่างต่อเนื่อง ณ ราคาเดือนกรกฎาคม 2026 การรันเพียงหนึ่งสตรีมบนโมเดลขนาดใหญ่ไม่มีทางถึงจุดนี้ได้ นี่คือเหตุผลว่าทำไมจึงต้องมีการทำ batching
ทำไม throughput ของ Ollama ถึงไม่เพิ่มขึ้นเมื่อเพิ่มจำนวน concurrent requests
OLLAMA_NUM_PARALLEL มีค่าเริ่มต้นเป็น 1 ทำให้เซิร์ฟเวอร์ประมวลผลทีละคำขอต่อหนึ่งโมเดลและนำคำขอที่เหลือเข้าคิวไว้ จนถึงขีดจำกัดที่ OLLAMA_MAX_QUEUE (ค่าเริ่มต้นคือ 512) ก่อนจะส่งคืนสถานะ 503 ปริมาณ output รวมจึงคงที่ในขณะที่ค่า p99 TTFT เพิ่มสูงขึ้น ซึ่งเป็นสัญญาณบ่งชี้ว่าเกิดการเข้าคิวแทนที่จะเป็นเพราะ GPU ทำงานหนักเกินไป ให้ตั้งค่าตัวแปรนี้ใน systemd drop-in แล้วรีสตาร์ท จากนั้นตรวจสอบ ollama ps เนื่องจากแต่ละ parallel slot จะเพิ่มการใช้ context ที่จัดสรรไว้และอาจผลักภาระบางส่วนของโมเดลไปที่ CPU ได้
ควรวัดค่า time to first token หรือ tokens per second
ควรวัดทั้งสองค่าเนื่องจากทั้งคู่มีทิศทางที่สวนทางกันเมื่อโหลดเพิ่มขึ้น TTFT คือสิ่งที่ผู้ใช้สัมผัสได้ ส่วน saturated output throughput คือสิ่งที่สะท้อนในใบแจ้งหนี้ของคุณ ให้บันทึกค่า p50 และ p99 TTFT ในทุกระดับของ concurrency จากนั้นเลือกค่า concurrency สูงสุดที่ค่า p99 TTFT ยังอยู่ในระดับที่คุณยอมรับได้ แล้วรายงานค่า throughput ณ จุดนั้นว่าเป็นความจุของคุณ ไม่ใช่ค่าสูงสุดจากจุดสูงสุดของกราฟ
ค่า tokens per second ที่สูงกว่าหมายถึงต้นทุนต่อ token ที่ต่ำกว่าเสมอไปหรือไม่
ไม่เสมอไป ต้นทุนต่อ token คือราคาต่อชั่วโมงหารด้วยจำนวน tokens ที่เซิร์ฟเวอร์ผลิตได้จริงในชั่วโมงนั้น ดังนั้นเซิร์ฟเวอร์ที่เร็วแต่ปล่อยให้ว่างงานเกือบทั้งวันก็ยังมีต้นทุนต่อ token ที่สูงอยู่ดี อัตราการใช้งาน (utilisation) เป็นตัวตัดสิน ไม่ใช่ความเร็วสูงสุด นอกจากนี้ให้สังเกตหน่วยวัดด้วย: ปริมาณ total token throughput ที่ระบุไว้มักนับรวม input tokens ด้วย ดังนั้นที่อัตราส่วน input ต่อ output เป็น 1:1 ปริมาณดังกล่าวจะใกล้เคียงกับสองเท่าของอัตรา output ที่คุณถูกเรียกเก็บเงินจริง