LLM Frontline
開発・エージェント

LLMアプリの「遅い」を設計で潰す|TTFT・生成速度・総所要時間を分けて考えるレイテンシ設計

ミナト・開発・API担当
・ 約31分で読めます
LLMアプリの「遅い」を設計で潰す|TTFT・生成速度・総所要時間を分けて考えるレイテンシ設計

LLMを組み込んだ機能をリリースすると、品質の次に必ず出てくるのが「遅い」という声です。ところがこの「遅い」は、そのままでは直せません。最初の文字が出るまで待たされているのか、書き終わるまでが長いのか、そもそもリクエストが詰まっているのか。原因が違えば打ち手も違い、しかも打ち手には効果の桁がまったく違うものが混ざっています。この記事では、レイテンシをどう分解し、どの順番で手を入れ、どこで諦めるかを、各社の公式ドキュメントに書かれている内容を確認しながら整理します。

「遅い」を1つの数字で語らない

最初にやるべきことは、指標を分けることです。Anthropicのレイテンシ削減ドキュメントは、計測の話として2つの用語を挙げています。1つはbaseline latencyで、「入力・出力のトークン毎秒を考慮せず、モデルがプロンプトを処理して応答を生成するのにかかる時間」と説明されています。もう1つがtime to first token(TTFT)で、「プロンプトを送ってから、モデルが応答の最初のトークンを生成するまでにかかる時間を測る指標」であり、ストリーミングを使ってユーザーに応答性の高い体験を提供したいときにとくに関係する、とされています。

実務では、ここに生成の速さを加えた3つで見るのが扱いやすいと考えています。

指標何を測るか主に効くもの
TTFTリクエスト送信から最初のトークン(またはチャンク)が届くまで入力トークン数、キャッシュヒット、推論トークン、キューイング
生成速度(TPS)最初のトークン以降、1秒あたり何トークン生成されるか(値が大きいほど速い)モデルの大きさ、実行環境、サービスティア
総所要時間リクエストからレスポンス完了まで出力トークン数(支配的)、上記すべて、リトライ

OpenAIのレイテンシ最適化ガイドは、この生成の速さを「LLMがトークンを処理する実際の速度」と表現し、TPM(tokens per minute)やTPS(tokens per second)で測られるものとしています。

OpenTelemetryのGenAI semantic conventionsにも対応するメトリクスが定義されています。クライアント側はgen_ai.client.operation.time_to_first_chunk(リクエスト発行から応答ストリームの最初のチャンク受信までの秒数)とgen_ai.client.operation.time_per_output_chunk(2つ目以降の各チャンクについて、前のチャンクの終わりから当該チャンクの終わりまでの経過時間)、サーバ側はgen_ai.server.time_to_first_tokenとgen_ai.server.time_per_output_tokenです。いずれも単位は秒ですが、報告の条件は共通ではありません。クライアント側の2つには「ストリーミング呼び出しについて報告すべき(SHOULD)、それ以外では報告すべきでない(SHOULD NOT)」という注記が付いています。サーバ側のtime_to_first_tokenにこの注記はなく、キューとプレフィル段階の時間を測る指標で、とくにストリーミングのリクエストで重要だと説明されています。呼び名を自分たちで決める前に、この語彙に寄せておくと後で困りません。

ヒント

ユーザーの体感に一番効くのはTTFTです。ストリーミングしている限り、最初の1文字が0.8秒で出て20秒かけて書き終わる応答は、8秒黙ってから12秒で書き終わる応答より「速い」と感じられます。総所要時間だけを追いかけていると、この差が見えません。

遅さの内訳:入力は主にTTFT、出力は総時間

推論は大きく2つの段階に分かれます。入力を読み込む段階(プレフィル)と、トークンを1つずつ生成する段階です。前者は主にTTFTに、後者は総所要時間に効きます。この非対称性が、打ち手の優先順位をほぼ決めてしまいます。

