Priority Tier を契約してしばらく経った頃、奇妙な現象に気づきました。日中、ユーザーからの問い合わせが増える時間帯に限って、同じプロンプト・同じモデルなのに応答が普段より明らかに遅くなるのです。コードは何も変えていません。それでも夕方のピークだけ、体感で待たされる。
原因にたどり着くまで少し遠回りをしました。結論から言えば、私自身が裏側で回している自動ジョブが、ユーザー向けのリクエストと同じ優先枠を食い合っていたのです。service_tier というリクエストパラメータの挙動を理解していなかったことが、そのまま遅延として表面化していました。個人開発で Dolice Labs の4サイトぶんの定期処理と問い合わせ応答を1つの API キーで賄っていると、この食い合いはとても起きやすくなります。
ピーク時だけユーザーの応答が遅くなる、その正体
Priority Tier は、入力・出力トークンの毎分処理量をあらかじめ確保しておく契約枠です。確保した範囲では、混雑時でも優先的に処理され、レイテンシが安定します。問題は、その優先枠が「無限」ではなく「契約した分だけ」という点にあります。
service_tier のデフォルトは auto です。auto のリクエストは、優先枠に空きがあればそれを使い、なければスタンダード枠へ自動的に流れます。一見すると賢い挙動ですが、落とし穴があります。背景で動く自動ジョブも、何も指定しなければ auto として優先枠を消費しにいくのです。
私の場合、夕方のピークは「ユーザー問い合わせの増加」と「夕方に組んでいた記事生成バッチ」がちょうど重なる時間帯でした。背景ジョブが先に優先枠を埋めてしまい、肝心のユーザー向けリクエストが押し出されてスタンダード枠に落ちる。だから遅くなっていたわけです。
service_tier が決めているもの — auto と standard_only
service_tier が取り得る値と、それぞれの意味を整理しておきます。
| 値 | 挙動 | 向いているリクエスト |
| auto(既定) | 優先枠に空きがあれば使い、なければスタンダードへフォールバック | レイテンシを守りたいユーザー向けの同期リクエスト |
| standard_only | 優先枠を一切使わず、常にスタンダード枠で処理 | 多少遅くても構わない背景・定期ジョブ |
ここで大切なのは、standard_only は「遅くする設定」ではなく「優先枠を使わせない設定」だという理解です。スタンダード枠が空いていれば、standard_only でも十分に速く返ってきます。狙いは速度を落とすことではなく、契約した有限の優先枠を、本当に守りたいトラフィックのために空けておくことにあります。
なお、非同期で 24 時間以内に返れば十分な処理は、そもそも Batch 枠(約 50% 安)に逃がすのが第一選択です。Batch についてはClaude API の Messages Batches 非同期処理ガイドにまとめてあります。この記事で扱うのは、Batch に逃がせない「同期で受けたいが、ユーザー向けほど優先したくない」中間のワークロードの置き場所です。
リクエストに service_tier を指定する
指定は単純で、Messages API のリクエストボディに service_tier を1行加えるだけです。まずは Python の例です。
import anthropic
client = anthropic.Anthropic()
# 背景ジョブ: 優先枠を使わせない
message = client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=1024,
service_tier="standard_only", # ← 優先枠を消費しない
messages=[{"role": "user", "content": "この記事の要約を3文で"}],
)
# どの枠で処理されたかは usage に出る
print(message.usage.service_tier) # 例: "standard"
TypeScript(公式 SDK)でも同じ考え方です。
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const message = await client.messages.create({
model: "claude-haiku-4-5-20251001",
max_tokens: 1024,
service_tier: "standard_only", // 背景ジョブはスタンダードに固定
messages: [{ role: "user", content: "この記事の要約を3文で" }],
});
console.log(message.usage.service_tier); // "standard"
ユーザー向けの同期リクエスト側は、何も指定しない(= auto)か、明示的に service_tier: "auto" と書きます。明示しておくと、コードを読んだときに「ここは優先枠を使ってよい経路だ」という意図が一目で伝わります。
レスポンスの usage.service_tier で実態を確認する
設定よりも先に効いたのは、実は「観測」のほうでした。auto を指定したリクエストが、実際に優先枠で処理されたのか、それともスタンダードに落ちたのかは、レスポンスの usage.service_tier を見ないと分かりません。ここを記録していなかったために、私は遅延の原因を長く取り違えていました。
そこで、すべての呼び出しを薄いラッパーで包み、どの枠で処理されたかを必ずログに残すようにしました。
import logging
import anthropic
logger = logging.getLogger("claude")
client = anthropic.Anthropic()
def call(messages, *, tier="auto", label="unknown", **kwargs):
"""service_tier を明示しつつ、実際に使われた枠を記録する薄いラッパー"""
msg = client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=1024,
service_tier=tier,
messages=messages,
**kwargs,
)
served = msg.usage.service_tier # "priority" / "standard" / "batch"
# 要求した枠と実際に使われた枠の食い違いを後から追えるようにする
logger.info("tier_request=%s tier_served=%s label=%s in=%d out=%d",
tier, served, label,
msg.usage.input_tokens, msg.usage.output_tokens)
return msg
このログを1日ぶん集計すると、ピーク帯に tier_request=auto かつ tier_served=standard のリクエストがどれだけ発生していたかが数字で見えます。私の環境では、夕方の1時間に優先枠から押し出された auto リクエストが全体の3割近くに達していました。これが体感の遅延と一致したことで、ようやく原因が確定しました。
背景ジョブを standard_only に固定して優先枠を守る
観測で食い合いが裏付けられたら、対処は素直です。ユーザー向け以外のすべての呼び出しを standard_only に倒すのです。先ほどのラッパーがあれば、呼び出し側で tier を渡し分けるだけで済みます。
# ユーザーからの同期リクエスト: 優先枠を使ってよい
reply = call(user_messages, tier="auto", label="user_chat")
# 夜間・定期の自動ジョブ: 優先枠を温存するため standard_only
summary = call(batch_messages, tier="standard_only", label="nightly_summary")
運用に落とすときの手順は、私は次の順で進めました。
- まず観測だけ入れる。
service_tier は変えず、usage.service_tier のログだけ1〜2日とる
- ピーク帯で
auto がスタンダードに落ちている量を確認し、食い合いが本当に起きているか裏付ける
- 背景ジョブの呼び出しから順に
standard_only へ切り替える。ユーザー向け経路は最後まで触らない
- 切り替え後、ユーザー向け
auto の tier_served=priority 率が改善したかをログで確認する
ポイントは、いきなり全部を切り替えないことです。背景ジョブから一つずつ倒し、そのたびにユーザー向けの優先枠ヒット率が回復するかを見ます。こうすると、どのジョブが優先枠を一番食っていたのかも副産物として分かります。
どのワークロードをどの枠に置くか
判断の軸は「ユーザーがその場で待っているか」の一点に尽きます。私は次のように整理しています。
| ワークロード | 推奨する枠 | 理由 |
| ユーザー向けの同期応答(チャット・問い合わせ) | auto | レイテンシが体験に直結するため優先枠を使う |
| 同期で受けたい内部処理(管理画面の補助生成など) | standard_only | 遅延が許容でき、優先枠を温存したい |
| 非同期で 24 時間以内に返れば十分な処理 | Batch 枠 | 約 50% 安く、優先枠もスタンダード枠も圧迫しない |
工程ごとにモデルや推論の強さを変えてコストとレイテンシを詰める考え方は、stage 別に effort パラメータを調整する記事とも相性が良いです。service_tier は「どの枠で処理されるか」、effort は「どれだけ考えさせるか」を決めるので、両者は直交します。組み合わせると、ユーザー向けは優先枠かつ十分な effort、背景ジョブはスタンダード枠かつ控えめな effort、といった割り当てができます。
よくある落とし穴
Priority Tier を契約していないのに standard_only に期待しすぎる。 優先枠を契約していなければ、auto も standard_only も実質スタンダードで処理されるため、切り替えても速度は変わりません。この設定が効いてくるのは、有限の優先枠を持っていて、その配分を制御したい場合だけです。未契約なら、まず非同期処理を Batch に逃がすほうが効果が大きいです。
standard_only を「常に遅い枠」と誤解する。 スタンダード枠が空いていれば速く返ります。standard_only はレイテンシを犠牲にする設定ではなく、優先枠の取り合いに参加しない設定だと捉えてください。
usage.service_tier を見ずに auto のまま放置する。 観測がなければ、優先枠が枯渇していることにも気づけません。最低限、要求した枠と実際に使われた枠の組をログに残しておくと、ピーク帯の挙動が数字で追えます。
ピーク時の遅延をすべて 529 と混同する。 優先枠から押し出されてスタンダードで処理されるのは正常な動作で、エラーにはなりません。一方、スタンダード枠自体が混雑すると 529 が返ることがあります。混雑そのものへの対処はClaude API の 529 過負荷エラー対処に分けてまとめてあります。service_tier は「枠の配分」、529 対策は「混雑時の粘り方」で、役割が異なります。
まず確認したい一歩
コードを変える前に、usage.service_tier をログへ1行足すところから始めてみてください。要求した枠と実際に処理された枠の食い違いが数字で見えた時点で、自分のトラフィックのどこに優先枠を振り向けるべきかは自然と決まってきます。私自身、この観測を入れるまで原因を取り違えていたので、まず測ることをお勧めします。