最新のテストにおいて、最初の可視トークンを最も早く表示したモデルは、完了までの時間は最も遅いという結果になりました。2026年10月3日、私たちは1つのプロンプトを4つのモデルでストリーミングしました。claude-sonnet-5-5は最初の可視トークン(2,981 ms)で先頭に立ちましたが、合計時間(12,384 ms)では最後尾でした。このギャップこそが、LLMのレイテンシとスループットの核心です。一方はユーザーがテキストを見るまでの待ち時間を示し、もう一方は作業が完了するまでの速さを示しています。本稿では各メトリクスを定義し、私たちの小規模な一次測定とその限界を示し、TokenLab APIに対して実行可能な測定用ハーネスを提供します。
重要なポイント
- 3つの数値、3つの役割。 最初のトークンまでの時間(TTFT)、合計時間、および1秒あたりの出力トークン数は、それぞれ異なる問いに答えるものです。チャット、エージェント、バッチ処理は、それぞれ異なる指標に依存します。
- 最初のイベントと最初の可視トークンを分ける。
deepseek-v4.1-flashでは、これら2つのメディアン(中央値)の間に2,334 msと3,925 msの差がありました。推論デルタは、可視テキストが表示されるよりもずっと前に到着する可能性があります。 - 推論トークンは
max_tokensの予算を消費する。max_tokensを400に設定した場合、deepseek-v4.1-flashは可視トークンをほぼ0返し、gemini-3.8-flashは約14返しました。2000に設定すると、両者とも完全な回答を返しました。 - トークン数は使用量チャンクから読み取る。 文字数から推定してはいけません。
- モデルの速度はリクエスト制限を引き上げない。 レート制限、トークン制限、モデルの速度はそれぞれ独立した制約です。
- サンプルは小規模。 モデルごとに5回の実行、1つのクライアント、1つのプロンプト、1日という条件です。これは測定方法を示すものであり、誰が最速かを決めるものではありません。
3つのスピード数値:実務におけるLLMのレイテンシとスループット
「スピード」を各要素に分解してください。それぞれの要素には、ネットワーク、モデル、そして自身のキューという異なる所有者が存在するためです。
send request
-> first stream event (任意のSSEチャンク。推論デルタの場合がある)
-> first visible content token (最初の空ではないdelta.content)
-> last token + final usage chunk
最初のトークンまでの時間(TTFT)は、リクエスト送信から最初のトークンが到着するまでの時間です。私たちは2つのバージョンを記録しています。最初のストリームイベントは、あらゆる種類の最初のSSEチャンクです。最初の可視コンテンツトークンは、choices[0].delta.contentが空ではない最初のチャンクです。回答前に推論を行うモデルの場合、最初のイベントは可視テキストよりもずっと前に到達する推論デルタ(delta.reasoning_content)である可能性があります。delta.contentのみを監視するハーネスは、最初のバイトまでの時間ではなく、最初の可視トークンまでの時間を測定します。ユーザーが体感するのは後者です。
合計時間は、リクエスト送信からストリーム終了までの時間です。これには推論、ネットワーク時間、および追加したリトライ待ち時間が含まれます。
1秒あたりの出力トークン数は、出力トークン数を合計時間で割ったものです。トークン数は、推論トークンを含む usage.completion_tokens から取得します。可視ウィンドウではなく合計時間で割ります。サンプル内のいくつかのモデルは、可視テキストを数個の大きなチャンクで配信したため、ウィンドウベースのレートでは誤解を招く可能性があります。
| ワークロード | 最初に監視するもの | 次に監視するもの | 理由 |
|---|---|---|---|
| チャット | 最初の可視トークン | 合計時間 | ユーザーは可視テキストが表示されるまで空白のボックスを見ているため。 |
| エージェント | 合計時間 | 最初の可視トークン | 各ステップは通常前のステップを待つため、ステップごとの合計が積み重なる。 |
| バッチ抽出または要約 | 1秒あたりの出力トークン数、タスクあたりのコスト | リクエスト制限の余裕 | 最初のトークンを気にする人はおらず、アカウントのリクエスト制限が作業提出速度の上限となるため。 |
構造化JSON抽出のようなストリーミングを行わない呼び出しは、合計時間のみを公開します。分割して測定したい場合は、テスト時にストリーミングを行ってください。
2026年10月3日の測定結果
手法。 これはTokenLabの一次測定であり、2026年10月3日に POST https://api.tokenlab.sh/v1/chat/completions に対して観測されました(ソース)。各リクエストは stream=true および stream_options.include_usage=true を使用しました。東アジアの単一クライアントから、Node 24の fetch を使用してモデルごとに5回連続で実行しました。プロンプトは「HTTP keep-aliveがAPIクライアントのレイテンシをどのように低減するか説明してください。約200語で書いてください。」です。すべてのモデルでデフォルトの推論設定を使用しました。タイミングはクライアント側のウォールクロックであり、以下のすべての行で実行は成功(5/5)しました。
モデル (max_tokens 2000) |
最初のストリームイベント中央値 | 最初の可視トークン中央値 | 合計時間中央値 | 完了トークン中央値 (推論) | 推定トークン/秒 |
|---|---|---|---|---|---|
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 (未報告) | 34 |
gpt-5.6-luna |
3,262 ms | 3,262 ms | 8,183 ms | 313 (42) | 38 |
トークン/秒の列は独自の推定値です:完了トークン中央値を合計時間中央値で割ったもの(例:453 ÷ 5.204 ≈ 87)。これは中央値の比率であり、実行ごとのレートの中央値ではありません。
数値が示すこと(それ以上でも以下でもありません):
- 最初の可視トークンによる順序(
claude-sonnet-5-5,gpt-5.6-luna,deepseek-v4.1-flash,gemini-3.8-flash)は、合計時間による順序(deepseek-v4.1-flash,gpt-5.6-luna,gemini-3.8-flash,claude-sonnet-5-5)とは異なります。一方のメトリクスで他方を代用することはできません。 deepseek-v4.1-flashは、最初のイベントと最初の可視トークンの間に1,591 msのギャップがありました。可視出力の中央値は約228トークンで、1,304 msかけて87個のイベントで配信されました。gemini-3.8-flashでは、最初のイベントと最初の可視トークンの中央値は6,892 msで一致しています。可視テキストは1,734 msかけて11個のイベントで配信されたため、ストリームはトークンごとではなくチャンク状でした。claude-sonnet-5-5は9,186 msかけて371個のイベントを送信し、gpt-5.6-lunaは4,901 msかけて265個のイベントを送信しました。
コストはスピードと並ぶ重要な要素です。以下の価格は2026年10月3日に観測されたTokenLabモデルAPIによるもので、価格は2026-10-02T16:53:30.068Zに更新されています。最後の列は推定値です:完了トークン中央値にレートを掛けたもの(出力側のみ)。実際の請求額については使用量レコードを確認してください。
| モデル | 入力/100万 | 出力/100万 | 最大出力トークン | 出力側推定(中央値) | ソース |
|---|---|---|---|---|---|
deepseek-v4.1-flash |
$0.15 (オフピーク), $0.30 (ピーク) | $0.60 (オフピーク), $1.20 (ピーク) | 384,000 | 453 × $0.60 / 1M ≈ $0.00027 (オフピーク), ≈ $0.00054 (ピーク) | model API |
gemini-3.8-flash |
$0.375 | $1.875 | 65,536 | 826 × $1.875 / 1M ≈ $0.00155 | model API |
claude-sonnet-5-5 |
$0.60 | $3 | 128,000 | 418 × $3 / 1M ≈ $0.00125 | model API |
gpt-5.6-luna |
$0.06 | $0.36 | 128,000 | 313 × $0.36 / 1M ≈ $0.00011 | model API |
gpt-5.6-luna の場合、これらのレートは入力が最大272Kトークンの場合に適用されます。それを超えると、リクエスト全体で2倍の入力レートと1.5倍の出力レートが適用されます。
このサンプルの限界。 東アジアの1クライアントからの5回の連続実行は非常に限定的なスライスです。プロンプトは短いエッセイのリクエスト1つであるため、結果は地域、時間帯、プロンプト、出力長によって変化します。並行性はテストしていないため、負荷がかかった場合に何が起こるかは示していません。この表は、本番環境を実行する地域から実行するためのテンプレートとして扱ってください。モデルのより広い視野が必要な場合は、TokenLabのLLM APIリーダーボードが出発点となります。数値を信頼する前に、その手法と日付を確認してください。モデルを黙って入れ替えることも避けてください。信頼性ガイド(2026年10月3日観測)では、置き換えによって品質、価格、コンテキスト長、ツールが変更される可能性があると指摘されています。
推論トークンと max_tokens:なぜ400でほとんど何も返されなかったのか
同じプロンプトで max_tokens を400に設定して実行しました。手法、5回の実行、日付は同じです(ソース)。
モデル (max_tokens 400) |
完了トークン中央値 | 推論トークン中央値 | 可視出力 (概算) | 最初の可視トークン中央値 | 合計時間中央値 |
|---|---|---|---|---|---|
deepseek-v4.1-flash |
400 | 400 | 0 トークン | 3,795 ms | 4,693 ms |
gemini-3.8-flash |
396 | 382 | 14 トークン | 4,199 ms | 4,240 ms |
claude-sonnet-5-5 |
400 | 未報告 | 400 トークン | 3,088 ms | 11,078 ms |
gpt-5.6-luna |
317 | 42 | 275 トークン | 3,040 ms | 8,083 ms |
中央値は列ごとに計算されるため、1行の列が単一の実行を記述しているとは限りません。そのため、deepseek-v4.1-flash は可視イベント中央値が0であるにもかかわらず、最初の可視時間が表示されています。
結果は明らかです。deepseek-v4.1-flash と gemini-3.8-flash は400トークンの予算のほぼすべてを推論に費やし、可視テキストをほとんど返しませんでした。max_tokens を2000に引き上げると完全な回答が得られました。推論トークンは usage.completion_tokens 内でカウントされます。これらは usage.completion_tokens_details.reasoning_tokens に個別に報告されます。
最初の400トークンの結果を見たとき、失敗は予算の問題ではなく空の回答のように見えました。以下の3つのチェックで原因が判明します:
stream_options={"include_usage": True}で有効にした最終使用量チャンクを読み取ります。reasoning_tokensがcompletion_tokensに近く、テキストが空であれば、予算は推論に費やされています。finish_reasonを確認します。ストリーミングガイド(2026年10月3日観測)には、トークン制限に達した際の値としてlengthが記載されています。- モデルの最大出力を確認します。例えば、モデルAPIには
deepseek-v4.1-flashは384,000、gemini-3.8-flashは65,536と記載されているため、400はモデルが許可するごく一部に過ぎません。
Create Chat Completionリファレンス(2026年10月3日観測)には max_completion_tokens と reasoning_effort も記載されています。サポートされる値はモデルに依存するため、設定前にモデルページを読んでください。私たちはこれらをテストしておらず、すべての行をデフォルトの推論で実行しました。プロンプトに合わせて上限を設定してください。今回の実行では、200語の回答で約228〜418の可視トークンが生成され、さらに最大528の推論トークンが追加されました。
TokenLabベースURL用の測定ハーネス
このスクリプトはTokenLabベースURLを使用し、使用量チャンクからトークン数を読み取り、最初のストリームイベントを最初の可視コンテンツトークンとは別に記録します。また、後のデバッグのためにレスポンスヘッダーを保持します。SDKがタイミングに隠れたリトライを追加しないよう、ドキュメントのクライアント設定(timeout=30.0, max_retries=0)に従っています。モデルIDは測定済みのものですが、受け入れ可能なリクエスト形式に openai_chat_completions を含むIDであれば何でも入れ替えて使用できます。
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))
出力の読み方に関する注意点:
first_event_sは、ロールのみのチャンクや推論チャンクを含む、あらゆるチャンクで発生します。first_visible_sは、空ではないdelta.contentのみで発生します。両者の間に数秒の差がある場合、モデルは回答前に推論を行っています。- トークン数は最終使用量チャンクから取得されます。そのチャンクは
choicesリストが空であるため、ループ内でchunk.usageを確認してからスキップしています。 - 5回以上実行し、地域を記録し、サンプルサイズとともに中央値を報告してください。
openai_responsesをリストするモデルについては、ストリーミングガイドにresponse.output_text.deltaおよびresponse.completedイベントでストリーミングされるレスポンスが示されています。同様の分割が適用されます:最初のイベント、次に最初のテキストデルタを測定してください。response.completedまたはstop終了理由の前に閉じるストリームは、高速な成功ではなく不完全なものとして扱ってください。
レイテンシデバッグのためにログに記録すべきヘッダーと識別子
遅いリクエストは、期間だけを記録していてもデバッグが困難です。APIリファレンスとトラブルシューティングガイド(いずれも2026年10月3日観測)には、保持すべき識別子が記載されています。
| 識別子 | 出現場所 | 用途 |
|---|---|---|
X-Request-ID |
レスポンスヘッダー (利用可能な場合) | 単一リクエストのサポートとデバッグ |
request_id |
エラーボディ、ダッシュボードログ、使用量レコード | リクエストレベルのサポートと照合 |
X-Routing-Time-MS |
レスポンスヘッダー (利用可能な場合) | 生成前の配信選択にかかった時間 |
X-Task-ID, task_id, poll_url |
非同期作成およびステータスレスポンス | 画像、動画、音楽、3Dジョブ |
X-Billing-Transaction-ID |
最終請求後のヘッダー (利用可能な場合) | コスト照合 |
| 独自のジョブIDまたはユーザーID | アプリケーション | ユーザーの苦情の背後にあるリクエストの特定 |
各呼び出しについて、エンドポイント、メソッド、モデル、ステータスコード、タイムスタンプ、レイテンシをログに記録してください。送信したフィールド名(プロンプトではなく)、リトライ回数、リトライが新しいタスクを作成したか再開したかを記録します。私たちのハーネスは、使用量チャンクからの分割タイミングとトークン数を追加します。
2つの注意点。ストリーミングレスポンスはストリーム終了後に確定する場合があるため、使用量が後で記録されても請求ヘッダーが欠落している可能性があります。請求額については、レスポンスのトークン数だけでなく、管理APIの使用量レコードを使用してください。また、設定した場合は X-TokenLab-Delivery-Policy の値もログに記録してください。リファレンスによると、auto、verified、official を受け入れ、無効な値は 400 を返し、利用できないオプションは 503(code: delivery_tier_unavailable, retryable: true)を返します。Authorization、APIキー、署名付きURL、完全なプロンプト、個人データは決してログに記録しないでください。
コンソールのリクエスト詳細はキャプチャから30日間保持されるため、必要なIDを独自のログにコピーしてください。私たちのパイプラインでは、これらのIDをリクエストビューと照合しています。TokenLabリクエストコンソールの投稿でそのビューについて解説しています。
レート制限、リトライ、LLMのレイテンシとスループット
ストリームごとのスピードとアカウントのスループットは異なる上限です。レート制限ガイド(2026年10月3日観測)には、以下の標準ティア値が記載されています。これらはアクティブな構成によって変更される可能性があり、APIキーごとに適用されることに注意してください。
| ティア | 1分あたりのリクエスト数 |
|---|---|
| ユーザー | 1,000 |
| パートナー | 10,000 |
| VIP | 10,000 |
制限を超えると、APIは Retry-After ヘッダーとともに 429 rate_limit_exceeded を返します。ガイドのサンプルボディには "retryable": true と "retry_after": 8 が含まれています。ガイドでは、コピーされた表よりも、返された X-RateLimit-Limit と Retry-After の値を信頼するように指示しています。また、より高速なモデルがアカウントのリクエスト制限を増やすことはありません。
バッチ処理の計算式は以下の通りです。これは負荷テストではなく、上記の中央値からの推定です。並行ストリーム数は、おおよそ「1秒あたりのリクエスト数 × リクエストあたりの秒数」です。1分あたり1,000リクエスト(1秒あたり約16.7)の場合:
deepseek-v4.1-flash(合計中央値5.204秒)では、約87ストリームが同時に実行されます。claude-sonnet-5-5(合計中央値12.384秒)では、約206ストリームが同時に実行されます。
ストリームが遅いということは、同じリクエストレートに達するために必要な並行性が高くなることを意味します。制限に達すると、生成時間に加えて待ち時間が追加されます。トークン制限については使用したページではカバーされていないため、アカウントとモデルページを確認してください。
数値を損なわずにリトライする方法:
Retry-Afterが存在する場合はそれに従ってください。そうでない場合は、ランダムなジッターと厳格な試行上限を設けた指数バックオフを使用してください。- SDKを
max_retries=0に設定し、1箇所でリトライしてください。そうしないと、2つのレイヤーが同じ呼び出しをリトライし、タイミングが二重にカウントされます。 - バリデーション、認証、残高、権限エラーは決してリトライしないでください。一時的な
5xxレスポンスは短いバックオフでリトライしてください。 - 最初のイベントが到着した後、中断されたストリームは不完全であり、自動的に再開されません。リクエストを繰り返すと、異なる出力が生成され、別の料金が発生する可能性があります。
- リトライ回数と待ち時間はモデル時間とは別にログに記録し、スロットリングされた実行が遅いモデルのように見えないようにしてください。
以下はガイドの境界付きリトライパターンです:
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)
また、1分あたりの平均リクエスト数だけでなく、並行性にも上限を設け、バーストをキューに入れてください。APIキーごとの繰り返される 429 レスポンスを追跡し、1つのクライアントがアプリケーションの残りを圧迫しないようにしてください。
FAQ
1秒あたりのトークン数が多いほど、常にユーザー体験は高速ですか?
いいえ。2026年10月3日のサンプルでは、claude-sonnet-5-5 が最も早い最初の可視トークン(2,981 ms)を示しましたが、合計時間は最長(12,384 ms)でした。deepseek-v4.1-flash は可視テキストの開始が遅く(3,925 ms)、終了は最速(5,204 ms)でした。どちらが速く感じるかは、ユーザーがストリームを見ているか、完全な回答を待っているかによって異なります。1クライアントからの5回の実行では、ワークロードに対してそれを決定することはできません。
ストリーミングレスポンスがほとんどテキストなしで返ってきたのはなぜですか?
おそらく予算を推論に費やしたためです。max_tokens 400で、deepseek-v4.1-flash は400の推論トークンを使用し、可視トークンは0でした。最終使用量チャンクの usage.completion_tokens_details.reasoning_tokens と finish_reason を確認してください。その後、上限を引き上げてください。2000に設定すると、テストした両方の推論モデルが完全な回答を返しました。
より高速なモデルはレート制限を引き上げますか?
いいえ。レート制限ガイドには、モデルの速度、トークン制限、アカウントのレート制限は独立した制約であると記載されています。ストリームが速く終了すれば並行性スロットは解放されますが、キーごとのリクエスト制限は変わりません。制限の変更が必要な場合はサポートに問い合わせてください。
ストリームが遅い場合、サポートにどのIDを送ればよいですか?
request_id(または X-Request-ID)、エンドポイント、メソッド、モデル、タイムスタンプ、ステータスコードを送ってください。非同期作業の場合は task_id と poll_url を、存在する場合は billing_transaction_id を追加してください。分割タイミングと安全なエラーボディを含め、キー、プロンプト、プライベートメディアは事前に編集してください。
独自のプロンプトで上記のハーネスを実行し、測定結果を TokenLabモデルランキングと比較してください。
出典
価格確認日 2026-10-03
- TokenLab Docs: Streaming2026-10-03 時点で確認
- TokenLab Docs: Rate limits2026-10-03 時点で確認
- TokenLab Docs: Logs and troubleshooting2026-10-03 時点で確認
- TokenLab Docs: Build a reliable TokenLab integration2026-10-03 時点で確認
- TokenLab Docs: API Reference2026-10-03 時点で確認
- TokenLab Docs: Create Chat Completion2026-10-03 時点で確認
- TokenLab live model API: deepseek-v4.1-flash2026-10-03 時点で確認
- TokenLab live model API: gemini-3.8-flash2026-10-03 時点で確認