OpenAIのレイテンシ最適化ガイドは、この点をかなり直接的な数字で書いています。出力については「出力トークンを50%削ると、レイテンシも約50%削れることがある(cutting 50% of your output tokens may cut ~50% of your latency)」。入力については「プロンプトを50%削っても、レイテンシの改善は1〜5%程度にしかならないことがある(cutting 50% of your prompt may only result in a 1-5% latency improvement)」。同ガイドは、入力削減が効いてくるのは巨大なコンテキストを扱う場合が中心だとしています。

つまり、プロンプトを一生懸命短くしても総所要時間はほとんど変わらない一方、出力を短くすれば素直に効きます。「プロンプトが長いから遅いのでは」という直感は、多くの場合は外れです。もちろん入力削減はコストには効きますし、TTFTには効きます。ただしそれは総所要時間の話とは別問題として扱う必要があります。

「プロンプトを半分にしたのに体感が変わらない」という報告は珍しくありません。総所要時間で見ているなら、それは想定どおりの結果です。見るべき指標がTTFTだったのか総所要時間だったのかを、先に決めておく必要があります。
LLMアプリを運用するエンジニア

推論(thinking)トークンという第4の変数

推論モデルを使っている場合、この構図にもう1つ変数が入ります。応答本文を書き始める前に、モデルが内部で推論トークンを生成する時間です。この時間がどの指標に乗るかは、思考を画面に出すかどうかで変わります。思考を表示しない設計なら、ユーザーから見た「まだ何も出てこない時間」、つまり最初の可視テキストまでの時間に丸ごと乗ります。一方、思考を逐次表示する設計では事情が違います。Anthropicのストリーミングのドキュメントによれば、拡張思考をストリーミングすると思考の内容がthinking_deltaイベントとして届き(display: "omitted"を指定した場合は届きません)、最初に開くのは思考ブロックです。この場合、最初のチャンクの到達で測るTTFTは思考時間で押し上げられず、押し上げられるのは最初の可視テキストまでの時間のほうになります。

Googleは、Gemini 3の開発者ガイドでthinking_levelの各値を説明しており、lowは「レイテンシとコストを最小化する。単純な指示追従、チャット、高スループット用途に最適」、highは「推論の深さを最大化する。モデルが最初の(思考ではない)出力トークンに到達するまで大幅に長くかかることがあるが、出力はより慎重に推論されたものになる」としています。同ガイドは、複雑な推論が不要な場合に、より速く低レイテンシの応答を得るにはthinking_levelをlowに制約できる、とも書いています。

ここで注意したいのは、推論を切れば速くなるのは事実でも、切ってよいかどうかは別だということです。分類やルーティングのような単純な判断では推論の効果が薄く、切ってもほぼ影響がありません。一方、複数の制約を突き合わせる判断や、手順を組み立てる必要のあるタスクでは、推論を削ると失敗率が上がり、リトライや人手の差し戻しが発生します。差し戻しまで含めた「回答が確定するまでの時間」で見ると、かえって遅くなることがあります。

注意

推論トークンは課金上も出力側に乗ります。Googleのthinkingのドキュメントは、thinkingを有効にした場合の応答の価格は出力トークンと思考トークンの合計になると明記しています。レイテンシとコストが同じ方向に動く数少ない変数なので、まずここの設定を用途別に見直すのは費用対効果が高い作業です。

効く順に打ち手を並べる

OpenAIのレイテンシ最適化ガイドは、原則を7つ挙げています。「トークンをより速く処理する」「生成するトークンを減らす」「入力トークンを減らす」「リクエスト回数を減らす」「並列化する」「ユーザーを待たせる時間を減らす」「LLMを既定の選択肢にしない」です。これを実務の着手順に組み替えると、次のようになります。

1. 出力トークンを減らす

前述のとおり、総所要時間にもっとも素直に効きます。やり方は3つあります。

1つ目は、出力の長さを指示することです。OpenAIのガイドは自然言語の応答について「20語以内で」「簡潔に」といった指示を挙げ、例示やファインチューニングで補強できるとしています。Anthropicのドキュメントも同様に簡潔さを求めることを挙げたうえで、有用な注意を添えています。LLMは単語ではなくトークンを数えるため、正確な語数や語数上限を指定するのは、段落数や文数の上限を指定するほど有効な戦略ではない、というものです。「300字以内で」より「3文以内で」のほうが効きます。

