Model yang menampilkan token terlihat pertamanya paling cepat dalam pengujian terbaru kami ternyata juga yang paling lambat untuk selesai. Pada 2026-10-03, kami melakukan streaming satu prompt melalui empat model. claude-sonnet-5-5 memimpin dalam waktu token terlihat pertama (2.981 ms) dan tertinggal dalam total waktu (12.384 ms). Kesenjangan tersebut adalah inti dari LLM latency vs throughput: satu angka menunjukkan berapa lama pengguna menunggu untuk melihat teks, angka lainnya menunjukkan seberapa cepat pekerjaan selesai. Artikel ini mendefinisikan setiap metrik, menunjukkan pengukuran pihak pertama kami yang terbatas, dan memberikan alat (harness) yang dapat Anda jalankan terhadap TokenLab API.
Poin Penting
- Tiga angka, tiga tugas. Time to first token, total time, dan output tokens per second menjawab pertanyaan yang berbeda. Chat, agen, dan pekerjaan batch masing-masing mengandalkan metrik yang berbeda.
- Pisahkan event pertama dari token terlihat pertama. Pada
deepseek-v4.1-flash, kedua median tersebut berjarak 2.334 ms dan 3.925 ms. Delta penalaran (reasoning) bisa tiba jauh sebelum teks terlihat muncul. - Token penalaran menghabiskan anggaran
max_tokensAnda. Padamax_tokens400,deepseek-v4.1-flashmengembalikan sekitar 0 token terlihat dangemini-3.8-flashsekitar 14. Pada 2000, keduanya menjawab secara penuh. - Baca jumlah token dari chunk penggunaan (usage chunk). Jangan mengestimasinya dari karakter.
- Kecepatan model tidak menaikkan batas permintaan Anda. Rate limit, token limit, dan kecepatan model adalah batasan yang terpisah.
- Sampel kami kecil. Ini mencakup lima kali pengujian per model, satu klien, satu prompt, dan satu hari. Ini menunjukkan cara mengukur, bukan siapa yang tercepat.
Tiga angka kecepatan: LLM latency vs throughput dalam praktik
Bagi "kecepatan" menjadi beberapa bagian, karena setiap bagian memiliki pemilik yang berbeda: jaringan, model, dan antrean Anda sendiri.
send request
-> first stream event (setiap chunk SSE; bisa berupa delta penalaran)
-> first visible content token (delta.content non-kosong pertama)
-> last token + final usage chunk
Time to first token (TTFT) adalah waktu dari pengiriman permintaan hingga token pertama tiba. Kami mencatat dua versi. First stream event adalah chunk SSE pertama dalam bentuk apa pun. First visible content token adalah chunk pertama yang choices[0].delta.content-nya tidak kosong. Untuk model yang melakukan penalaran sebelum menjawab, event pertama bisa berupa delta penalaran (delta.reasoning_content) yang mendarat jauh sebelum teks terlihat. Alat yang hanya memantau delta.content mengukur waktu hingga token terlihat pertama, bukan waktu hingga byte pertama. Pengguna merasakan yang terlihat.
Total time berjalan dari pengiriman permintaan hingga akhir stream. Ini mencakup penalaran, waktu jaringan, dan waktu tunggu percobaan ulang (retry) yang Anda tambahkan.
Output tokens per second adalah token output dibagi dengan total waktu. Ambil jumlah token dari usage.completion_tokens, yang mencakup token penalaran. Kami membaginya dengan total waktu, bukan dengan jendela terlihat. Beberapa model dalam sampel kami mengirimkan teks terlihat dalam beberapa chunk besar, sehingga tingkat berbasis jendela akan menyesatkan.
| Beban Kerja | Pantau pertama | Kemudian | Mengapa |
|---|---|---|---|
| Chat | First visible token | Total time | Pengguna melihat kotak kosong sampai teks terlihat muncul. |
| Agen | Total time | First visible token | Setiap langkah biasanya menunggu langkah sebelumnya, jadi total per langkah terakumulasi. |
| Ekstraksi batch atau ringkasan | Output tokens per second, dan biaya per tugas | Request limit headroom | Tidak ada yang memantau token pertama, dan batas permintaan akun membatasi seberapa cepat Anda dapat mengirimkan pekerjaan. |
Panggilan non-streaming, seperti ekstraksi JSON terstruktur, hanya menampilkan total waktu. Lakukan streaming saat pengujian jika Anda menginginkan pemisahan tersebut.
Apa yang kami ukur pada 2026-10-03
Metode. Ini adalah pengukuran pihak pertama TokenLab, diamati pada 2026-10-03, terhadap POST https://api.tokenlab.sh/v1/chat/completions (sumber). Setiap permintaan menggunakan stream=true dan stream_options.include_usage=true. Kami menjalankan 5 kali pengujian berurutan per model dari satu klien di Asia Timur, menggunakan Node 24 fetch. Prompt-nya adalah "Explain how HTTP keep-alive reduces latency for API clients. Write about 200 words." Setiap model menggunakan pengaturan penalaran default. Waktu adalah waktu jam dinding sisi klien, dan semua pengujian berhasil (5/5) untuk setiap baris di bawah.
Model (max_tokens 2000) |
Median first stream event | Median first visible token | Median total time | Median completion tokens (reasoning) | Estimated tokens/s |
|---|---|---|---|---|---|
deepseek-v4.1-flash |
2.334 ms | 3.925 ms | 5.204 ms | 453 (225) | 87 |
gemini-3.8-flash |
6.892 ms | 6.892 ms | 8.626 ms | 826 (528) | 96 |
claude-sonnet-5-5 |
2.981 ms | 2.981 ms | 12.384 ms | 418 (tidak dilaporkan) | 34 |
gpt-5.6-luna |
3.262 ms | 3.262 ms | 8.183 ms | 313 (42) | 38 |
Kolom tokens/s adalah estimasi kami sendiri: median token penyelesaian dibagi dengan median total detik, misalnya 453 ÷ 5,204 ≈ 87. Ini adalah rasio median, bukan median dari tingkat per pengujian.
Apa yang ditunjukkan oleh angka-angka tersebut, dan tidak lebih:
- Pengurutan berdasarkan token terlihat pertama (
claude-sonnet-5-5,gpt-5.6-luna,deepseek-v4.1-flash,gemini-3.8-flash) berbeda dari pengurutan berdasarkan total waktu (deepseek-v4.1-flash,gpt-5.6-luna,gemini-3.8-flash,claude-sonnet-5-5). Satu metrik tidak bisa menggantikan yang lain. deepseek-v4.1-flashmemiliki kesenjangan 1.591 ms antara event pertama dan token terlihat pertama. Median output terlihatnya sekitar 228 token, dikirim dalam 87 event selama 1.304 ms.- Untuk
gemini-3.8-flash, event pertama dan token terlihat pertama berbagi median 6.892 ms. Teks terlihatnya muncul dalam median 11 event selama 1.734 ms, jadi stream-nya bersifat bongkahan (chunky) daripada per token. claude-sonnet-5-5mengirimkan median 371 event selama 9.186 ms, dangpt-5.6-lunamengirimkan 265 event selama 4.901 ms.
Biaya berada di samping kecepatan. Harga di bawah berasal dari API model TokenLab, diamati pada 2026-10-03, dengan harga diperbarui pada 2026-10-02T16:53:30.068Z. Kolom terakhir adalah estimasi: median token penyelesaian dikalikan dengan tarif output, sisi output saja. Periksa catatan penggunaan untuk biaya sebenarnya.
| Model | Input per 1J | Output per 1J | Max output tokens | Estimasi sisi output, median run | Sumber |
|---|---|---|---|---|---|
deepseek-v4.1-flash |
$0,15 off-peak, $0,30 peak | $0,60 off-peak, $1,20 peak | 384.000 | 453 × $0,60 / 1J ≈ $0,00027 off-peak, ≈ $0,00054 peak | model API |
gemini-3.8-flash |
$0,375 | $1,875 | 65.536 | 826 × $1,875 / 1J ≈ $0,00155 | model API |
claude-sonnet-5-5 |
$0,60 | $3 | 128.000 | 418 × $3 / 1J ≈ $0,00125 | model API |
gpt-5.6-luna |
$0,06 | $0,36 | 128.000 | 313 × $0,36 / 1J ≈ $0,00011 | model API |
Untuk gpt-5.6-luna, tarif tersebut berlaku ketika input maksimal 272K token. Di atas itu, permintaan penuh menggunakan tarif input 2x dan output 1,5x.
Batasan sampel ini. Lima pengujian berurutan dari satu klien di Asia Timur adalah irisan yang tipis. Prompt-nya adalah satu permintaan esai singkat, jadi hasil akan bergeser dengan wilayah, waktu, prompt, dan panjang output. Kami tidak menguji konkurensi, jadi tidak ada yang menyatakan apa yang terjadi di bawah beban. Perlakukan tabel sebagai templat untuk pengujian Anda sendiri, dijalankan dari wilayah tempat produksi berjalan. Jika Anda menginginkan pandangan model yang lebih luas, TokenLab LLM API leaderboard for developers adalah titik awal. Periksa metode dan tanggalnya sebelum Anda mempercayai angka kecepatan apa pun di sana. Jangan menukar model secara diam-diam juga: panduan keandalan, diamati pada 2026-10-03, mencatat bahwa penggantian dapat mengubah kualitas, harga, panjang konteks, dan alat.
Token penalaran dan max_tokens: mengapa 400 tidak mengembalikan apa pun
Kami juga menjalankan prompt yang sama dengan max_tokens diatur ke 400. Metode yang sama, lima pengujian yang sama, tanggal yang sama (sumber).
Model (max_tokens 400) |
Median completion tokens | Median reasoning tokens | Visible output (approx.) | Median first visible token | Median total time |
|---|---|---|---|---|---|
deepseek-v4.1-flash |
400 | 400 | 0 token | 3.795 ms | 4.693 ms |
gemini-3.8-flash |
396 | 382 | 14 token | 4.199 ms | 4.240 ms |
claude-sonnet-5-5 |
400 | tidak dilaporkan | 400 token | 3.088 ms | 11.078 ms |
gpt-5.6-luna |
317 | 42 | 275 token | 3.040 ms | 8.083 ms |
Median dihitung per kolom, jadi kolom satu baris tidak perlu mendeskripsikan satu pengujian. Itulah sebabnya deepseek-v4.1-flash menunjukkan waktu terlihat pertama di samping median nol event terlihat.
Temuannya jelas. deepseek-v4.1-flash dan gemini-3.8-flash menghabiskan hampir seluruh anggaran 400-token untuk penalaran dan hampir tidak mengembalikan teks terlihat. Menaikkan max_tokens ke 2000 menghasilkan jawaban lengkap. Token penalaran dihitung di dalam usage.completion_tokens. Mereka dilaporkan secara terpisah di usage.completion_tokens_details.reasoning_tokens.
Ketika kami melihat hasil 400-token pertama, kegagalannya tampak seperti jawaban kosong, bukan masalah anggaran. Tiga pemeriksaan membuatnya terlihat:
- Baca chunk penggunaan akhir, diaktifkan oleh
stream_options={"include_usage": True}. Jikareasoning_tokensmendekaticompletion_tokensdan teks kosong, anggaran habis untuk penalaran. - Periksa
finish_reason. Panduan streaming (diamati pada 2026-10-03) mencantumkanlengthsebagai nilai ketika batas token tercapai. - Bandingkan dengan output maksimum model. Misalnya, API model mencantumkan 384.000 untuk
deepseek-v4.1-flashdan 65.536 untukgemini-3.8-flash, jadi 400 adalah irisan kecil dari apa yang diizinkan model.
Referensi Create Chat Completion (diamati pada 2026-10-03) juga mencantumkan max_completion_tokens dan reasoning_effort. Dikatakan nilai yang didukung bergantung pada model, jadi baca halaman model sebelum mengatur keduanya. Kami tidak mengujinya, dan kami menjalankan setiap baris dengan penalaran default. Sesuaikan batas dari prompt Anda sendiri: dalam pengujian kami, jawaban 200 kata menghasilkan sekitar 228 hingga 418 token terlihat, dan hingga 528 token penalaran di atasnya.
Alat pengukuran untuk URL dasar TokenLab
Skrip ini menggunakan URL dasar TokenLab, membaca jumlah token dari chunk penggunaan, dan mencatat event stream pertama secara terpisah dari token konten terlihat pertama. Skrip ini juga menyimpan header respons untuk debugging nanti. Skrip ini mengikuti pengaturan klien dalam dokumentasi (timeout=30.0, max_retries=0) sehingga SDK tidak menambahkan percobaan ulang tersembunyi ke waktu Anda. ID model adalah salah satu yang kami ukur; tukar dengan ID apa pun yang format permintaan yang diterimanya mencakup openai_chat_completions.
import json
import os
import statistics
import time
from openai import OpenAI
client = OpenAI(
api_key=os.environ["TOKENLAB_API_KEY"],
base_url="https://api.tokenlab.sh/v1",
timeout=30.0,
max_retries=0,
)
PROMPT = "Explain how HTTP keep-alive reduces latency for API clients. Write about 200 words."
def measure(model: str, max_tokens: int = 2000) -> dict:
start = time.perf_counter()
raw = client.chat.completions.with_raw_response.create(
model=model,
messages=[{"role": "user", "content": PROMPT}],
max_tokens=max_tokens,
stream=True,
stream_options={"include_usage": True},
)
headers = raw.headers
first_event = first_visible = None
visible_events = 0
usage = None
finish_reason = None
for chunk in raw.parse():
now = time.perf_counter() - start
if first_event is None:
first_event = now
if chunk.usage is not None:
usage = chunk.usage
if not chunk.choices:
continue
choice = chunk.choices[0]
if choice.delta.content:
visible_events += 1
if first_visible is None:
first_visible = now
if choice.finish_reason:
finish_reason = choice.finish_reason
total = time.perf_counter() - start
details = getattr(usage, "completion_tokens_details", None)
completion = usage.completion_tokens if usage else None
return {
"model": model,
"request_id": headers.get("x-request-id"),
"routing_time_ms": headers.get("x-routing-time-ms"),
"first_event_s": first_event,
"first_visible_s": first_visible,
"total_s": total,
"completion_tokens": completion,
"reasoning_tokens": getattr(details, "reasoning_tokens", None),
"visible_events": visible_events,
"finish_reason": finish_reason,
"tokens_per_s": completion / total if completion else None,
}
if __name__ == "__main__":
runs = [measure("gemini-3.8-flash") for _ in range(5)]
print(json.dumps(runs[0], indent=2))
print("median total_s:", statistics.median(r["total_s"] for r in runs))
Beberapa catatan tentang membaca output:
first_event_saktif pada chunk apa pun, termasuk chunk khusus peran atau penalaran.first_visible_saktif hanya padadelta.contentyang tidak kosong. Jika keduanya berbeda beberapa detik, model sedang melakukan penalaran sebelum menjawab.- Jumlah token berasal dari chunk penggunaan akhir. Chunk tersebut memiliki daftar
choiceskosong, itulah sebabnya loop memeriksachunk.usagesebelum melewatinya. - Jalankan lima kali atau lebih, catat wilayahnya, dan laporkan median beserta ukuran sampel.
- Untuk model yang mencantumkan
openai_responses, panduan streaming menunjukkan Respons streaming dengan eventresponse.output_text.deltadanresponse.completed. Pemisahan yang sama berlaku: catat waktu event pertama, lalu delta teks pertama. - Perlakukan stream yang ditutup sebelum
response.completedatau alasan selesaistopsebagai tidak lengkap, bukan sebagai keberhasilan yang cepat.
Header dan pengenal untuk dicatat guna debugging latensi
Permintaan yang lambat sulit di-debug jika Anda hanya menyimpan durasi. Referensi API dan panduan pemecahan masalah, keduanya diamati pada 2026-10-03, menyebutkan pengenal yang layak disimpan.
| Pengenal | Di mana muncul | Gunakan untuk |
|---|---|---|
X-Request-ID |
Header respons, jika tersedia | Dukungan dan debugging untuk satu permintaan |
request_id |
Badan kesalahan, log dasbor, catatan penggunaan | Dukungan tingkat permintaan dan rekonsiliasi |
X-Routing-Time-MS |
Header respons, jika tersedia | Waktu yang dihabiskan untuk memilih pengiriman, sebelum pembuatan |
X-Task-ID, task_id, poll_url |
Respons pembuatan dan status asinkron | Pekerjaan gambar, video, musik, dan 3D |
X-Billing-Transaction-ID |
Header setelah penagihan akhir, jika tersedia | Rekonsiliasi biaya |
| ID pekerjaan atau pengguna Anda sendiri | Aplikasi Anda | Menemukan permintaan di balik keluhan pengguna |
Untuk setiap panggilan, catat endpoint, metode, model, kode status, stempel waktu, dan latensi. Tambahkan nama bidang yang Anda kirim (bukan prompt), jumlah percobaan ulang Anda, dan apakah percobaan ulang membuat tugas baru atau melanjutkan tugas yang ada. Alat kami menambahkan waktu pemisahan dan jumlah token dari chunk penggunaan.
Dua peringatan. Respons streaming mungkin selesai setelah stream berakhir, sehingga header penagihan bisa absen bahkan ketika penggunaan dicatat nanti. Untuk jumlah yang ditagih, gunakan catatan penggunaan Management API alih-alih hanya jumlah token respons. Juga catat nilai X-TokenLab-Delivery-Policy jika Anda mengaturnya. Referensi menyatakan bahwa itu menerima auto, verified, atau official, bahwa nilai yang tidak valid mengembalikan 400, dan bahwa opsi yang tidak tersedia mengembalikan 503 dengan code: delivery_tier_unavailable dan retryable: true. Jangan pernah mencatat Authorization, kunci API, URL yang ditandatangani, prompt lengkap, atau data pribadi.
Detail permintaan konsol disimpan selama 30 hari sejak penangkapan, jadi salin ID yang Anda perlukan ke log Anda sendiri. Dalam pipeline kami, kami menyelaraskan ID ini dengan tampilan permintaan; postingan TokenLab request console mencakup tampilan tersebut.
Rate limit, retry, dan LLM latency vs throughput
Kecepatan per-stream dan throughput akun adalah batasan yang berbeda. Panduan rate limit, diamati pada 2026-10-03, mencantumkan nilai tingkat standar di bawah. Panduan tersebut mencatat bahwa nilai tersebut dapat berubah dengan konfigurasi aktif dan diberlakukan per kunci API.
| Tingkat | Permintaan per menit |
|---|---|
| Pengguna | 1.000 |
| Mitra | 10.000 |
| VIP | 10.000 |
Ketika Anda melewati batas, API mengembalikan 429 rate_limit_exceeded dengan header Retry-After. Badan contoh panduan membawa "retryable": true dan "retry_after": 8. Panduan mengatakan untuk mempercayai nilai X-RateLimit-Limit dan Retry-After yang dikembalikan daripada tabel yang disalin. Panduan juga mengatakan bahwa model yang lebih cepat tidak meningkatkan batas permintaan akun Anda.
Berikut adalah aritmatika untuk pekerjaan batch. Ini adalah estimasi kami dari median di atas, bukan uji beban. Stream konkuren kira-kira adalah permintaan per detik dikalikan detik per permintaan. Pada 1.000 permintaan per menit (sekitar 16,7 per detik):
- Dengan
deepseek-v4.1-flashpada median total 5,204 s, sekitar 87 stream berjalan sekaligus. - Dengan
claude-sonnet-5-5pada median 12,384 s, sekitar 206 stream berjalan sekaligus.
Stream yang lebih lambat berarti lebih banyak konkurensi untuk mencapai tingkat permintaan yang sama. Mencapai batas kemudian menambahkan waktu tunggu di atas waktu pembuatan. Batas token tidak tercakup dalam halaman yang kami gunakan, jadi periksa akun Anda dan halaman model untuk itu.
Cara melakukan retry tanpa merusak angka Anda:
- Hormati
Retry-Aftersaat ada. Jika tidak, gunakan exponential backoff dengan jitter acak dan batas percobaan yang ketat. - Atur SDK ke
max_retries=0dan lakukan retry di satu tempat. Jika tidak, dua lapisan akan melakukan retry pada panggilan yang sama dan waktu Anda akan terhitung ganda. - Jangan pernah melakukan retry pada kesalahan validasi, autentikasi, saldo, atau izin. Lakukan retry pada respons
5xxsementara dengan backoff singkat. - Setelah event pertama tiba, stream yang terputus tidak lengkap dan tidak dimulai ulang secara otomatis. Mengulangi permintaan dapat menghasilkan output yang berbeda dan biaya lain.
- Catat jumlah retry dan waktu tunggu secara terpisah dari waktu model, sehingga pengujian yang dibatasi tidak terlihat seperti model yang lambat.
Ini adalah pola retry terbatas panduan:
import random
import time
from openai import RateLimitError
def chat_with_rate_limit_retry(client, model, messages, attempts=4):
for attempt in range(attempts):
try:
return client.with_options(max_retries=0).chat.completions.create(
model=model,
messages=messages,
)
except RateLimitError as exc:
if attempt == attempts - 1:
raise
header = exc.response.headers.get("Retry-After")
wait = float(header) if header else min(30, 2 ** attempt + random.random())
time.sleep(wait)
Juga batasi konkurensi, bukan hanya rata-rata permintaan per menit, dan antrekan lonjakan. Lacak respons 429 berulang per kunci API sehingga satu klien tidak dapat menyingkirkan aplikasi Anda yang lain.
FAQ
Apakah token per detik yang lebih tinggi selalu berarti pengalaman pengguna yang lebih cepat?
Tidak. Dalam sampel 2026-10-03 kami, claude-sonnet-5-5 menunjukkan token terlihat pertama paling awal (2.981 ms) tetapi total waktu terlama (12.384 ms). deepseek-v4.1-flash memulai teks terlihat lebih lambat (3.925 ms) dan selesai lebih dulu (5.204 ms). Mana yang terasa lebih cepat bergantung pada apakah pengguna menonton stream atau menunggu jawaban lengkap. Lima pengujian dari satu klien tidak dapat menyelesaikannya untuk beban kerja Anda.
Mengapa respons streaming saya kembali dengan hampir tidak ada teks?
Anda mungkin menghabiskan anggaran untuk penalaran. Pada max_tokens 400, deepseek-v4.1-flash menggunakan 400 token penalaran dan mengembalikan sekitar 0 token terlihat. Periksa usage.completion_tokens_details.reasoning_tokens di chunk penggunaan akhir dan finish_reason. Kemudian naikkan batasnya; pada 2000, kedua model penalaran dalam pengujian kami menjawab secara penuh.
Apakah model yang lebih cepat menaikkan rate limit saya?
Tidak. Panduan rate limit mengatakan kecepatan model, batas token, dan rate limit akun adalah batasan yang terpisah. Stream yang lebih cepat selesai lebih cepat dan mengosongkan slot konkurensi, tetapi batas permintaan per-kunci Anda tetap sama. Minta dukungan untuk batas yang berbeda jika Anda membutuhkannya.
ID mana yang harus saya kirim ke dukungan ketika stream lambat?
Kirim request_id (atau X-Request-ID), endpoint, metode, model, stempel waktu, dan kode status. Tambahkan task_id dan poll_url untuk pekerjaan asinkron dan billing_transaction_id jika ada. Sertakan waktu pemisahan Anda dan badan kesalahan yang aman, dan redaksi kunci, prompt, serta media pribadi terlebih dahulu.
Jalankan alat di atas pada prompt Anda sendiri, lalu bandingkan apa yang Anda ukur dengan peringkat model TokenLab.
Sumber
Harga diamati pada 2026-10-03
- TokenLab Docs: StreamingDiamati pada 2026-10-03
- TokenLab Docs: Rate limitsDiamati pada 2026-10-03
- TokenLab Docs: Logs and troubleshootingDiamati pada 2026-10-03
- TokenLab Docs: Build a reliable TokenLab integrationDiamati pada 2026-10-03
- TokenLab Docs: API ReferenceDiamati pada 2026-10-03
- TokenLab Docs: Create Chat CompletionDiamati pada 2026-10-03
- TokenLab live model API: deepseek-v4.1-flashDiamati pada 2026-10-03
- TokenLab live model API: gemini-3.8-flashDiamati pada 2026-10-03
