すべてのプロダクト
Search
ドキュメントセンター

Alibaba Cloud Model Studio:Context Cache

最終更新日:Jan 29, 2026

大規模言語モデル (LLM) を呼び出す際、マルチターン対話や同じドキュメントについて複数の質問をする場合など、異なる推論リクエストで入力内容が重複することがあります。コンテキストキャッシュ機能は、これらのリクエストの共通プレフィックスをキャッシュすることで、推論中の冗長な計算を削減します。これにより、応答品質に影響を与えることなく、応答速度を向上させ、コストを削減します。

多様なシナリオの要件を満たすために、コンテキストキャッシュは 2 つのモードを提供します。利便性、確実性、コストのニーズに基づいてモードを選択できます。

  • 暗黙的キャッシュ:これは自動モードであり、追加の構成は不要で、無効にすることもできません。使いやすさが優先される一般的なシナリオに適しています。システムはリクエスト内容の共通プレフィックス自動的に識別してキャッシュします。ただし、キャッシュヒット率は保証されません。キャッシュされた部分は、標準の入力トークン価格の 20% で課金されます。

  • 明示的キャッシュ:このモードは手動で有効にする必要があります。特定のコンテンツに対して明示的にキャッシュを作成し、5 分間の有効期間内にキャッシュヒットを保証できます。キャッシュの作成に使用されるトークンは、標準の入力トークン価格の 125% で課金されます。その後のキャッシュヒットは、標準価格のわずか 10% のコストで済みます。

項目

暗黙的キャッシュ

明示的キャッシュ

応答の有効性に影響はありますか?

影響なし

影響なし

ヒット確率

保証されません。正確なヒット確率はシステムが決定します。

ヒットを保証

キャッシュトークンの課金

トークンの完全な単価を入力します。

標準入力トークン価格の 125%

入力トークンのキャッシュヒットに対する課金

トークンの単価の 20% を入力します。

トークン価格の 10% を入力します

キャッシュの最小トークン数

256

1,024

キャッシュの有効期間

保証されません。システムは長期間使用されていないキャッシュデータを定期的にパージします。

5 分 (ヒット時にリセット)

説明

暗黙的キャッシュと明示的キャッシュは相互排他的です。1 つのリクエストで使用できるモードは 1 つだけです。

暗黙的キャッシュ

サポート対象モデル

グローバル

グローバルデプロイメントモードでは、アクセスポイントとデータストレージは米国 (バージニア) リージョンに配置されます。モデル推論の計算リソースは世界中で動的にスケジュールされます。

国際

国際デプロイメントモードでは、アクセスポイントとデータストレージはシンガポールリージョンに配置されます。モデル推論の計算リソースは、中国本土を除く世界中で動的にスケジュールされます。

米国

米国デプロイメントモードでは、アクセスポイントとデータストレージは米国 (バージニア) リージョンに配置されます。モデル推論の計算リソースは米国内に限定されます。

中国本土

中国本土デプロイメントモードでは、アクセスポイントとデータストレージは北京リージョンに配置されます。モデル推論の計算リソースは中国本土に限定されます。

説明

スナップショットモデルと最新モデルは現在サポートされていません。

仕組み

暗黙的キャッシュをサポートするモデルにリクエストを送信すると、この機能は自動的に有効になります。システムは次のように動作します。

  1. 検索:リクエストを受信すると、システムは messages 配列内のコンテンツの共通プレフィックスがキャッシュに存在するかどうかを確認します。この確認はプレフィックスマッチングの原則に基づいています。

  2. 決定

    • キャッシュヒットが発生した場合、システムは後続の推論にキャッシュされた結果を使用します。

    • キャッシュミスが発生した場合、システムはリクエストを通常どおり処理し、将来の使用のために現在のプロンプトのプレフィックスをキャッシュに保存します。

システムは、長期間使用されていないキャッシュデータを定期的にパージします。コンテキストキャッシュのヒット率は 100% ではありません。同一のリクエストコンテキストでもキャッシュミスが発生する可能性があります。正確なヒット率はシステムが決定します。
説明

256 トークン未満のコンテンツはキャッシュされません。

キャッシュヒット確率の向上

暗黙的キャッシュは、異なるリクエストが共通のプレフィックスを共有しているかどうかを確認することでヒットを判断します。キャッシュヒット率を上げるには、繰り返されるコンテンツをプロンプトの先頭に、変化するコンテンツを末尾に配置します。

  • テキストモデル:たとえば、システムが「ABCD」をキャッシュしている場合、「ABE」のリクエストは「AB」部分でキャッシュヒットする可能性がありますが、「BCD」のリクエストはキャッシュヒットしません。

  • 視覚理解モデル:

    • 同じ画像またはビデオに関する複数の質問の場合は、画像またはビデオをテキストの前に配置すると、キャッシュヒット率が向上します。

    • 異なる画像またはビデオに関する同じ質問の場合は、テキストを画像またはビデオの前に配置すると、キャッシュヒット率が向上します。