2つ目は、構造化出力で無駄な字面を削ることです。OpenAIのガイドは、構造化出力については構文を最小化する方向を挙げており、関数名を短くする、名前付き引数を省略する、パラメータをまとめる、といった手を示しています。実際、JSONのキー名を冗長にしていると、それだけで毎回トークンを吐かせることになります。

3つ目は、そもそも要約や説明を求めない設計にすることです。分類結果だけが欲しいのに「理由も添えて」と書いていないか、UIで表示していない前置きを毎回書かせていないかを見直します。同ガイドは「出力トークンを1つ削ることは、(ミリ)秒を1つ稼ぐことだ」と表現しています。

あわせて読みたい

構造化出力(Structured Outputs)とは何か|LLMの返答をプログラムで安全に扱うための仕組み

2. ストリーミングでTTFTを見せる

ストリーミングは、応答が完成する前から送り始める仕組みです。Anthropicのドキュメントは、これによりユーザーが出力をリアルタイムで見られるため、アプリケーションの体感的な応答性を大きく改善できるとしています。Googleのテキスト生成のドキュメントも、既定では生成がすべて終わってから応答が返るとしたうえで、より滑らかなインタラクションのためにストリーミングを使い、生成されたそばから応答のチャンクを処理することを挙げています。

OpenAIのガイドは、これを「ユーザーを待たせる時間を減らす」原則の中心に置き、ストリーミングにより体感の待ち時間を1秒以下に短縮できるとしたうえで、「各応答が終わるまで何も見えなかったら、ChatGPTはかなり違った感触になるだろう」と書いています。同ガイドはチャンキング(出力を分割して処理し、処理済みのチャンクからフロントエンドへ送る)にも触れ、途中経過の表示やローディングインジケータが主に体感に効くのに対し、ストリーミングとチャンキングはアプリとユーザーを含めた全体で見れば実際に総時間を減らす、と整理しています。

ここで重要なのは、ストリーミングが体感の問題だけではない点です。Anthropicのエラーに関するドキュメントには「Long requests」という節があり、長時間かかるリクエスト、とくに10分を超えるものにはストリーミングのMessages APIかMessage Batches APIの利用を検討すべきとされています。理由も具体的で、大きなmax_tokensをストリーミングなしで指定すると、ネットワークによってはアイドル接続が切断され、応答を受け取れないままリクエストが失敗またはタイムアウトすることがある、というものです。同ドキュメントによれば、公式SDKは非ストリーミングのMessages APIリクエストが10分のタイムアウトを超えないことを検証し、TCPキープアライブのソケットオプションも設定します。

イベントを逐次処理する必要がない場合でも、SDK側でストリームを消費して完成したメッセージを返す使い方が用意されています。Anthropicの公式ドキュメントに載っている形は次のとおりです。実行にはPython向け公式SDKとANTHROPIC_API_KEYの設定が前提で、モデル名や引数は使用するバージョンのリファレンスで確認してください。

# Anthropic公式ドキュメントに掲載されているストリーミングの記法
client = anthropic.Anthropic()

