Claude APIのレイテンシ削減とTTFT計測 — 実装3パターン
Claude APIの応答が遅いとき、完了までと最初のトークンまでのどちらが長いかをcurlで測り、モデル・effort・キャッシュ・ストリーミングから選ぶ手順です。
Claude APIの応答が遅いとき、最初に決めるのは「どの待ち時間を縮めたいか」です。画面に最初の文字が出るまでなのか、回答が最後まで終わるまでなのかで、効く打ち手が変わります。この記事では2つの指標の違いを手元で計測し、モデル選択・effort・プロンプト短縮・キャッシュ・ストリーミングの順に、どの待ち時間に効くかを見ていきます。
対策に着手する前に、制約なしで精度の出るプロンプトを先に作っておきます。最初からレイテンシを気にすると、そのタスクで出せる最高精度の水準を見失うためです。
遅いのは「最初の1文字」か「最後の1文字」か
2つの指標が指す時間
baseline latency
公式の定義では、プロンプトの処理から応答の生成までにかかる時間で、毎秒の入出力トークン数は考慮しません。処理・生成するトークンが少ないほど応答は速くなるため、出力を減らすと縮みます。バッチ処理のように、全文が揃ってから次の工程へ進む用途で効く指標です。
TTFT
プロンプトを送ってから、最初の1トークンが生成されるまでの時間です。最初のトークンまでの時間なので、出力の長さの影響は受けにくい指標です。チャットのように、最初の反応の早さが体感を決める用途で効く指標です。
2つを混同すると改善の的が外れます。ストリーミングを入れても、完了までの時間は変わらないためです。指標を決めずに「速くなった気がする」で判断すると、変更の効果を切り分けられません。
curlで計測する: time_starttransferが最初の1バイトを返す
curlの-wオプションには、リクエスト開始から最初のバイトを受け取るまでの時間time_starttransferと、全体のtime_totalがあります。ストリーミングのリクエストにこの2つを並べると、TTFTに近い値と完了時間を1回で取れます。
curl -sN -o /dev/null https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-5-5",
"max_tokens": 1024,
"stream": true,
"messages": [{"role": "user", "content": "Hello"}]
}' \
-w 'time_starttransfer=%{time_starttransfer} time_total=%{time_total}\n'time_starttransferには、DNS・TCP・TLSの接続時間も含まれます。接続分を引きたいときは、time_connectやtime_appconnectも併記します。
2つの値の差が、最初のバイトが届いてから生成が終わるまでの時間です。API本体を叩く前に-wの読み方を確かめるため、手元のローカルサーバーで試しました。0.5秒待って最初のイベントを返し、その後は1秒おきに3回イベントを返すだけの模擬サーバーです(Anthropic APIの応答ではありません)。
time_starttransfer=0.503386 time_total=3.520944time_starttransferは待機の0.5秒に、time_totalは全体の約3.5秒に一致します。-wの2つの値がそれぞれ何を拾うかが、1回の実行で読み取れます。
ただし最初のバイトは、本文の最初のトークンとは限りません。ストリームはmessage_startで始まり、続けてcontent_block_start、content_block_deltaの順に届きます。content_block_deltaのdeltaにはテキスト以外に、thinking_deltaやinput_json_deltaもあります。本文の最初の文字までを正確に測るなら、SDKのストリーミングイベントに受信時刻を記録し、最初のtext_deltaが届いた時刻をとります。
モデルを替える: 最速はHaiku 4.5、単価も一緒に動く
最も直接的な方法は、タスクに見合ったモデルを選ぶことです。速度が最優先なら、高い知性を保ちながら最速の応答を返すClaude Haiku 4.5が候補になります。
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-haiku-4-5",
"max_tokens": 100,
"messages": [{"role": "user", "content": "顧客フィードバックを2文で要約してください: [フィードバック本文]"}]
}'モデル概要の比較表では、相対レイテンシが最速のHaiku 4.5から、高速のSonnet 5.5、中程度のOpus 5.5、遅めのFable 5.1の順に並びます。この比較は現行ラインナップの中での相対評価で、実際の速度はプロンプト長・出力長・thinkingのeffortで変わります。
| モデル | 相対レイテンシ | 単価(入力/出力1Mトークン) |
|---|---|---|
| Claude Haiku 4.5 | 相対レイテンシ最速 | 単価(入力/出力1Mトークン)$1 / $5 |
| Claude Sonnet 5.5 | 相対レイテンシ高速 | 単価(入力/出力1Mトークン)$2 / $10 |
| Claude Opus 5.5 | 相対レイテンシ中程度 | 単価(入力/出力1Mトークン)$4 / $20 |
| Claude Fable 5.1 | 相対レイテンシ遅い | 単価(入力/出力1Mトークン)$10 / $50 |
速度と単価は同じ向きに動きます。速い順に安く、遅い順に高いので、速度を取ると精度の余裕が減る傾向があります。単価そのものの考え方はClaude APIとサブスクの料金比較でも扱っています。
effortを下げる: モデルを替えずに待ち時間を縮める
モデルを替えられないときの手段が、output_config.effortです。公式のeffortの説明では、すべてのトークン数に効くパラメータで、thinkingの有無にかかわらず働くとされています。レベルを下げると、速度とコストを優先する代わりに能力が多少落ちます。
既定値はモデルで異なります。Claude Opus 5・Claude Sonnet 5.5・Claude Fable 5.1はhigh、Claude Opus 5.5はmediumです。既定値を明示しても省略時と同じ挙動になるので、Opus 5.5でmediumを指定しても何も変わりません。
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-5-5",
"max_tokens": 1024,
"output_config": {"effort": "low"},
"messages": [{"role": "user", "content": "Hello"}]
}'モデルごとの公式の推奨も違います。Fable 5.1は既定のhighから始め、評価で品質が保てると確認できたルーチン作業やレイテンシ重視の処理でmediumやlowに下げる、という書き方です。Sonnet 5.5はエージェント用途やレイテンシ重視の用途でなければhighから始め、明確に指定されたエージェント作業ではmediumから始めるとされています。
Sonnet 5.5には、さらにthinkingを絞る設定があります。thinking: {"type": "between_tools"}は最も低いthinking設定で、low・medium・highのeffortで使えます。xhighとmaxでは400エラーになります。between_toolsでは会話の途中でeffortを変えられず、メッセージごとに異なるeffortを指定すると400エラーを返します。一方、Opus 5.5はthinking: {"type": "disabled"}を送ると、どのeffortでも400エラーを返します。thinkingを切って速くするという発想は、モデルによって通りません。
Claude Haiku 4.5は、effortの対応モデル一覧に載っていません。Haiku 4.5で詰める余地は、次の節以降の入力短縮・キャッシュ・ストリーミングにあります。
入力と出力を短くする
処理・生成するトークンが少ないほど応答は速くなります。公式ガイドが挙げる具体策は次のとおりです。
- プロンプトを明確かつ簡潔にする: 不要な詳細や重複を削ります。Claudeはユースケースの文脈を持たないので、指示が曖昧すぎると意図した論理の飛躍をしてくれません。
- 簡潔な応答を直接頼む: 冗長な出力が続くなら、短く答えるよう明示します。LLMは単語ではなくトークンで数えるため、単語数の指定より段落数や文数の指定のほうが効きます。
max_tokensで上限を置く: 応答の最大長にハードリミットをかけます。
temperatureも短縮の手段として挙がっています。0.2のような低い値は焦点の絞られた短い応答に、0.8のような高い値は多様で長めの出力につながることが「ある」という書き方です。プロンプトの明確さ・出力品質・トークン数のバランスは、値を変えて試して決めます。
長い共通プロンプトはキャッシュでTTFTを縮める
毎回同じ長い指示や資料を先頭に付けるアプリでは、プロンプトキャッシュが効きます。cache_controlで共通の前置きをキャッシュすると、コストとレイテンシが下がります。公式のプロンプトキャッシュの説明では、長い文書で最初のトークンまでの時間が改善しやすいとされています。5分と1時間のキャッシュで、レイテンシの挙動は同じです。
コスト面では、キャッシュ読み取りは基本入力単価の10%です。Fable 5.1は2.5%、Opus 5.5とSonnet 5.5は5%と、モデルにより異なります。出力を減らす手段と違って、共通の前置きが長いアプリほど入力側の待ちを減らせます。
Opusだけの選択肢: 高速モード
Opus 5.5・Opus 5・Opus 4.8には、出力トークン毎秒を最大2.5倍にする高速モードがあります。リクエストにspeed: "fast"を指定し、ベータヘッダーfast-mode-2026-02-01を付けます。プレミアム価格で、リサーチプレビューの扱いです。アクセスにはアカウントマネージャーへの依頼かウェイトリスト登録が必要で、Claude APIのみで提供され、Amazon Bedrockなどでは使えません。公式の指標は出力トークン毎秒なので、最初のトークンまでの時間の短縮は保証されていません。
ストリーミングで見かけの待ち時間を縮める
ストリーミングは、応答全体が完成する前から生成済みの部分を送り始める機能です。リクエストに"stream": trueを付けるだけで有効になり、トークンが届くたびに画面へ出せば、生成時間が同じでも体感の応答は速くなります。
curl -sN https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-5-5",
"max_tokens": 1024,
"stream": true,
"messages": [{"role": "user", "content": "Hello"}]
}' | grep '^data: ' | sed 's/^data: //' \
| jq -rj 'select(.delta.type? == "text_delta") | .delta.text'curlの生の出力はSSE形式で、event:行とdata:行が交互に並びます。jqにそのまま渡すとJSONとして読めないので、data:行だけを取り出してから渡します。公式のCLI(ant messages create --stream --format jsonl)は1行1イベントのJSONで出力するため、jqに直接つなげます。
入れたあとにbaseline latencyだけを測ると、効果が数字に出ません。計測はTTFTに切り替えます。途中でエラーが起きたときの扱いはClaude APIストリーミングのエラー復旧にあります。コード側での組み立てはAgent SDKのストリーミング出力を有効にすると構造化出力とストリーミングの組み込みが扱っています。
どの打ち手がどの待ち時間に効くか
効く待ち時間の違い
最初のトークンまで
モデルをHaikuへ替える、effortを下げる、共通の前置きをキャッシュする、の3つが候補です。effortはthinkingを含む出力トークン全体に効くので、thinkingが長い設定ほど最初の本文までの待ちに響くと考えられます。
完了まで
出力を短くする、
max_tokensで絞る、高速モードで出力速度を上げる、の3つが候補です。出力が長いタスクほど、ここが効きます。見かけの待ち
ストリーミングだけです。
試す順序
1つずつ変えて測る
- 1
制約なしの基準を作る
冒頭で作った精度の出るプロンプトで、モデルもeffortも既定のまま基準の回答を保存します。
- 2
基準を計測する
time_starttransferと、time_totalからtime_starttransferを引いた値を、同じ入力で数回とります。どちらが長いかで、効く打ち手が分かれます。 - 3
待ち時間に合う打ち手を1つ変える
上のカードから該当する打ち手を1つ選びます。モデルとeffortは品質への影響も大きいので、変更ごとに基準の回答と見比べます。
1回に1つだけ変えると、どの変更がどれだけ効いたかを切り分けられます。
まとめ
打ち手を選ぶ前に、基準の2つの値のどちらが長いかを測っておきます。ストリーミングを入れたあとは、効果をbaseline latencyでなくTTFTで見ます。