Cara Kira Tokens Per Second LLM Sendiri
Ketahui cara mengukur tokens per second dengan tepat menggunakan ujian concurrency. Bandingkan kos sewaan GPU dengan API untuk menentukan pilihan paling jimat bagi projek anda.
Mengapa tokens per second menentukan sama ada GPU berbaloi
Tokens per second ialah kadar pelayan anda menghasilkan teks output, dan angka inilah yang menentukan sama ada menyewa GPU lebih murah berbanding membayar API bagi setiap token. Kotak GPU dibilkan mengikut jam sama ada ia sibuk atau melahu. API yang dihoskan dibilkan mengikut token. Jadi, GPU hanya lebih menguntungkan jika anda mengekalkan kadar output yang cukup tinggi sepanjang kebanyakan jam yang anda bayar.
Ini bermakna anda memerlukan ukuran sendiri, bukan angka yang anda baca di tempat lain. Halaman ini mentakrifkan empat nombor yang perlu direkodkan, kemudian memberikan arahan yang menghasilkannya serta pengiraan yang menukarkannya menjadi keputusan.
Mengapa angka token sesaat yang diterbitkan bukan angka anda
DigitalOcean menerbitkan angka throughput pada Julai 2026 untuk satu NVIDIA H200 yang menjalankan llama3.3-70b-instruct dalam FP8 (floating point 8-bit) di bawah vLLM. Angka tersebut berguna tetapi ia bukan angka anda.
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"
}
]Setiap baris di atas dipetik daripada halaman tersebut, dan dua daripadanya merupakan nilai terendah bagi julat yang diberikan, jadi baca kedua-duanya sebagai nilai lantai. Tiada apa-apa dalam carta ini yang diukur oleh kami.
Mulakan dengan dua baris terakhir. Tajuk utamanya ialah 4,071.6 tok/s, manakala kadar output sahaja ialah 2,036 tok/s. Tajuk utama tersebut mengira token input dan output bersama-sama. Ujian itu menggunakan 1,024 token input berbanding 1,024 token output, jadi hampir tepat separuh daripada tajuk utama tersebut adalah output. Pembahagian ini penting kerana output adalah separuh bahagian yang anda dikenakan bayaran, dan ia merupakan bahagian yang perlahan. Prefill (membaca prompt) memproses semua token input dalam satu laluan. Decode (menulis jawapan) menghasilkan satu token pada satu masa. Tajuk utama jumlah throughput meratakan nombor yang murah dengan nombor yang mahal.
Sekarang lihat baris pertama. H200 yang sama melayani satu permintaan pada satu masa menghasilkan 47 tok/s, jadi angka tepu adalah lebih empat puluh kali ganda lebih tinggi pada perkakasan yang sama. Jurang itu wujud kerana satu langkah decode membiarkan GPU menunggu memori untuk kebanyakan masanya, dan permintaan serentak mengisi masa terbiar tersebut. Baris kedua, 236 tok/s, adalah satu H100 pada model yang sama, yang dikekang oleh KV cache (cache kunci dan nilai, iaitu memori setiap permintaan yang disimpan oleh perbualan yang dilayani pada kad tersebut). Kad 80 GB memuatkan lebih sedikit permintaan serentak untuk model 70B, jadi ia mencapai tahap tepu yang lebih rendah.
Tukar model atau tukar nisbah input kepada output dan setiap nombor di atas akan berubah. Angka yang diterbitkan menetapkan jangkaan anda, bukan bajet anda, yang merupakan peraturan sama yang terpakai untuk menanda aras VPS secara jujur pada cakera dan rangkaian.
Empat angka yang penting
- Time to first token, TTFT. Sela masa antara penghantaran permintaan dan ketibaan token output pertama. Ia adalah hasil tambah masa prefill dan masa baris gilir. Pengguna merasai kesan metrik ini secara langsung.
- Output tokens per second, per stream. Kelajuan satu jawapan ditulis sebaik sahaja ia bermula. Melebihi kadar kira-kira 20 tok/s, ia sudah lebih pantas daripada kelajuan membaca kebanyakan orang, jadi kelajuan tambahan di sini tidak memberikan banyak manfaat.
- Saturated total output throughput. Hasil tambah merentasi semua aliran serentak apabila pelayan dimuatkan sepenuhnya. Ini adalah angka kapasiti, dan ia merupakan angka yang menentukan kos GPU.
- p50 dan p99 TTFT di bawah konkurensi. p50 ialah permintaan pertengahan. p99 ialah nilai yang mana 99 daripada 100 permintaan berada di bawahnya. Isu baris gilir sentiasa muncul dalam p99 terlebih dahulu.
Dua metrik pertama bertambah baik apabila pelayan tidak sibuk. Metrik ketiga bertambah baik apabila pelayan sibuk. Metrik-metrik ini saling bertentangan, itulah sebabnya tiada satu angka tunggal yang dapat menggambarkan prestasi sesebuah kotak pelayan.
Betulkan panjang input dan output sebelum anda mengukur
Throughput bergantung pada bentuk trafik. Prompt 4,000-token dengan jawapan 50-token merupakan beban kerja yang berat pada prefill. Prompt 200-token dengan jawapan 2,000-token pula merupakan beban kerja yang berat pada decode. Pelayan yang sama akan melaporkan token per saat yang sangat berbeza bagi kedua-dua situasi ini, jadi pilih satu nisbah, tulis nisbah tersebut di sebelah setiap nombor yang anda rekod, dan jangan sesekali membandingkan antara nisbah yang berbeza. Input 1,024 dengan output 1,024 adalah nilai lalai yang munasabah kerana beberapa vendor menerbitkan data pada nisbah tersebut. Jika anda mengetahui trafik sebenar anda, gunakan trafik sebenar tersebut.
Tetapkan juga panjang output secara paksa. Model yang mencapai stop token selepas 60 token akan memberikan tempoh larian yang lebih singkat dan kelihatan lebih pantas, kerana TTFT akan membentuk bahagian yang lebih besar dalam tempoh tersebut. Flag --ignore-eos dalam klien penanda aras vLLM memastikan setiap permintaan menjana jumlah yang diminta dengan tepat, supaya dua larian kekal boleh dibandingkan. Pilihan model lebih mempengaruhi angka-angka ini berbanding mana-mana flag: memuatkan model Qwen 3 ke dalam satu GPU VPS membincangkan aspek memori bagi pilihan tersebut.
Ukur satu aliran dahulu
Mulakan dengan kes yang paling ringkas. Ini merupakan pemeriksaan kewarasan dan had maksimum. Ollama mencetak masa operasinya sendiri.
ollama run llama3.1:8b --verbose "Write 200 words about disk scheduling."Baris yang perlu dibaca ialah eval rate, iaitu token output sesaat. prompt eval rate ialah kadar pra-isi (prefill), dan load duration ialah masa yang diambil untuk memuatkan model ke dalam VRAM. Pada panggilan pertama selepas permulaan sejuk (cold start), load duration adalah besar, jadi total duration boleh mengelirukan. Jalankan arahan tersebut dua kali dan baca hasil yang kedua. Ollama akan memunggah model yang melahu selepas lima minit secara lalai, jadi jeda yang lama antara larian akan mengembalikan anda kepada keadaan permulaan sejuk.
Medan yang sama diperoleh daripada API, yang lebih mudah untuk diskripkan.
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 adalah dalam nanosaat, jadi membahagikannya dengan 1,000,000,000 akan memberikan saat. Pembahagian tersebut adalah tepat seperti yang ditetapkan oleh dokumentasi API Ollama untuk token sesaat. Jika pelayan belum aktif, pengehosan kendiri LLM dengan Ollama pada VPS merangkumi pemasangan dan unit systemd.
TTFT memerlukan permintaan penstriman, dan curl boleh mengukur masa tersebut untuk anda.
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 ialah saat bait pertama badan respons tiba. Pada penyelesaian sembang penstriman, bait tersebut tergolong dalam acara pertama yang dihantar pelayan (server-sent event), sama ada token kandungan pertama atau delta peranan sahaja yang dihantar tepat sebelum itu. Jadi, anggap nilai tersebut sebagai TTFT dengan ralat satu acara. Ia cukup tepat untuk membandingkan dua larian pada pelayan yang sama.
Nombor aliran tunggal memberikan gambaran yang terlalu optimistik terhadap perkakasan. TTFT adalah yang terbaik yang boleh dicapai, kerana tiada apa-apa yang beratur di hadapan anda. Kadar per-aliran adalah yang terbaik yang boleh dicapai, kerana keseluruhan kad grafik melayani satu permintaan sahaja. Kedua-duanya tidak menunjukkan kapasiti sebenar perkakasan tersebut.
Bagaimanakah anda menjalankan imbasan konkurensi?
Satu imbasan menjalankan beban kerja tetap pada tahap konkurensi yang meningkat dan merekodkan apa yang berlaku pada setiap langkah. vLLM menyertakan klien untuk tujuan ini, dan ia menggunakan API OpenAI, jadi ia juga berfungsi dengan Ollama dan mana-mana perisian lain yang serasi dengan 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 mengehadkan permintaan yang sedang diproses, dan ia merupakan pemboleh ubah yang anda imbas. --num-prompts ialah jumlah keseluruhan yang dihantar, jadi pastikan nilainya sekitar sepuluh kali ganda daripada konkurensi untuk mendapatkan purata yang stabil. Ringkasan akan mencetak Output token throughput (tok/s): dan Total token throughput (tok/s):, kemudian Mean TTFT (ms):, Median TTFT (ms): dan P99 TTFT (ms): di bawah tajuk Time to First Token.
Tiada kadar per-strim dalam output tersebut, tetapi ia boleh diperoleh melalui satu operasi pembahagian. Mean TPOT (ms): ialah purata masa bagi setiap token output selepas yang pertama, jadi 25 ms bagi setiap token bermakna 40 token sesaat bagi setiap strim. Membahagikan throughput output dengan konkurensi akan memberikan jawapan yang sama.
Kemudian gelungkan proses tersebut, dan simpan setiap larian.
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"
doneMembaca fail JSON yang disimpan
Setiap larian menulis satu fail, jadi ekstrak medan yang anda perlukan daripada semua fail tersebut sekaligus.
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 ialah token output sesaat. total_token_throughput menambah semula token input, jadi pada nisbah 1:1, nilainya hampir dua kali ganda. p99_ttft_ms wujud hanya kerana --metric-percentiles menyertakan 99; jika anda meminta persentil yang tidak dipohon, jq akan mencetak null.
Apakah yang sebenarnya ditunjukkan oleh imbasan konkurensi?
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 baris tersebut merupakan gambaran bentuk yang dihasilkan oleh imbasan pada kotak GPU sewaan kecil, pada magnitud yang munasabah. Ia bukanlah ukuran bagi pelayan anda, dan ia juga bukan angka daripada vendor. Jalankan gelung di atas dan gantikan angka tersebut dengan angka anda sendiri.
Fahami bentuknya, kerana bentuk itulah yang boleh digeneralisasikan. Pada satu aliran, keseluruhan kotak menghasilkan 92 token sesaat dengan p99 TTFT sebanyak 61 ms. Pada 128 streams, jumlah keseluruhan mencapai 2304 token sesaat, dua puluh lima kali ganda lebih tinggi, manakala setiap aliran individu jatuh kepada 18 token sesaat dan p99 TTFT mencapai 3820 ms. Jumlah throughput meningkat kerana pemprosesan kelompok (batching) menukarkan masa tunggu memori yang terbiar kepada kerja yang berguna. Kelajuan setiap aliran menurun kerana kuasa pengkomputeran yang sama kini dikongsi.
Peningkatan dua kali ganda yang terakhir adalah penanda arasnya. Peralihan daripada 64 kepada 128 aliran menambah kurang daripada enam peratus kepada jumlah keseluruhan, manakala p99 TTFT meningkat kira-kira tiga kali ganda. Ini bermakna KV cache telah penuh dan permintaan sedang beratur dan bukannya diproses. Titik operasi yang berguna adalah lebih awal: pada 32 aliran, kotak tersebut masih menghasilkan 1728 token sesaat, iaitu 75 peratus daripada kemuncaknya, pada 54 token sesaat bagi setiap aliran dan p99 TTFT sebanyak 498 ms. Laporkan titik tersebut sebagai kapasiti anda. Kemuncak lengkung tersebut adalah angka yang tidak boleh digunakan untuk melayani pengguna.
Ollama dan vLLM tidak mengukur perkara yang sama
Jalankan ujian tersebut terhadap pelayan Ollama lalai dan jumlahnya hampir tidak berubah. OLLAMA_NUM_PARALLEL ditetapkan kepada 1 secara lalai, jadi satu permintaan dijalankan sementara yang lain menunggu, dan baris gilir inilah yang menyebabkan p99 TTFT meningkat manakala output keseluruhan kekal mendatar. Tingkatkan nilainya sebelum anda mengukur apa-apa.
sudo systemctl edit ollama.service[Service]
Environment="OLLAMA_NUM_PARALLEL=8"Mulakan semula dengan sudo systemctl restart ollama, kemudian sahkan model tersebut masih dimuatkan. Setiap slot selari mendapat bahagiannya sendiri daripada tetingkap konteks, jadi dokumentasi Ollama menyatakan bahawa konteks 2K dengan 4 permintaan selari memperuntukkan 8K. Tingkatkan bilangan slot sehingga model melimpah keluar daripada VRAM. Semak ollama ps: lajur PROCESSOR yang membaca sesuatu seperti 48%/52% CPU/GPU bermakna sebahagian daripada model berada pada CPU, dan daya pemprosesan kini akan jatuh apabila anda menambah konkurensi dan bukannya meningkat. Melepasi slot selari, permintaan beratur sehingga OLLAMA_MAX_QUEUE, iaitu 512 secara lalai, selepas itu pelayan akan menjawab 503.
vLLM menggunakan continuous batching, jadi ia membenarkan permintaan baharu masuk ke dalam batch yang sedang berjalan apabila slot dikosongkan, dan keluknya terus meningkat sehingga KV cache kehabisan. Ollama mengoptimumkan untuk satu model, satu mesin, dengan kos penyediaan yang rendah. Oleh itu, kedua-dua enjin memberikan jawapan yang berbeza kepada ujian yang sama, yang merupakan subjek sebenar bagi Ollama dan vLLM dibandingkan sebagai enjin penyajian. Rekodkan enjin dan versi yang menghasilkan setiap nombor.
Lima cara mengukur perkara yang salah
- Pelanggan berada jauh. Penandaarasan dari komputer riba anda melalui internet menambah masa pergi-balik (round trip) pada setiap TTFT, jadi anda sebenarnya mengukur sambungan internet rumah anda. Jalankan pelanggan di rantau yang sama dengan pelayan.
- Model berada dalam keadaan sejuk (cold). Permintaan pertama menanggung beban pemuatan pemberat (weight loading), dan pada vLLM ia juga mungkin menanggung beban tangkapan graf (graph capture). Hantar kelompok pemanas (warmup batch) dan abaikan hasilnya.
- Prefix caching menjawab bagi pihak anda. vLLM mendayakan prefix caching automatik secara lalai, jadi menghantar prompt yang sama berulang kali akan mengukur cache dan bukannya prefill, menyebabkan TTFT merosot kepada sebahagian kecil daripada nilai sebenar.
--dataset-name randommengelakkan perkara ini kerana setiap prompt adalah berbeza. Untuk kepastian, mulakan pelayan dengan--no-enable-prefix-caching. - Output terlalu pendek. Dengan jawapan 32-token, TTFT mendominasi setiap permintaan dan nilai token per saat anda sebenarnya hanya menggambarkan prefill. Gunakan
--ignore-eosdengan panjang output yang realistik. - Anda melaporkan konkurensi 1. Ia adalah nombor yang paling mesra dalam helaian data dan tidak mempunyai kaitan dengan kos.
Tukarkan nombor yang diukur kepada keputusan
Ambil daya pemprosesan output tepu daripada ujian anda, bukan kadar aliran tunggal, dan bandingkan dengan harga per-token. Titik pulang modal adalah hasil satu pembahagian:
break_even_tok_s = (price_per_hour / price_per_million_output_tokens) * 1000000 / 3600Lakukan pengiraan ini menggunakan harga DigitalOcean bagi Julai 2026. Endpoint inferens khusus H200 mereka berharga $4.47 sejam, manakala setara serverless berharga $0.65 bagi setiap sejuta token. Jadi, 4.47 dibahagikan dengan 0.65 ialah 6.88 juta token sejam, dan membahagikannya dengan 3,600 saat memberikan kira-kira 1,910 token output sesaat. Harga tersebut adalah milik mereka. Pembahagian itu adalah milik kami.
Perkataan yang menentukan keputusan ini ialah berterusan (sustained). Mencapai 1,910 token sesaat pada tahap tepu selama dua jam sehari bukanlah 1,910 token sesaat secara berterusan, kerana anda perlu membayar untuk dua puluh dua jam yang lain juga. Titik silang DigitalOcean sendiri untuk GPU Droplet yang lebih murah pada harga $3.44 sejam berada pada tahap penggunaan purata berterusan 72.2 peratus, dan di bawah tahap itu, harga per-token adalah lebih menguntungkan. Jam GPU yang melahu, bukannya token yang perlahan, biasanya menjadi punca kegagalan pengehosan kendiri.
Oleh itu, keputusan anda mempunyai dua input. Ujian tersebut memberikan anda had maksimum. Corak trafik anda memberikan pecahan daripada had maksimum tersebut yang sebenarnya anda peroleh. Darabkan kedua-duanya, kemudian bawa hasilnya ke titik pulang modal GPU VPS berbanding API per-token dan lihat jawapan untuk volum anda.
FAQ
Apakah kadar token per saat yang baik untuk LLM yang dihoskan sendiri?
Terdapat dua jawapan, kerana metrik ini mempunyai dua fungsi. Bagi seorang individu yang membaca output, sebarang kadar melebihi kira-kira 20 token output sesaat bagi setiap aliran sudah lebih pantas daripada kelajuan membaca, jadi kadar yang lebih tinggi tidak memberikan kelebihan. Dari segi kos, angka yang penting ialah jumlah throughput output tepu, dan "baik" bermaksud apa sahaja yang melepasi titik pulang modal anda. Berbanding $0.65 bagi setiap sejuta token pada pelayan yang berharga $4.47 sejam, paras minimum tersebut berada sekitar 1,910 token output sesaat yang dikekalkan pada harga Julai 2026. Satu aliran pada model besar tidak akan mencapai tahap ini, itulah sebabnya batching wujud.
Mengapa throughput Ollama saya kekal mendatar apabila saya menambah permintaan serentak?
OLLAMA_NUM_PARALLEL ditetapkan secara lalai kepada 1, jadi pelayan menjalankan satu permintaan pada satu masa bagi setiap model dan meletakkan selebihnya dalam baris gilir, sehingga OLLAMA_MAX_QUEUE (512 secara lalai) sebelum mengembalikan ralat 503. Jumlah output kekal mendatar sementara p99 TTFT meningkat, yang merupakan petanda bagi baris gilir dan bukannya GPU yang sibuk. Tetapkan pemboleh ubah tersebut dalam drop-in systemd dan mulakan semula, kemudian semak ollama ps, kerana setiap slot selari akan mendarabkan konteks yang diperuntukkan dan boleh menolak sebahagian daripada model ke CPU.
Patutkah saya mengukur masa ke token pertama (TTFT) atau token per saat?
Kedua-duanya, kerana ia bergerak ke arah bertentangan apabila beban meningkat. TTFT ialah apa yang dirasai oleh pengguna, dan throughput output tepu ialah apa yang dicerminkan oleh invois anda. Rekod p50 dan p99 TTFT pada setiap langkah konkurensi, kemudian pilih konkurensi tertinggi di mana p99 TTFT masih boleh diterima oleh anda. Laporkan throughput pada titik tersebut sebagai kapasiti anda, bukan nilai maksimum dari puncak lengkung.
Adakah angka token per saat yang lebih tinggi sentiasa bermakna kos per token yang lebih rendah?
Tidak. Kos per token ialah harga sejam dibahagikan dengan token yang sebenarnya dihasilkan oleh pelayan dalam jam tersebut, jadi pelayan yang pantas tetapi melahu sepanjang hari masih mempunyai kos per token yang tinggi. Penggunaan (utilisation) yang menentukan kos, bukan kelajuan puncak. Perhatikan juga unitnya: jumlah throughput token yang dipetik mengira token input, jadi pada nisbah input kepada output 1:1, ia hampir dua kali ganda kadar output yang dikenakan bayaran kepada anda.