with client.messages.stream(
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello"}],
    model="claude-opus-5",
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

TTFTを計測したいなら、このforループに入る直前ではなく、最初のテキストが到着した瞬間の時刻を取ります。SDKによっては最初に届くイベントがメッセージ開始のメタ情報なので、「最初のイベント」と「最初の可視テキスト」を取り違えると、UIの体感とずれた数字を測ることになります。

3. プロンプトキャッシュでプレフィルを削る

入力トークンの削減はTTFTに効く、と書きました。その中でもっとも手数が少ないのがプロンプトキャッシュです。OpenAIのプロンプトキャッシュのドキュメントは利点として「Faster: 応答が始まる前の入力処理にかかる時間を減らす」を挙げています。Anthropicのドキュメントは、5分キャッシュと1時間キャッシュはレイテンシに関して同じ挙動であるとしたうえで、「長い文書については一般にtime-to-first-tokenの改善が見られる」と書いています。Googleも、コンテキストキャッシュの効果として「Faster time-to-first-token」を挙げています。

効かせるコツはどの社でも同じで、静的な部分を先頭に、可変部分を末尾に置くことです。OpenAIのガイドも、共有されるプロンプトのプレフィックスを最大化し、動的な内容を後ろに置くことでKVキャッシュの効率が上がるとしています。Anthropicの場合はキャッシュのプレフィックスがtools・system・messagesの順に作られるという階層があるので、ツール定義を毎回並べ替えるだけで壊れます。

あわせて読みたい

プロンプトキャッシュ(Prompt Caching)とは|LLM APIのコストとレイテンシを下げる仕組みと実務

4. モデルを段階化する

OpenAIのガイドは「トークンをより速く処理する」原則の主要因としてモデルの大きさを挙げ、小さいモデルは一般に推論が速くコストも低い、詳細なプロンプトや少数例、ファインチューニングで補えば大きいモデルに匹敵しうるとしています。Anthropicのドキュメントも、レイテンシを減らすもっとも直接的な方法の1つは用途に合ったモデルを選ぶことだとし、速度が重要なアプリケーションにはClaude Haiku 4.5が最速の応答時間を提供するとしています。

実務では「全部を小さいモデルにする」ではなく段階化が現実的です。前段に小さいモデルを置いて分類・ルーティング・抽出を担当させ、難しいと判定されたものだけを大きいモデルに回します。ここで効くのは、前段の判定が外れたときのコストです。前段が誤って簡単だと判定したケースの被害が小さい(やり直せる、人が気づける)構成にしておかないと、速度と引き換えに品質事故を買うことになります。

あわせて読みたい

主要LLMの選び方|用途別の考え方と「使い分け」の基準

5. 並列化と投機的実行

OpenAIのガイドは、依存関係のない手順は並列呼び出しに分割してよいとしています。処理が重複しても追加のレイテンシにはならないためです。順序依存がある場合でも投機的実行(speculative execution)が使えるとし、具体例としてモデレーションと本文生成を同時に開始し、モデレーションの結果を検証して問題があれば生成側をキャンセルするパターンを挙げています。予測が当たっていれば追加のレイテンシは実質ゼロになります。

出力の大半が事前にわかっているケースには、別の手もあります。OpenAIのPredicted Outputsは、出力トークンの多くが事前にわかっているときに応答を高速化する機能で、ドキュメントは軽微な修正を伴う文書やコードの再生成に向くとしています。ただし制約は多めです。ドキュメントによれば対象はChat Completionsで、対応モデルはGPT-4o・GPT-4o-mini・GPT-4.1・GPT-4.1-mini・GPT-4.1-nanoの各系列に限られます。パラメータ側にも制限があり、tools(function calling)は現時点で非対応、max_completion_tokensとlogprobsも非対応、nは1より大きい値を使えません。さらに、予測として渡したトークンのうち最終的な補完に含まれなかったものも、補完トークンの料金で課金されます。推論モデルやツールを併用するエージェント的な使い方では選択肢に入らないため、適用範囲は限定的だと考えておくのが安全です。

一方で、OpenAIのガイドは「リクエスト回数を減らす」も原則に挙げています。複数の手順を順番に呼び出す代わりに1つのプロンプトにまとめて1回の応答で受け取れば、往復のオーバーヘッドを避けられるという話です。並列化と統合は相反するように見えますが、判断軸は単純で、依存関係があるものは統合、ないものは並列です。

6. そもそも同期で返さない

いちばん効くのに検討されないのがこれです。人がその場で待っていない処理を、同期APIで返す必要はありません。

各社とも非同期・低優先度の選択肢を用意しています。OpenAIのBatch APIは「各バッチは24時間以内に完了する(多くの場合はもっと早い)」とされ、同期APIに比べて50%の割引があり、同期APIとは別のレート制限プールを持ちます。AnthropicのMessage Batches APIは、多くのバッチが1時間未満で完了し、コストを50%削減するとされています。結果は全メッセージの完了後か24時間後の早いほうで取得でき、24時間以内に処理が完了しないバッチは期限切れになります。GoogleのBatch APIも目標所要時間24時間・50%割引という位置づけです。

同期のまま優先度を下げる選択肢もあります。OpenAIのFlex processingは、応答が遅くなることと時折リソースが利用できないことと引き換えに低コストを提供するもので、トークンはBatch API相当の価格になります。リソース不足時は429 Resource Unavailableが返り、その場合は課金されません。Googleの推論オプションの比較表では、Standardが「秒から分」、Priorityが「秒」で標準より75%から100%高い価格、Flexが「1〜15分の目標」で50%割引、Batchが「最大24時間」で50%割引と整理されています。

ヒント

「非同期にする」はアプリのUXを変える判断でもあります。結果を通知で受け取る、一覧画面で状態を見る、完了したものから順に表示する。UIの作り方を変えられるなら、レイテンシ最適化としてはもっとも安上がりです。逆に言えば、UIを変えられない制約があるなら、この選択肢は最初から外して考える必要があります。

効かない打ち手・逆効果になる打ち手

ここまでの裏返しとして、やりがちだが効かない、あるいは害のあるものを並べます。

まず、やみくもなmax_tokensの切り下げです。Anthropicのドキュメントはmax_tokensについて、応答が上限に達すると文の途中や単語の途中で打ち切られるため、後処理が必要になりうる大まかな手法(a blunt technique)であり、通常は答えが冒頭に来る多肢選択や短答に向いている、と説明しています。上限は安全弁であって、短くする手段ではありません。短くしたいなら指示と設計で短くして、max_tokensはその外側に置きます。打ち切りが起きているかどうかは停止理由で判定できるので、そこを監視していないまま上限を下げるのは危険です。

次に、リトライの多重化です。遅いからといってタイムアウトを短くして再送を増やすと、サーバ側の負荷が上がり、レート制限に当たり、全体としてはさらに遅くなります。並行実行数の上限、リトライ予算、締め切りをセットで設計する話は別記事にまとめています。

あわせて読みたい

LLM APIのレート制限とリトライ設計|429・タイムアウト・二重実行を本番で捌く

3つ目は、キャッシュが効かないプロンプト構成のまま入力を削ることです。タイムスタンプやリクエストIDをシステムプロンプトの先頭に入れている、ツール定義を毎回動的に並べ替えている、といった構成では、プレフィックスが一致しないためキャッシュが効きません。この状態で入力を1割削っても、得られるのは1割よりずっと小さい改善です。

4つ目は、推論を一律で切ることです。前述のとおり、切ってよい処理と切ると失敗が増える処理があります。全体のp95だけを見て一律に下げると、難しいケースだけが静かに壊れます。

5つ目は、最適化の前倒しです。Anthropicのドキュメントには印象的な注意書きがあります。モデルやプロンプトの制約なしでうまく動くプロンプトをまず作り、そのうえでレイテンシ削減の戦略を試すほうが常に良い、早すぎるレイテンシ削減は最高の性能がどのようなものかを発見する機会を奪ってしまうかもしれない、というものです。速度から入ると、そもそも達成可能だった品質のラインが分からなくなります。

レイテンシ改善の前に確認すること

  • 「遅い」の中身は、TTFTか、生成速度か、総所要時間か
  • ストリーミングをしているか。していないなら、それは技術的制約か、単に未対応か
  • 出力トークン数の分布を見たか(平均ではなくp95)
  • 推論トークンを使っているか。用途ごとに水準を変えているか
  • プロンプトキャッシュが実際にヒットしているか(キャッシュ読み出しトークンの比率を見る)
  • 同期で返す必要が本当にあるか。非同期・バッチにできる処理が混ざっていないか
  • リトライやタイムアウトの設定が、遅延をさらに悪化させていないか

計測:平均ではなくp50/p95で見る

レイテンシは分布で見ます。平均は、少数の極端に遅いリクエストに引っ張られるうえ、大多数の体感も表しません。p50(中央値)で普段の体感を、p95やp99で「たまに起きるひどい待ち」を見るのが基本です。ユーザーが不満を言うのはほぼ後者で、そして後者は平均ではまず見えません。

LLM特有の注意点が2つあります。

1つ目は、ストリーミングの計測です。TTFTと総所要時間は別々に記録します。OpenTelemetryのGenAIメトリクスも、前述のとおりストリーミング呼び出しについてのみtime_to_first_chunkとtime_per_output_chunkを報告すべきとしており、非ストリーミングの呼び出しと混ぜないことが前提になっています。ダッシュボードでも分けて持つべきです。

2つ目は、レイテンシを出力トークン数で正規化することです。総所要時間は出力の長さに支配されるので、生の秒数だけを見ていると「今日は遅い」のか「今日は長い応答が多かった」のかが分かりません。出力トークンあたりの時間(あるいは出力トークン数の分布)を並べて置くと、切り分けができます。

トレースに何を残すかは観測設計の話になりますが、レイテンシの調査に最低限必要なのは、TTFT、総所要時間、入出力トークン数、キャッシュ読み出しトークン数、停止理由、リトライ回数、そして使ったモデル名とサービスティアです。これらが同じspanに乗っていれば、遅い理由をほぼ機械的に分類できます。

あわせて読みたい

LLMアプリのオブザーバビリティ|トレーシングとログ設計で「なぜこの出力になったか」を後から追えるようにする

SLOの決め方:用途ごとに別の数字を持つ

「何ミリ秒なら速いのか」という業界共通の基準はありません。各社の公式ドキュメントも、具体的な目標値ではなく相対的な位置づけを示すにとどめています。Googleの推論オプションの比較表が「秒」「秒から分」「1〜15分の目標」「最大24時間」という粒度で書かれているのは、そのくらいの解像度でしか一般化できないということでもあります。

そこで、自分のユースケースごとに決めます。決め方の枠組みだけを示します。

  1. 1

    待っている主体を特定する

    画面の前の人か、別の処理か、誰も待っていないか。誰も待っていないなら、それは同期で返す必要がありません。
  2. 2

    ユーザーの次の行動を基準にする

    応答を読んでから次の入力をするのか、結果を眺めるだけか。会話のテンポが重要な用途ではTTFTを、読み物を生成する用途では総所要時間を主指標にします。
  3. 3

    現状の分布を1週間ぶん測る

    目標を決める前に現在地を測ります。p50とp95、そして出力トークン数の分布をセットで取ります。
  4. 4

    p95で目標を置き、超過率で運用する

    「p95が○秒以内」という形にし、達成率(SLO)で運用します。1件の遅延でアラートを鳴らすと、すぐに誰も見なくなります。
  5. 5

    超えたときの縮退動作を決める

    遅延が閾値を超えたら、小さいモデルに落とす、推論の水準を下げる、非同期に切り替えて通知で返す、といった縮退の手順を先に決めておきます。

用途別のおおまかな整理としては、次のように考えると設計判断がぶれにくくなります。対話UIはTTFTが主指標で、ストリーミングが事実上の必須。社内の定期バッチは総所要時間だけが問題で、TTFTには意味がないためBatch APIや低優先ティアが第一候補。エージェントの長時間実行は、1回の呼び出しのレイテンシよりも「何回まわるか」が支配的なので、まずステップ数を減らす設計を見ます。3つ目については、そもそも同期で返さない前提に立てるかどうかが分かれ目です。

あわせて読みたい

マルチエージェント構成をいつ選ぶか|単一エージェントで足りる線引きと、分割するときの設計判断

コストとのトレードオフ

レイテンシとコストは、同じ方向に動くこともあれば逆に動くこともあります。混同すると判断を誤ります。

同じ方向に動くのは、出力トークンの削減、推論トークンの削減、プロンプトキャッシュの活用、小さいモデルへの切り替えです。ここは素直に両取りできます。逆に動くのは、優先度の高いサービスティアの利用(Googleの比較表では標準より75%から100%高い価格)、投機的実行やPredicted Outputsのように無駄になる可能性のあるトークンを先に払う手法、そして冗長化のための並列呼び出しです。速さを金で買っている形なので、どのくらい速くなるのかを測ってから続けるかを決めます。

逆に、コストを下げると遅くなるのがBatchやFlexです。OpenAIのBatch APIもFlex processingも50%相当の割引がある代わりに、前者は最大24時間、後者は応答が遅くなることと時折のリソース不足を受け入れる設計です。人が待っていない処理をこちらに寄せるだけで、コストとレイテンシの両方の会話が楽になります。

あわせて読みたい

LLMのコスト管理|トークン課金の考え方と削減の定石

小さく始める順番

一度に全部はできないので、効果と工数の比が良い順に並べます。

  1. 1

    計測を分ける

    TTFTと総所要時間を別々に記録し、出力トークン数と一緒にp50/p95で見られるようにします。ここが無いと、以降の改善の効果が測れません。
  2. 2

    ストリーミングを入れる

    対話UIならまずここです。総所要時間が変わらなくても、体感は大きく変わります。長時間リクエストの安定性も同時に上がります。
  3. 3

    出力を短くする

    文数・段落数での指示、構造化出力のキー名整理、不要な理由説明の削除。総所要時間にもっとも素直に効きます。
  4. 4

    推論の水準を用途別に設定する

    単純な判断は低く、複雑な判断は高く。一律の設定をやめるだけで、平均も分散も改善することがあります。
  5. 5

    プロンプトキャッシュを効かせる

    静的な部分を先頭に寄せ、キャッシュ読み出しトークンの比率を監視します。TTFTに効きます。
  6. 6

    モデルを段階化する

    前段に小さいモデルを置き、難しいものだけを大きいモデルへ。誤判定時の被害が小さい構成にします。
  7. 7

    同期をやめられる処理を切り出す

    人が待っていない処理をBatchや低優先ティアへ移します。ここまで来ると、残った同期処理に集中できます。

なお、OpenAIのガイドの7番目の原則は「LLMを既定の選択肢にしない」です。取りうる出力が限られている確認メッセージや定型の断り文句はハードコードでよく、入力の種類が限られているなら事前に生成しておけばよい。集計値やレポートや検索結果は、生成した文章よりも専用のUIコンポーネントのほうがうまく伝わる。二分探索やキャッシュやハッシュマップといった従来の最適化手法も、LLMアプリの中で依然として有効だ、という趣旨のことが書かれています。いちばん速いLLM呼び出しは、しなかったLLM呼び出しです。

よくある質問

プロンプトを短くしたのに速くなりません。なぜですか
総所要時間は主に出力トークン数で決まるためです。OpenAIのレイテンシ最適化ガイドは、プロンプトを50%削ってもレイテンシの改善は1〜5%程度にとどまることがある一方、出力トークンを50%削ればレイテンシも約50%削れることがある、としています。入力削減が効いてくるのは巨大なコンテキストを扱う場合が中心です。ただし入力削減はコストには効きますし、最初のトークンが出るまでの時間(TTFT)には効きます。何を改善したいのかを先に決めて、対応する指標で測ってください。
max_tokensを小さくすれば速くなりますか
上限に達するほど長い出力が出ている場合は総時間が短くなりますが、代償があります。Anthropicのドキュメントは、max_tokensに達すると応答が文の途中や単語の途中で打ち切られるため後処理が必要になりうる大まかな手法であり、通常は答えが冒頭に来る多肢選択や短答に向いている、と説明しています。短くしたいなら、文数や段落数での指示や出力形式の設計で短くするのが本筋です。max_tokensは暴走を止める安全弁として、実際に必要な長さより十分大きい値に置きます。合わせて、停止理由が上限到達になった割合を監視してください。
TTFTはどこで測るのが正しいですか
ユーザーの体感に合わせるなら、クライアントがリクエストを発行した時点から、画面に最初の可視テキストが出た時点までです。OpenTelemetryのGenAIメトリクスは、クライアント側にgen_ai.client.operation.time_to_first_chunk(リクエスト発行から応答ストリームの最初のチャンク受信まで)、サーバ側にgen_ai.server.time_to_first_tokenを定義しており、いずれも単位は秒です。クライアント側のtime_to_first_chunkにはストリーミング呼び出しについて報告すべき(SHOULD)という注記が付いており、サーバ側のtime_to_first_tokenはキューとプレフィル段階の時間を測る指標で、とくにストリーミングのリクエストで重要だと説明されています。SDKによっては最初に届くイベントがメタ情報で本文を含まないため、「最初のイベント」を測ってしまうと体感より良い数字が出ます。実装時に何を最初と見なしているかを確認してください。
推論(thinking)を切れば速くなりますか
速くはなりますが、切ってよいかは処理によります。Googleは、Gemini 3の開発者ガイドでthinking_levelのlowを「レイテンシとコストを最小化する。単純な指示追従、チャット、高スループット用途に最適」、highを「モデルが最初の(思考ではない)出力トークンに到達するまで大幅に長くかかることがあるが、出力はより慎重に推論されたものになる」と説明しています。分類やルーティングのような単純な判断では下げても影響が小さい一方、複数の制約を突き合わせる判断では失敗率が上がり、リトライや人手の差し戻しで結局遅くなることがあります。一律に切るのではなく、用途ごとに水準を決めて、品質の指標とセットで評価してください。
バッチ処理に回すと、どのくらい待つことになりますか
公式が示している目安は各社で異なります。OpenAIのBatch APIは各バッチが24時間以内に完了する(多くの場合はもっと早い)とされ、同期APIに対して50%の割引と、別枠のレート制限が用意されています。AnthropicのMessage Batches APIは多くのバッチが1時間未満で完了しコストを50%削減するとされ、結果は全メッセージ完了後か24時間後の早いほうで取得でき、24時間以内に完了しないバッチは期限切れになります。GoogleのBatch APIも目標所要時間24時間・50%割引という位置づけです。いずれも保証された所要時間ではないので、締め切りのある処理に使う場合は、期限切れや遅延時の代替経路を先に決めておいてください。
レイテンシのSLOは何秒に置くべきですか
業界共通の基準はなく、公式ドキュメントも具体的な秒数ではなく相対的な位置づけしか示していません。自分のユースケースで決める前提に立ってください。手順としては、待っている主体(画面の前の人か、別の処理か、誰も待っていないか)を特定し、主指標をTTFTにするか総所要時間にするかを決め、現状の分布を一定期間測り、p95で目標を置いて達成率で運用する形が扱いやすいです。合わせて、目標を超えたときの縮退動作(小さいモデルに落とす、推論の水準を下げる、非同期に切り替える)を先に決めておくと、実際に遅くなったときに慌てずに済みます。

まとめ

LLMアプリのレイテンシ設計は、最適化のテクニックを集める話ではなく、指標を分ける話から始まります。TTFT、生成速度、総所要時間。この3つを分けた瞬間に、打ち手の優先順位はほぼ自動的に決まります。

総所要時間を縮めたいなら出力を短くする。体感を良くしたいならストリーミングを入れてTTFTを見せる。TTFTを縮めたいならプロンプトキャッシュを効かせ、推論の水準を用途別に見直す。そして、人が待っていない処理は最初から同期で返さない。順番を守るだけで、無駄な作業がかなり減ります。

同時に、効かない打ち手を知っておくことも同じくらい重要です。プロンプトを削っても総時間はほとんど変わらず、max_tokensの切り下げは途中切れを生み、リトライの多重化は状況を悪化させ、推論を一律で切ると難しいケースだけが静かに壊れます。そして、品質が固まる前にレイテンシから入ると、そもそも到達できたはずの品質が分からなくなります。

目標値については、公式が示す一般論の粒度が「秒」「分」「時間」であることを、そのまま受け取ってよいと考えています。ミリ秒単位の業界基準を探すより、自分のユースケースでp95を測り、超えたときに何をするかを決めるほうが、はるかに実用的です。

あわせて読みたい

OpenAIがUltrafast modeをプレビュー公開|「最大14倍速」は業務のどこに効くのか

出典・参考

この記事をシェア

関連する記事

開発・エージェント

LLMアプリのオブザーバビリティ|トレーシングとログ設計で「なぜこの出力になったか」を後から追えるようにする

LLMアプリ・AIエージェントの観測をどう設計するかを実務目線で整理します。通常のWebアプリのログとの違い、最低限とるべきシグナル、OpenTelemetryのGenAI semantic conventions(現在Development段階)の使い方、入出力本文を残すかどうかの判断、コスト可視化とアラート設計、評価(eval)との接続、既存APMとLLM専用ツールの選び分けをまとめます。