課金

暗黙的キャッシュモードを有効にしても、追加料金は発生しません。

リクエストがキャッシュヒットした場合、一致した入力トークンは cached_token として課金され、標準の input_token 価格の 20% となります。一致しなかった入力トークンは、標準の input_token 価格で課金されます。出力トークンは標準価格で課金されます。

たとえば、リクエストに 10,000 の入力トークンが含まれ、そのうち 5,000 がキャッシュヒットした場合、課金は次のように計算されます。

  • 不一致トークン (5,000):標準価格の 100% で課金

  • 一致トークン (5,000):標準価格の 20% で課金

合計入力コストは、キャッシュなしモードのコストの 60% になります:(50% × 100%) + (50% × 20%) = 60%。

image.png

応答cached_tokens 属性からキャッシュされたトークンの数を取得できます。

OpenAI 互換バッチモードは、キャッシュ割引の対象外です。

キャッシュヒットの例

テキスト生成モデル

OpenAI 互換

OpenAI 互換のメソッドを使用して暗黙的キャッシュをトリガーすると、次のような応答が返されます。usage.prompt_tokens_details.cached_tokens でキャッシュされたトークンの数を確認できます。この値は usage.prompt_tokens の一部です。

{
    "choices": [
        {
            "message": {
                "role": "assistant",
                "content": "私は Alibaba Cloud によって開発された大規模言語モデルです。私の名前は Qwen です。"
            },
            "finish_reason": "stop",
            "index": 0,
            "logprobs": null
        }
    ],
    "object": "chat.completion",
    "usage": {
        "prompt_tokens": 3019,
        "completion_tokens": 104,
        "total_tokens": 3123,
        "prompt_tokens_details": {
            "cached_tokens": 2048
        }
    },
    "created": 1735120033,
    "system_fingerprint": null,
    "model": "qwen-plus",
    "id": "chatcmpl-6ada9ed2-7f33-9de2-8bb0-78bd4035025a"
}

DashScope

DashScope Python SDK または HTTP を使用してモデルを呼び出し、暗黙的キャッシュをトリガーすると、次のような応答が返されます。usage.prompt_tokens_details.cached_tokens でキャッシュされたトークンの数を確認できます。この値は usage.input_tokens の一部です。

{
    "status_code": 200,
    "request_id": "f3acaa33-e248-97bb-96d5-cbeed34699e1",
    "code": "",
    "message": "",
    "output": {
        "text": null,
        "finish_reason": null,
        "choices": [
            {
                "finish_reason": "stop",
                "message": {
                    "role": "assistant",
                    "content": "私は Alibaba Cloud の大規模言語モデルです。私の名前は Qwen です。記事、物語、詩など、さまざまな種類のテキストを生成でき、さまざまなシナリオやニーズに基づいて適応および拡張できます。さらに、さまざまな質問に答え、ヘルプとソリューションを提供できます。ご質問やサポートが必要な場合は、お気軽にお知らせください。最善を尽くしてサポートいたします。同じコンテンツを繰り返し送信しても、より詳細な応答が得られない場合があることにご注意ください。ニーズをよりよく理解できるように、より具体的な情報を提供するか、質問を変えることをお勧めします。"
                }
            }
        ]
    },
    "usage": {
        "input_tokens": 3019,
        "output_tokens": 101,
        "prompt_tokens_details": {
            "cached_tokens": 2048
        },
        "total_tokens": 3120
    }
}

視覚理解モデル

OpenAI 互換

OpenAI 互換のメソッドを使用して暗黙的キャッシュをトリガーすると、次のような応答が返されます。usage.prompt_tokens_details.cached_tokens でキャッシュされたトークンの数を確認できます。このトークン数は usage.prompt_tokens の一部です。

{
  "id": "chatcmpl-3f3bf7d0-b168-9637-a245-dd0f946c700f",
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "logprobs": null,
      "message": {
        "content": "この画像は、ビーチで女性と犬が触れ合っている心温まるシーンです。女性はチェック柄のシャツを着て砂の上に座り、犬と触れ合いながら微笑んでいます。犬はカラフルな首輪をつけた大きな薄い色の犬種で、前足を上げて女性と握手したりハイタッチしたりしているようです。背景には広大な海と空が広がり、フレームの右側から太陽の光が差し込み、シーン全体に暖かく平和な雰囲気を加えています。",
        "refusal": null,
        "role": "assistant",
        "audio": null,
        "function_call": null,
        "tool_calls": null
      }
    }
  ],
  "created": 1744956927,
  "model": "qwen-vl-max",
  "object": "chat.completion",
  "service_tier": null,
  "system_fingerprint": null,
  "usage": {
    "completion_tokens": 93,
    "prompt_tokens": 1316,
    "total_tokens": 1409,
    "completion_tokens_details": null,
    "prompt_tokens_details": {
      "audio_tokens": null,
      "cached_tokens": 1152
    }
  }
}

