プロンプトキャッシュ
繰り返し使うプロンプトのプレフィックスを、入力料金のごく一部で利用できます。各ベンダーのキャッシュを使い、各会話をキャッシュを持つチャネルに固定する処理はゲートウェイに任せます。
プロンプトキャッシュを使うと、モデルは最近処理したプロンプトのプレフィックスについて、その処理結果を再利用できます。キャッシュされた入力の料金は、通常の入力料金のごく一部です。claude-sonnet-5.5 の場合、キャッシュ読み取りは 100 万トークンあたり $0.10 で、キャッシュされない入力の $2.00 と比べて大幅に安くなります。毎ターン履歴全体を送り直すエージェントや長いチャットでは、入力トークンの大半をキャッシュから提供できます。
Lovely Router 経由でキャッシュを機能させる仕組みは 2 つです。
- ベンダーのキャッシュ。 各ベンダーのキャッシュを、ドキュメントどおりにそのまま使います。
cache_controlやprompt_cache_keyなどのリクエストフィールドは変更されずに転送されます。 - 会話のアフィニティ。 キャッシュは、それを書き込んだチャネル上に存在します。ゲートウェイは 1 つの会話に属するターンを識別し、同じチャネルに送り返します。そのため、次のターンが届いたときにキャッシュが残っています。
Anthropic#
Claude は、マークした部分だけをキャッシュします。変化しないプレフィックス(ツール、システムプロンプト、以前のターン)の最後のブロックに cache_control を付けてください。ブレークポイントは最大 4 つまで設定できます。また、リクエストのトップレベルに cache_control を 1 つ置くと、最後のブロックまでのすべてがキャッシュされます。
response = client.messages.create(
model="claude-sonnet-5.5",
max_tokens=1024,
system=[{
"type": "text",
"text": SYSTEM_PROMPT_AND_REFERENCE_DOCS,
"cache_control": {"type": "ephemeral"},
}],
messages=history,
)
print(response.usage)レスポンスには、cache_creation_input_tokens(書き込み。キャッシュ書き込みの価格で課金)と cache_read_input_tokens(読み取り。キャッシュ読み取りの価格で課金)が報告されます。モデルの最小長に満たないプレフィックスはキャッシュされません。ブレークポイントの置き方や、キャッシュが無効になる条件については Anthropic のキャッシュガイドを参照してください。
OpenAI#
GPT のモデルは、長いプロンプトのプレフィックスを自動でキャッシュします。マークする必要はありません。プロンプトの変化しない部分を先頭に、変化する部分を末尾に置いてください。会話ごとまたはユーザーごとに固定の値を prompt_cache_key に設定するとヒット率が上がります。ゲートウェイもこの値を使って、その会話を 1 つのチャネルに固定します。
response = client.chat.completions.create(
model="gpt-6.1-sol",
messages=history,
prompt_cache_key="conv_8f2a91",
)
print(response.usage.prompt_tokens_details.cached_tokens)usage.prompt_tokens_details.cached_tokens はキャッシュ読み取りの価格で、prompt_tokens の残りは入力の価格で課金されます。GPT のモデルには、キャッシュ書き込みの料金は別途かかりません。OpenAI のキャッシュガイドを参照してください。
Gemini#
Gemini のモデルは、繰り返し使われるプレフィックスを自動でキャッシュします(暗黙的キャッシュ)。キャッシュされたトークンは usageMetadata.cachedContentTokenCount に表示され、キャッシュ読み取りの価格で課金されます。キャッシュ書き込みの料金はかかりません。cachedContents API による明示的なコンテキストキャッシュは利用できません。
会話の識別方法#
ゲートウェイは各会話にフィンガープリントを付けます。次の一覧のうち、最初に一致したものを使います。
| 識別に使う情報 | API 形式 |
|---|---|
x-session-id ヘッダー | すべて |
x-lovely-session ヘッダー | すべて |
x-claude-code-session-id ヘッダー(Claude Code が送信) | すべて |
本文の metadata.user_id | Anthropic |
本文の prompt_cache_key | OpenAI |
本文の user | OpenAI |
| システムプロンプトと最初のユーザーメッセージ | すべて |
最後のルールでは、何も指定する必要はありません。会話の以降のターンはメッセージを追加するだけなので、システムプロンプトと最初のユーザーメッセージは変わらず、すべてのターンが同じフィンガープリントになります。比較されるのは、それぞれの先頭 4,000 文字だけです。
フィンガープリントの範囲は、API キー、モデル、チャネルグループごとです。同じ会話でも、別のキーで送ったり別のモデルに送ったりすると、新しい固定が始まります。
会話が固定される期間#
会話は、最初に成功した呼び出しを処理したチャネルに固定されます。以降のターンは、まずそのチャネルに送られます。
- 期間。 固定は最長 1 時間で、会話が続いている間は更新されます。リクエストがないまま 30〜60 分経つと固定は期限切れになり、次のターンは新しい会話と同じように割り当てられます。
- キャッシュの期限切れ。 Anthropic Messages 形式では、会話がプロンプトキャッシュの有効期間(5 分。
cache_controlのブレークポイントでttl: "1h"を指定した場合は 1 時間)を超えて止まっていると、固定も終わります。守っていたキャッシュはその時点で消えているため、次のターンは前回のチャネルに戻らず、新しい会話と同じように割り当てられます。 - チャネルが混雑している場合。 固定先のチャネルが容量の上限に達している場合、ターンは別のチャネルに移って新たなキャッシュ書き込みの料金を払うのではなく、しばらく待機します(短いプロンプトでは約 1 秒、長いプロンプトでは最大 10 秒)。それでも空きがなければ、ターンは別のチャネルに移ります。
- チャネルが障害中の場合。 固定先のチャネルで障害が起きている場合、ターンは正常なチャネルに移り、固定もそれに合わせて移ります。そのターンでは新しいキャッシュが書き込まれ、以降のターンは再びそこから読み取ります。
セッション ID を明示的に送る#
ターン間で最初のユーザーメッセージが変わると、自動のフィンガープリントは機能しません。たとえば、アプリが古い履歴を書き換えたり要約したりする場合です。その場合は、会話ごとに固定の ID を送ってください。ヘッダーならどの API 形式でも使えます。
curl https://lovelyrouter.com/v1/messages \
-H "x-api-key: $LOVELY_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "x-session-id: conv_8f2a91" \
-H "content-type: application/json" \
-d '{"model": "claude-sonnet-5.5", "max_tokens": 1024,
"messages": [{"role": "user", "content": "Continue the report."}]}'本文のフィールドも使えます。Anthropic 形式では metadata.user_id、OpenAI 形式では prompt_cache_key です。ID は会話ごとに 1 つ使ってください。1 つの ID を無関係な多数の会話で使い回すと、それらがすべて 1 つのチャネルに集まってしまいます。
ログと請求でキャッシュの利用状況を確認する#
ログには、各呼び出しについて次の情報が表示されます。
| 項目 | 意味 |
|---|---|
| 入力 | キャッシュされない入力とキャッシュ書き込みの合計。 |
| キャッシュ | キャッシュから読み取られた入力トークン。 |
| キャッシュ書き込み(詳細) | キャッシュに書き込まれた入力トークン。 |
| キャッシュヒット(詳細) | すべての入力トークンに占めるキャッシュされたトークンの割合。 |
| アフィニティ(詳細) | explicit:セッション ID を送った。sticky:会話が固定されており、そのチャネルに戻った。new:会話の最初の呼び出し、または固定が期限切れだったか、固定先のチャネルが利用できなかった。none:フィンガープリントを作成できなかった。 |
ダッシュボードの概要には、すべての呼び出しにわたるキャッシュヒット率が表示されます。トークンは種類ごとにそれぞれの価格で課金されます。呼び出しの課金方法を参照してください。
ヒット率が低いときの確認ポイント
ある会話で毎ターン new と表示される場合、ターン間でシステムプロンプトか最初のユーザーメッセージが変わっています。よくある原因はシステムプロンプト内のタイムスタンプで、これはベンダー側のキャッシュも無効にします。タイムスタンプを最新のユーザーメッセージに移すか、セッション ID を明示的に送ってください。ターンが sticky と表示されているのに キャッシュ が空のままの場合は、プレフィックスがモデルの最小長を満たしているか、また Claude の場合は cache_control が付いているかを確認してください。