DashScope

DashScope Python SDK または HTTP を使用してモデルを呼び出し、暗黙的キャッシュをトリガーすると、キャッシュされたトークンの数が合計入力トークン (usage.input_tokens) に含まれます。特定のフィールドはリージョンとモデルによって異なります。

  • 北京リージョン:

    • qwen-vl-max および qwen-vl-plus の場合、値は usage.prompt_tokens_details.cached_tokens で確認できます。

    • qwen3-vl-plus および qwen3-vl-flash の場合、値は usage.cached_tokens で確認できます。

  • シンガポールリージョン:すべてのモデルで、値は usage.cached_tokens で確認できます。

現在 usage.cached_tokens を使用しているモデルは、将来的に usage.prompt_tokens_details.cached_tokens を使用するようにアップグレードされます。
{
  "status_code": 200,
  "request_id": "06a8f3bb-d871-9db4-857d-2c6eeac819bc",
  "code": "",
  "message": "",
  "output": {
    "text": null,
    "finish_reason": null,
    "choices": [
      {
        "finish_reason": "stop",
        "message": {
          "role": "assistant",
          "content": [
            {
              "text": "この画像は、ビーチで女性と犬が触れ合っている心温まるシーンです。女性はチェック柄のシャツを着て砂の上に座り、犬と触れ合いながら微笑んでいます。犬はカラフルな首輪をつけた大きな犬種で、前足を上げて女性と握手したりハイタッチしたりしているようです。背景には広大な海と空が広がり、フレームの右側から太陽の光が差し込み、シーン全体に暖かく平和な雰囲気を加えています。"
            }
          ]
        }
      }
    ]
  },
  "usage": {
    "input_tokens": 1292,
    "output_tokens": 87,
    "input_tokens_details": {
      "text_tokens": 43,
      "image_tokens": 1249
    },
    "total_tokens": 1379,
    "output_tokens_details": {
      "text_tokens": 87
    },
    "image_tokens": 1249,
    "cached_tokens": 1152
  }
}

利用シーン

リクエストが共通のプレフィックスを共有している場合、コンテキストキャッシュは推論速度を大幅に向上させ、推論コストを削減し、最初のパケットのレイテンシを短縮できます。以下は典型的なアプリケーションシナリオです。

  1. 長文に基づく Q&A

    これは、小説、教科書、法律文書など、固定の長文に対して複数のリクエストが必要なビジネスシナリオに適用されます。

    最初のリクエストのメッセージ配列

    messages = [{"role": "system","content": "あなたは国語の先生で、生徒の読解を手伝います。"},
              {"role": "user","content": "<記事の内容> この文章で著者はどのような感情や考えを表現していますか?"}]

    後続のリクエストのメッセージ配列

    messages = [{"role": "system","content": "あなたは国語の先生で、生徒の読解を手伝います。"},
              {"role": "user","content": "<記事の内容> この文章の第 3 段落を分析してください。"}]

    質問は異なりますが、どちらも同じ記事に基づいています。同一のシステムプロンプトと記事の内容が、大きく反復的なプレフィックスを形成し、高いキャッシュヒット率をもたらします。

  2. コード自動補完

    コード自動補完シナリオでは、LLM は既存のコンテキストに基づいてコードを補完します。ユーザーがコードを書き続けると、コードのプレフィックスは変更されません。コンテキストキャッシュは、以前のコードを保存して補完速度を高速化できます。

  3. マルチターン対話

    マルチターン対話を実装するには、各ターンの対話を messages 配列に追加する必要があります。したがって、各新しいリクエストは前のターンとプレフィックスを共有し、高いキャッシュヒット率をもたらします。

    最初のターンのメッセージ配列

    messages=[{"role": "system","content": "あなたは役立つアシスタントです。"},
              {"role": "user","content": "あなたは誰ですか?"}]

    2 回目のターンのメッセージ配列

    messages=[{"role": "system","content": "あなたは役立つアシスタントです。"},
              {"role": "user","content": "あなたは誰ですか?"},
              {"role": "assistant","content": "私は Alibaba Cloud が開発した Qwen です。"},
              {"role": "user","content": "何ができますか?"}]

    会話のターン数が増えるにつれて、キャッシュによる速度とコストのメリットはより大きくなります。

  4. ロールプレイングまたは few-shot 学習

    ロールプレイングまたは few-shot 学習シナリオでは、通常、モデルの出力形式を定義するためにプロンプトに広範なガイダンスを含めます。これにより、異なるリクエスト間で大きく反復的なプレフィックスが作成されます。

    たとえば、モデルにマーケティングの専門家として行動させるために、システムプロンプトにはかなりのテキストが含まれています。以下は、2 つのリクエストのメッセージ例です。

    system_prompt = """あなたは経験豊富なマーケティングの専門家です。次の形式で、さまざまな製品に関する詳細なマーケティング提案を提供してください。
    
    1. ターゲットオーディエンス:xxx
    
    2. 主なセールスポイント:xxx
    
    3. マーケティングチャネル:xxx
    ...
    12. 長期的な開発戦略:xxx
    
    提案が具体的で、実行可能で、製品の特徴に非常に関連していることを確認してください。"""
    
    # 最初のリクエストはスマートウォッチについて尋ねます
    messages_1=[
      {"role": "system", "content": system_prompt},
      {"role": "user", "content": "新しく発売されたスマートウォッチのマーケティング提案を提供してください。"}
    ]
    
    # 2 番目のリクエストはラップトップについて尋ねます。system_prompt は同一であるため、キャッシュヒットの可能性は高いです。
    messages_2=[
      {"role": "system", "content": system_prompt},
      {"role": "user", "content": "新しく発売されたラップトップのマーケティング提案を提供してください。"}
    ]

    コンテキストキャッシュを使用すると、ユーザーが製品タイプを頻繁に切り替えても (たとえば、スマートウォッチからラップトップへ)、キャッシュヒットがトリガーされた後、システムは迅速に応答できます。

  5. ビデオ理解

    ビデオ理解シナリオでは、同じビデオに関する複数の質問の場合、videotext の前に配置するとキャッシュヒット率が向上します。異なるビデオに関する同じ質問の場合、textvideo の前に配置するとヒット率が向上します。以下は、同じビデオに関する 2 つのリクエストのメッセージ例です。

    # 最初のリクエストはビデオの内容について尋ねます
    messages1 = [
        {"role":"system","content":[{"text": "あなたは役立つアシスタントです。"}]},
        {"role": "user",
            "content": [
                {"video": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/20250328/eepdcq/phase_change_480p.mov"},
                {"text": "このビデオの内容は何ですか?"}
            ]
        }
    ]
    
    # 2 番目のリクエストはビデオのタイムスタンプについて尋ねます。同じビデオなので、ビデオをテキストの前に配置するとキャッシュヒットの可能性が高まります。
    messages2 = [
        {"role":"system","content":[{"text": "あなたは役立つアシスタントです。"}]},
        {"role": "user",
            "content": [
                {"video": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/20250328/eepdcq/phase_change_480p.mov"},
                {"text": "ビデオ内の一連のイベントを説明してください。開始時刻 (start_time)、終了時刻 (end_time)、イベント (event) を JSON 形式で出力してください。```json``` コードブロックは含めないでください。"}
            ]
        }
    ]

明示的キャッシュ

暗黙的キャッシュと比較して、明示的キャッシュは手動での作成が必要でオーバーヘッドが発生しますが、より高いキャッシュヒット率と低いアクセスレイテンシを提供します。

使用方法

"cache_control": {"type": "ephemeral"} マーカーをメッセージに追加できます。システムは、各 cache_control マーカーの位置から最大 20 個の content ブロックを遡ってトレースすることで、キャッシュヒットを取得しようとします。

1 つのリクエストでサポートされるキャッシュマーカーは最大 4 つです。
  • キャッシュミス

    システムは、messages 配列の先頭から cache_control マーカーまでのコンテンツを使用する新しいキャッシュブロックを作成します。このブロックは 5 分間有効です。

    キャッシュはモデルが応答した後に作成されます。キャッシュヒットを試みることができるのは、作成リクエストが完了した後のみです。
    キャッシュブロックのコンテンツには、少なくとも 1,024 トークンが含まれている必要があります。
  • キャッシュヒット

    システムは、最長一致プレフィックスをキャッシュヒットとして選択し、キャッシュブロックの有効期間を 5 分にリセットします。

以下に例を示します。

  1. 最初のリクエストを送信:キャッシュマーカー付きで 1,024 トークン以上のテキスト A を含むシステムメッセージを送信します。

    [{"role": "system", "content": [{"type": "text", "text": A, "cache_control": {"type": "ephemeral"}}]}] 

    システムは最初のキャッシュブロックを作成し、キャッシュブロック A としてラベル付けします。

  2. 2 番目のリクエストを送信:次の構造を持つリクエストを送信します。

    [
        {"role": "system", "content": A},
        <その他のメッセージ>
        {"role": "user","content": [{"type": "text", "text": B, "cache_control": {"type": "ephemeral"}}]}
    ]
    • 「その他のメッセージ」が 20 エントリ以下の場合、キャッシュブロック A のキャッシュヒットが発生し、その有効期間は 5 分にリセットされます。同時に、システムは A、その他のメッセージ、および B に基づいて新しいキャッシュブロックを作成します。

    • 「その他のメッセージ」が 20 エントリを超える場合、キャッシュブロック A のキャッシュヒットは発生しません。システムは引き続き、完全なコンテキスト (A + その他のメッセージ + B) に基づいて新しいキャッシュブロックを作成します。

サポート対象モデル

Qwen Max:qwen3-max

Qwen Plus:qwen-plus

Qwen Flash:qwen-flash

Qwen-Coder:qwen3-coder-plus、qwen3-coder-flash

上記のモデルは、中国本土と国際の両方のデプロイメントモードで明示的キャッシュをサポートしています。
スナップショットモデルと最新モデルは現在サポートされていません。

Qwen VL:qwen3-vl-plus

qwen3-vl-plus モデルは、中国本土デプロイメントモードでのみ明示的キャッシュをサポートしています。

DeepSeek-Alibaba Cloud Model Studio:deepseek-v3.2

deepseek-v3.2 モデルは、中国本土デプロイメントモードでのみ明示的キャッシュをサポートしています。

クイックスタート

以下の例では、OpenAI 互換インターフェイスと DashScope プロトコルを使用したキャッシュブロックの作成とヒットのメカニズムを示します。

OpenAI 互換

from openai import OpenAI
import os

client = OpenAI(
    # 環境変数を設定していない場合は、次の行を api_key="sk-xxx" に置き換えてください
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # 北京リージョンのモデルの場合は、https://dashscope.aliyuncs.com/compatible-mode/v1 を使用します
    base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
)

# シミュレートされたコードリポジトリのコンテンツ。キャッシュ可能なプロンプトの最小長は 1,024 トークンです。
long_text_content = "<ご利用のコードはここに>" * 400

# リクエスト関数
def get_completion(user_input):
    messages = [
        {
            "role": "system",
            "content": [
                {
                    "type": "text",
                    "text": long_text_content,
                    # ここに cache_control マーカーを配置して、messages の先頭からこのコンテンツの位置までのキャッシュブロックを作成します。
                    "cache_control": {"type": "ephemeral"},
                }
            ],
        },
        # 質問内容は毎回異なります
        {
            "role": "user",
            "content": user_input,
        },
    ]
    completion = client.chat.completions.create(
        # 明示的キャッシュをサポートするモデルを選択します
        model="qwen3-coder-plus",
        messages=messages,
    )
    return completion

# 最初のリクエスト
first_completion = get_completion("このコードは何についてですか?")
print(f"最初のリクエストで作成されたキャッシュトークン: {first_completion.usage.prompt_tokens_details.cache_creation_input_tokens}")
print(f"最初のリクエストでヒットしたキャッシュトークン: {first_completion.usage.prompt_tokens_details.cached_tokens}")
print("=" * 20)
# 2 番目のリクエスト、同じコードコンテンツ、異なる質問
second_completion = get_completion("このコードはどのように最適化できますか?")
print(f"2 番目のリクエストで作成されたキャッシュトークン: {second_completion.usage.prompt_tokens_details.cache_creation_input_tokens}")
print(f"2 番目のリクエストでヒットしたキャッシュトークン: {second_completion.usage.prompt_tokens_details.cached_tokens}")

DashScope

import os
from dashscope import Generation
# 北京リージョンのモデルの場合は、base_url を https://dashscope.aliyuncs.com/api/v1 に設定します
dashscope.base_http_api_url = "https://dashscope-intl.aliyuncs.com/api/v1"

# シミュレートされたコードリポジトリのコンテンツ。キャッシュ可能なプロンプトの最小長は 1,024 トークンです。
long_text_content = "<ご利用のコードはここに>" * 400

# リクエスト関数
def get_completion(user_input):
    messages = [
        {
            "role": "system",
            "content": [
                {
                    "type": "text",
                    "text": long_text_content,
                    # ここに cache_control マーカーを配置して、messages の先頭からこのコンテンツの位置までのキャッシュブロックを作成します。
                    "cache_control": {"type": "ephemeral"},
                }
            ],
        },
        # 質問内容は毎回異なります
        {
            "role": "user",
            "content": user_input,
        },
    ]
    response = Generation.call(
        # 環境変数が設定されていない場合は、Model Studio API キーに置き換えてください: api_key = "sk-xxx",
        api_key=os.getenv("DASHSCOPE_API_KEY"), 
        model="qwen3-coder-plus",
        messages=messages,
        result_format="message"
    )
    return response

# 最初のリクエスト
first_completion = get_completion("このコードは何についてですか?")
print(f"最初のリクエストで作成されたキャッシュトークン: {first_completion.usage.prompt_tokens_details['cache_creation_input_tokens']}")
print(f"最初のリクエストでヒットしたキャッシュトークン: {first_completion.usage.prompt_tokens_details['cached_tokens']}")
print("=" * 20)
# 2 番目のリクエスト、同じコードコンテンツ、異なる質問
second_completion = get_completion("このコードはどのように最適化できますか?")
print(f"2 番目のリクエストで作成されたキャッシュトークン: {second_completion.usage.prompt_tokens_details['cache_creation_input_tokens']}")
print(f"2 番目のリクエストでヒットしたキャッシュトークン: {second_completion.usage.prompt_tokens_details['cached_tokens']}")
// 最小 Java SDK バージョンは 2.21.6 です
import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.MessageContentText;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;

import java.util.Arrays;
import java.util.Collections;

public class Main {
    private static final String MODEL = "qwen3-coder-plus";
    // コードリポジトリのコンテンツをシミュレートします (400 回の繰り返しで 1,024 トークン以上を確保)
    private static final String LONG_TEXT_CONTENT = generateLongText(400);
    private static String generateLongText(int repeatCount) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < repeatCount; i++) {
            sb.append("<ご利用のコードはここに>");
        }
        return sb.toString();
    }
    private static GenerationResult getCompletion(String userQuestion)
            throws NoApiKeyException, ApiException, InputRequiredException {
        // 北京リージョンのモデルの場合は、base_url を https://dashscope.aliyuncs.com/api/v1 に設定します
        Generation gen = new Generation("http", "https://dashscope-intl.aliyuncs.com/api/v1");

        // キャッシュコントロール付きのシステムメッセージを構築
        MessageContentText systemContent = MessageContentText.builder()
                .type("text")
                .text(LONG_TEXT_CONTENT)
                .cacheControl(MessageContentText.CacheControl.builder()
                        .type("ephemeral") // キャッシュタイプを設定
                        .build())
                .build();

        Message systemMsg = Message.builder()
                .role(Role.SYSTEM.getValue())
                .contents(Collections.singletonList(systemContent))
                .build();
        Message userMsg = Message.builder()
                .role(Role.USER.getValue())
                .content(userQuestion)
                .build();

        // リクエストパラメーターを構築
        GenerationParam param = GenerationParam.builder()
                .model(MODEL)
                .messages(Arrays.asList(systemMsg, userMsg))
                .resultFormat(GenerationParam.ResultFormat.MESSAGE)
                .build();
        return gen.call(param);
    }

    private static void printCacheInfo(GenerationResult result, String requestLabel) {
        System.out.printf("%s で作成されたキャッシュトークン: %d%n", requestLabel, result.getUsage().getPromptTokensDetails().getCacheCreationInputTokens());
        System.out.printf("%s でヒットしたキャッシュトークン: %d%n", requestLabel, result.getUsage().getPromptTokensDetails().getCachedTokens());
    }

    public static void main(String[] args) {
        try {
            // 最初のリクエスト
            GenerationResult firstResult = getCompletion("このコードは何についてですか?");
            printCacheInfo(firstResult, "最初のリクエスト");
            System.out.println(new String(new char[20]).replace('\0', '='));            // 2 番目のリクエスト
            GenerationResult secondResult = getCompletion("このコードはどのように最適化できますか?");
            printCacheInfo(secondResult, "2 番目のリクエスト");
        } catch (NoApiKeyException | ApiException | InputRequiredException e) {
            System.err.println("API 呼び出しに失敗しました: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

シミュレートされたコードリポジトリのコンテンツは、cache_control マーカーを追加することで明示的キャッシュを有効にします。このリポジトリに関する後続のリクエストは、再計算なしでキャッシュブロックを再利用します。これにより、応答が高速化され、コストが削減されます。

最初のリクエストで作成されたキャッシュトークン: 1605
最初のリクエストでヒットしたキャッシュトークン: 0
====================
2 番目のリクエストで作成されたキャッシュトークン: 0
2 番目のリクエストでヒットしたキャッシュトークン: 1605

複数のキャッシュマーカーを使用した詳細な制御

複雑なシナリオでは、プロンプトはしばしば、再利用頻度が異なる複数の部分で構成されます。複数のキャッシュマーカーを使用して、詳細な制御を有効にできます。

たとえば、インテリジェントなカスタマーサービスのプロンプトには、通常、次の部分が含まれます。

  • システムペルソナ:この部分は非常に安定しており、めったに変更されません。

  • 外部ナレッジ:この部分は半安定的で、ナレッジベースから取得されるか、ツールクエリを使用して取得されます。連続した会話中に変更されない場合があります。

  • 会話履歴:この部分は動的に増加します。

  • 現在の質問:この部分は毎回異なります。

プロンプト全体を単一のユニットとしてキャッシュすると、外部ナレッジの更新などのわずかな変更でもキャッシュミスが発生する可能性があります。

リクエストごとに最大 4 つのキャッシュマーカーを設定して、プロンプトの異なる部分に対して個別のキャッシュブロックを作成できます。これにより、ヒット率が向上し、詳細な制御が可能になります。

課金

明示的キャッシュは、入力トークンの課金にのみ影響します。課金ルールは次のとおりです。

  • キャッシュ作成:新しいキャッシュのコンテンツは、標準の入力価格の 125% で課金されます。新しいリクエストのキャッシュコンテンツに既存のキャッシュがプレフィックスとして含まれている場合、新しい部分のみが課金されます。課金額は、新しいキャッシュトークンの数から既存のキャッシュトークンの数を引いた数に基づいて計算されます。

    たとえば、既存のキャッシュ A に 1,200 トークンがあり、新しいリクエストで 1,500 トークンのコンテンツ AB をキャッシュする必要がある場合、最初の 1,200 トークンはキャッシュヒットとして標準価格の 10% で課金されます。新しい 300 トークンは、キャッシュ作成のために標準価格の 125% で課金されます。

    キャッシュ作成に使用されるトークンの数は、cache_creation_input_tokens パラメーターを使用して表示できます。
  • キャッシュヒット:キャッシュヒットは、標準の入力価格の 10% で課金されます。

    キャッシュされたトークンの数は、cached_tokens パラメーターを使用して表示できます。
  • その他のトークン:一致しないトークンやキャッシュ作成に使用されないトークンは、標準価格で課金されます。

キャッシュ可能なコンテンツ

messages 配列内の次のメッセージタイプのみがキャッシュマーカーをサポートします。

  • システムメッセージ

  • ユーザーメッセージ

    qwen3-vl-plus モデルでキャッシュを作成する場合、cache_control マーカーは、ユーザーメッセージ全体のキャッシュに影響を与えることなく、マルチモーダルコンテンツまたはテキストの後に続くことができます。
  • アシスタントメッセージ

  • ツールメッセージ (ツール実行結果)

    リクエストに tools パラメーターが含まれている場合、messages にキャッシュマーカーを追加すると、ツールの説明情報もキャッシュされます。

システムメッセージの場合、content フィールドを配列に変更し、cache_control フィールドを追加できます。

{
  "role": "system",
  "content": [
    {
      "type": "text",
      "text": "<指定されたプロンプト>",
      "cache_control": {
        "type": "ephemeral"
      }
    }
  ]
}

この構造は、messages 配列内の他のメッセージタイプにも適用されます。

キャッシュの制限

  • キャッシュ可能なプロンプトの最小長は 1,024 トークンです。

  • キャッシュは後方プレフィックスマッチングを使用します。システムは最後の 20 個のコンテンツブロックをチェックします。一致させるコンテンツが cache_control マーカーから 20 個以上のコンテンツブロックで区切られている場合、キャッシュヒットは発生しません。

  • type パラメーターでは ephemeral 値のみがサポートされます。この値は 5 分の有効期間を指定します。

  • 1 つのリクエストでサポートされるキャッシュマーカーは最大 4 つです。

    4 つ以上のマーカーが追加された場合、最後の 4 つのみが有効になります。

使用例

長文に対する異なる質問

from openai import OpenAI
import os

client = OpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # 北京リージョンのモデルの場合は、base_url を https://dashscope.aliyuncs.com/compatible-mode/v1 に設定します
    base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
)

# シミュレートされたコードリポジトリのコンテンツ
long_text_content = "<ご利用のコードはここに>" * 400

# リクエスト関数
def get_completion(user_input):
    messages = [
        {
            "role": "system",
            "content": [
                {
                    "type": "text",
                    "text": long_text_content,
                    # ここに cache_control マーカーを配置して、プロンプトの先頭からこのコンテンツの末尾まで (シミュレートされたコードリポジトリ) のキャッシュを作成します。
                    "cache_control": {"type": "ephemeral"},
                }
            ],
        },
        {
            "role": "user",
            "content": user_input,
        },
    ]
    completion = client.chat.completions.create(
        # 明示的キャッシュをサポートするモデルを選択します
        model="qwen3-coder-plus",
        messages=messages,
    )
    return completion

# 最初のリクエスト
first_completion = get_completion("このコードは何についてですか?")
created_cache_tokens = first_completion.usage.prompt_tokens_details.cache_creation_input_tokens
print(f"最初のリクエストで作成されたキャッシュトークン: {created_cache_tokens}")
hit_cached_tokens = first_completion.usage.prompt_tokens_details.cached_tokens
print(f"最初のリクエストでヒットしたキャッシュトークン: {hit_cached_tokens}")
print(f"キャッシュでヒットも作成もされなかった最初のリクエストトークン: {first_completion.usage.prompt_tokens-created_cache_tokens-hit_cached_tokens}")
print("=" * 20)
# 2 番目のリクエスト、同じコードコンテンツ、異なる質問
second_completion = get_completion("このコードにはどのような最適化が可能ですか?")
created_cache_tokens = second_completion.usage.prompt_tokens_details.cache_creation_input_tokens
print(f"2 番目のリクエストで作成されたキャッシュトークン: {created_cache_tokens}")
hit_cached_tokens = second_completion.usage.prompt_tokens_details.cached_tokens
print(f"2 番目のリクエストでヒットしたキャッシュトークン: {hit_cached_tokens}")
print(f"キャッシュでヒットも作成もされなかった 2 番目のリクエストトークン: {second_completion.usage.prompt_tokens-created_cache_tokens-hit_cached_tokens}")

この例では、コードリポジトリのコンテンツをプレフィックスとしてキャッシュします。後続のリクエストでは、このリポジトリについて異なる質問をします。

最初のリクエストで作成されたキャッシュトークン: 1605
最初のリクエストでヒットしたキャッシュトークン: 0
キャッシュでヒットも作成もされなかった最初のリクエストトークン: 13
====================
2 番目のリクエストで作成されたキャッシュトークン: 0
2 番目のリクエストでヒットしたキャッシュトークン: 1605
キャッシュでヒットも作成もされなかった 2 番目のリクエストトークン: 15
モデルのパフォーマンスを確保するために、システムは少数の内部トークンを追加します。これらのトークンは標準の入力価格で課金されます。詳細については、「よくある質問」セクションをご参照ください。

連続的なマルチターン対話

日常的なマルチターンチャットシナリオでは、各リクエストの messages 配列の最後のコンテンツにキャッシュマーカーを追加できます。2 ターン目から、各リクエストは前のターンで作成されたキャッシュブロックでキャッシュヒットし、そのキャッシュブロックを更新します。同時に、新しいキャッシュブロックが作成されます。

from openai import OpenAI
import os
  
client = OpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # 北京リージョンのモデルの場合は、base_url を https://dashscope.aliyuncs.com/compatible-mode/v1 に設定します
    base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
)

system_prompt = "あなたは機知に富んだ人物です。" * 400
messages = [{"role": "system", "content": system_prompt}]

def get_completion(messages):
    completion = client.chat.completions.create(
        model="qwen3-coder-plus",
        messages=messages,
    )
    return completion

while True:
    user_input = input("入力:")
    messages.append({"role": "user", "content": [{"type": "text", "text": user_input, "cache_control": {"type": "ephemeral"}}]})
    completion = get_completion(messages)
    print(f"[AI 応答] {completion.choices[0].message.content}")
    messages.append(completion.choices[0].message)
    created_cache_tokens = completion.usage.prompt_tokens_details.cache_creation_input_tokens
    hit_cached_tokens = completion.usage.prompt_tokens_details.cached_tokens
    uncached_tokens = completion.usage.prompt_tokens - created_cache_tokens - hit_cached_tokens
    print(f"[キャッシュ情報] 作成されたキャッシュトークン: {created_cache_tokens}")
    print(f"[キャッシュ情報] ヒットしたキャッシュトークン: {hit_cached_tokens}")
    print(f"[キャッシュ情報] キャッシュでヒットも作成もされなかったトークン: {uncached_tokens}")

コードを実行すると、質問を入力してモデルと通信できます。各質問は、前のターンで作成されたキャッシュブロックでキャッシュヒットします。

よくある質問

Q:暗黙的キャッシュを無効にするにはどうすればよいですか?

A:無効にすることはできません。暗黙的キャッシュは、応答品質に影響を与えないため、適用可能なすべてのモデルリクエストで有効になっています。また、キャッシュヒットが発生した場合、コストを削減し、応答速度を向上させます。

Q:明示的キャッシュを作成した後、なぜキャッシュヒットしなかったのですか?

A:考えられる理由は次のとおりです。

  • 5 分以内にキャッシュヒットが発生しませんでした。システムは有効期限が切れた後、キャッシュブロックをパージします。

  • 最後の content が既存のキャッシュブロックから 20 個以上の content ブロックで区切られている場合、キャッシュヒットは発生しません。新しいキャッシュブロックを作成することをお勧めします。

Q:明示的キャッシュにヒットすると、その有効期間はリセットされますか?

A:はい、リセットされます。各キャッシュヒットにより、キャッシュブロックの有効期間が 5 分にリセットされます。

Q:明示的キャッシュは異なるアカウント間で共有されますか?

A:いいえ、共有されません。暗黙的キャッシュと明示的キャッシュの両方のデータは、アカウントレベルで分離されており、共有されません。

Q:同じアカウントが異なるモデルを使用する場合、それらの明示的キャッシュは共有されますか?

A:いいえ、共有されません。キャッシュデータはモデル間で分離されており、共有されません。

Q:なぜ usageinput_tokenscache_creation_input_tokenscached_tokens の合計と等しくないのですか?

A:モデル出力の品質を確保するために、バックエンドサービスは、ユーザーが提供したプロンプトの後に少数のトークン (通常は 10 未満) を追加します。これらのトークンは cache_control マーカーの後に追加されます。したがって、キャッシュの作成や読み取りにはカウントされませんが、input_tokens の合計数には含まれます。