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

Alibaba Cloud Model Studio:エクスプリシットキャッシュのベストプラクティス

最終更新日:Aug 26, 2026

このトピックでは、明示的キャッシュの使用方法とそのベストプラクティスについて説明します。リクエストにキャッシュマーカーを追加することで、明示的キャッシュは同一の入力コンテンツの場合に決定的なキャッシュヒットを保証し、コストとレイテンシーを大幅に削減します。

明示的なキャッシュを使用するタイミング

  • キャッシュヒットを保証する必要がある場合:明示的なキャッシュは、バックエンドリソースのスケジューリングに左右されず、100%決定的なヒットを保証します。アプリケーションで安定したコンテンツの再利用が必要な場合は、明示的なキャッシュが適しています。
  • 同じプロンプトを頻繁に再利用する場合:同一または一貫性が高いプロンプトを繰り返し送信する場合、明示的なキャッシュによりコストを大幅に削減できます。キャッシュの作成には、標準の入力料金に25%の追加料金がかかりますが、その後の各ヒットでは90%を節約できます。ヒットが1回あれば採算が取れます。
  • 本番環境のエージェントで長いコンテキストを管理する場合:エージェントアプリケーションでは、圧縮、要約、システムリマインダーなどの一般的なメカニズムにより、コンテキストが継続的に変化します。明示的なキャッシュを使用すると、重要なコンテキストセグメントをピン留めして再利用できるため、周辺のコンテキストが変化してもキャッシュされた状態が維持されます。

エージェントとコーディングツール

以下のエージェントとコーディングツールは、Anthropic プロトコルを使用して Model Studio に接続し、明示的キャッシュをネイティブでサポートします。それぞれのドキュメントに従って設定すると、自動的に明示的キャッシュを利用してコンテキスト管理を最適化します。

以下の例では Singapore エンドポイントを使用しています。他のリージョンの場合は、ベース URL を対応するリージョンエンドポイントに置き換えてください。

Claude Code

Claude Code v2.x 以降では、リクエストに cache_control マーカーが自動的に含まれます (system、env、最新のユーザーメッセージ) 。Model Studio の Anthropic 互換エンドポイントに接続した後、追加の設定は不要です。

設定

~/.claude/settings.json (Windows: C:\Users\<username>\.claude\settings.json) を作成または編集し、適切なプラン設定を行います。または、環境変数を介して接続することもできます。

export ANTHROPIC_BASE_URL="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/apps/anthropic"
export ANTHROPIC_AUTH_TOKEN="${DASHSCOPE_API_KEY}"
export ANTHROPIC_MODEL="qwen3.7-max"
claude

Anthropic プロトコルエンドポイントを設定します。

  • Token Plan (Team): https://token-plan.ap-southeast-1.maas.aliyuncs.com/apps/anthropic

  • Coding Plan: https://coding-intl.dashscope.aliyuncs.com/apps/anthropic

  • 従量課金: https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/apps/anthropic

    WorkspaceId を実際のワークスペース ID に置き換えてください。

詳細については、「Claude Code」をご参照ください。

オプション:セッション間のヒット率を向上させるには

デフォルトでは、Claude Code はシステムプロンプトに動的情報 (現在のディレクトリ、日付、git ステータス) を含めるため、セッション間のキャッシュヒット率が低下する可能性があります。起動時に次のフラグを追加すると、動的セクションをユーザーメッセージに移動できます。

claude --exclude-dynamic-system-prompt-sections

Open Code

OpenCode が @ai-sdk/anthropic を介して Model Studio の Anthropic 互換エンドポイントに接続すると、システムメッセージと最新の非システムメッセージに cache_control が自動的に挿入されます。

インストール
npm install -g opencode-ai
設定

設定ファイル ~/.config/opencode/opencode.json (Windows: C:\Users\<username>\.config\opencode\opencode.json) を作成します。

{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "bailian": {
      "npm": "@ai-sdk/anthropic",
      "name": "Alibaba Cloud Model Studio",
      "options": {
        "baseURL": "https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/apps/anthropic/v1",
        "apiKey": "{env:DASHSCOPE_API_KEY}"
      },
      "models": {
        "qwen3.7-max": { "name": "qwen3.7-max" }
      }
    }
  }
}

注記baseURL は /v1 で終わる必要があります。

export DASHSCOPE_API_KEY=sk-xxxxx
opencode run -m "bailian/qwen3.7-max" "..."

その他のプランのベース URL:

  • Token Plan (Team): https://token-plan.ap-southeast-1.maas.aliyuncs.com/apps/anthropic/v1
  • Coding Plan: https://coding-intl.dashscope.aliyuncs.com/apps/anthropic/v1

詳細については、「OpenCode」をご参照ください。

OpenClaw

Anthropic 互換エンドポイントを使用する場合、OpenClaw はシステムプロンプトと最新のユーザーメッセージに cache_control マーカーを自動的に挿入します。プロバイダーのベース URL が /apps/anthropic を指していれば、追加の設定を行わなくても、明示的なキャッシュが自動的に有効になります。

インストール
npm install -g openclaw
# または
curl -fsSL https://openclaw.ai/install.sh | bash
設定

設定ファイル ~/.openclaw/openclaw.json を編集します。"api" を "anthropic-messages" に設定し、ベース URL を設定します。

  • Token Plan (Team): https://token-plan.ap-southeast-1.maas.aliyuncs.com/apps/anthropic/v1
  • Coding Plan: https://coding-intl.dashscope.aliyuncs.com/apps/anthropic/v1
  • 従量課金: https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/apps/anthropic/v1

詳細については、「OpenClaw」をご参照ください。

オプション: カスタムキャッシュ境界

システムプロンプトに静的なテンプレートコンテンツと動的コンテンツ (タイムスタンプ、CWD など) の両方が含まれている場合は、それらの間に <!-- OPENCLAW_CACHE_BOUNDARY --> を挿入してください。OpenClaw は、境界の前の静的なプレフィックスにのみ cache_control を適用し、セッション間のヒット率を向上させます。

あなたは以下の規約に従う Python エンジニアです:
- 型ヒントは必須
- docstring は Google 形式

<!-- OPENCLAW_CACHE_BOUNDARY -->

現在時刻: 2026-05-25 18:42
作業ディレクトリ: /Users/<username>/project

この境界がない場合、OpenClaw は組み込みの戦略を使用してシステムプロンプト全体に cache_control を適用しますが、それでも明示的キャッシュのメリットを活用できます。

Hermes

hermes config set コマンドを使用してベース URL を設定してください。

  • Token Plan (Team): https://token-plan.ap-southeast-1.maas.aliyuncs.com/apps/anthropic/v1
  • Coding Plan: https://coding-intl.dashscope.aliyuncs.com/apps/anthropic/v1
  • 従量課金: https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/apps/anthropic/v1

詳細については、「Hermes Agent」をご参照ください。

API 統合

要点

  • キャッシュしたいメッセージコンテンツに "cache_control": {"type": "ephemeral"} を追加します。messages 配列の先頭からそのマーカーまでのすべてのコンテンツがブロックとしてキャッシュされます。
  • キャッシュされるコンテンツは、少なくとも 1024 トークンである必要があります。
  • 1 つのリクエストで最大 4 つのキャッシュマーカーをサポートします。
  • キャッシュ TTL は 5 分で、ヒットするたびに自動的に更新されます。
  • ツール定義は、キャッシュの目的上、システムプロンプトの一部です。ツールが変更されると、キャッシュにヒットしません。

クイックスタート

次の例は、基本的なワークフローを示しています。最初のリクエストでキャッシュが作成され、2 番目のリクエストでキャッシュにヒットします。

from openai import OpenAI
import os

client = OpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # WorkspaceId を実際のワークスペース ID に置き換えてください。
    base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1",
)

# キャッシュする長文 (1024 トークンを超える必要があります)
long_text_content = "<Your Long Text Here>" * 400

def get_completion(user_input):
    messages = [
        {
            "role": "system",
            "content": [
                {
                    "type": "text",
                    "text": long_text_content,
                    # キャッシュマーカー: messages の先頭からこのポイントまでのコンテンツがキャッシュされます
                    "cache_control": {"type": "ephemeral"},
                }
            ],
        },
        {"role": "user", "content": user_input},
    ]
    completion = client.chat.completions.create(
        model="qwen3.7-max",
        messages=messages,
        extra_body={"enable_thinking": False},
    )
    return completion

# 最初のリクエスト: キャッシュを作成
first = get_completion("Summarize the key points of this document")
print(f"Cache created: {first.usage.prompt_tokens_details.cache_creation_input_tokens}")
print(f"Cache hit: {first.usage.prompt_tokens_details.cached_tokens}")

# 2 番目のリクエスト: 同じシステムコンテンツ、異なる質問 — キャッシュにヒット
second = get_completion("What precautions are mentioned in the document?")
print(f"Cache created: {second.usage.prompt_tokens_details.cache_creation_input_tokens}")
print(f"Cache hit: {second.usage.prompt_tokens_details.cached_tokens}")
import anthropic
import os

client = anthropic.Anthropic(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/apps/anthropic",
)

# キャッシュする長文 (1024 トークンを超える必要があります)
long_text_content = "<Your Long Text Here>" * 400

def get_completion(user_input):
    response = client.messages.create(
        model="qwen3.7-max",
        max_tokens=1024,
        system=[
            {
                "type": "text",
                "text": long_text_content,
                # キャッシュマーカー
                "cache_control": {"type": "ephemeral"},
            }
        ],
        messages=[
            {"role": "user", "content": user_input},
        ],
    )
    return response

# 最初のリクエスト: キャッシュを作成
first = get_completion("Summarize the key points of this document")
print(f"Cache created: {first.usage.cache_creation_input_tokens}")
print(f"Cache hit: {first.usage.cache_read_input_tokens}")

# 2 番目のリクエスト: キャッシュにヒット
second = get_completion("What precautions are mentioned in the document?")
print(f"Cache created: {second.usage.cache_creation_input_tokens}")
print(f"Cache hit: {second.usage.cache_read_input_tokens}")

期待される出力:

Cache created: 2005
Cache hit: 0
Cache created: 0
Cache hit: 2005

最初のリクエストでキャッシュブロックが作成されます。2 番目のリクエストは、システムプロンプトのコンテンツが同一であるため、キャッシュにヒットします。キャッシュされたトークンは、標準の入力価格の 10% のみで課金されます。

キャッシュステータスの確認

レスポンスの usage フィールドを確認して、キャッシュの動作を検証してください。

  • cache_creation_input_tokens : キャッシュを新規作成した際のトークン数。0 より大きい値は、新しいキャッシュブロックが作成されたことを意味します。
  • usage.prompt_tokens_details.cached_tokens (OpenAI 互換) または cache_read_input_tokens (Anthropic 互換) : キャッシュにヒットしたトークンの数。0 より大きい値は、キャッシュにヒットしたことを意味します。

シナリオ別のベストプラクティス

複数ターンの会話

特徴:
  • ユーザーは複数ターンにわたってモデルと対話し、各リクエストには完全な会話履歴が含まれます。
  • 典型的なユースケース:カスタマーサービス、ナレッジ Q&A、コードアシスタント

ベストプラクティス:各リクエストの最後のメッセージに cache_control マーカーを追加します。各ターンでは、前のターンで作成されたキャッシュ (会話履歴) にヒットし、同時に次のターンのために現在のターンを含む新しいキャッシュを作成します。

例:
from openai import OpenAI
import os

client = OpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # WorkspaceId を実際のワークスペース ID に置き換えてください。
    base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1",
)

# システムプロンプト:製品マニュアル (1024 トークンを超える必要があります)
product_manual = """You are the support assistant for "BaiLian SmartHome" smart home controller. Here is the complete product manual:

## Product Overview
BaiLian SmartHome is a whole-home smart controller supporting voice control, scene automation, and energy management...

## Installation Guide
1. Install at a central location with good WiFi coverage...
2. Connect the power adapter (5V/2A)...

## FAQ
Q: Cannot connect to WiFi? A: Make sure your router supports 2.4GHz...
""" * 80  # 1024 トークンを超えるように繰り返します

messages = [{"role": "system", "content": product_manual}]

def chat(user_input):
    # ポイント:最後のユーザーメッセージに cache_control を追加します
    messages.append({
        "role": "user",
        "content": [
            {
                "type": "text",
                "text": user_input,
                "cache_control": {"type": "ephemeral"},
            }
        ],
    })
    completion = client.chat.completions.create(
        model="qwen3.7-max",
        messages=messages,
        extra_body={"enable_thinking": False},
    )
    assistant_msg = completion.choices[0].message.content
    messages.append({"role": "assistant", "content": assistant_msg})

    usage = completion.usage
    created = usage.prompt_tokens_details.cache_creation_input_tokens
    cached = usage.prompt_tokens_details.cached_tokens
    print(f"  [Cache] Created: {created} tokens, Hit: {cached} tokens")
    return assistant_msg

# 複数ターンの会話をシミュレートします
print("User: What voice assistants does BaiLian SmartHome support?")
print(f"Agent: {chat('What voice assistants does BaiLian SmartHome support?')[:80]}...\n")

print("User: What if I cannot connect to WiFi?")
print(f"Agent: {chat('What if I cannot connect to WiFi?')[:80]}...\n")

print("User: How many devices can it control simultaneously?")
print(f"Agent: {chat('How many devices can it control simultaneously?')[:80]}...")

期待される出力:

User: What voice assistants does BaiLian SmartHome support?
  [Cache] Created: 8739 tokens, Hit: 0 tokens
Agent: BaiLian SmartHome supports Tmall Genie, XiaoAi, Siri, and other voice assistants...

User: What if I cannot connect to WiFi?
  [Cache] Created: 151 tokens, Hit: 8739 tokens
Agent: For WiFi connectivity issues, try the following: 1. Confirm your router supports 2.4GHz...

User: How many devices can it control simultaneously?
  [Cache] Created: 101 tokens, Hit: 8890 tokens
Agent: BaiLian SmartHome can control up to 256 smart devices simultaneously...

2ターン目以降、各リクエストは前のターンのキャッシュ (会話履歴) にヒットし、同時に現在のターンを含む新しいキャッシュを作成します。会話のターン数が多ければ多いほど、節約効果は大きくなります。

本番エージェント (複数キャッシュマーカー)

特徴:
  • システムプロンプト、スキル/ツール定義、プロジェクトコンテキスト、ユーザーメッセージ/ツール呼び出しで構成される、長い複数ターンの会話。
  • セクションごとに変更頻度が異なります。
  • 典型的なユースケース:AI コーディングアシスタント (Claude Code、OpenClaw)、RAG ベースの Q&A システム

ベストプラクティス:複数のキャッシュマーカー (最大 4 つ) を使用して、さまざまな安定性レベルのコンテンツを固定します。各マーカーは、独立したブレークポイントとして機能するよう、別々のメッセージ (異なるロール) に配置する必要があります:

  • システムプロンプト — 1 つのマーカー (ほとんど変更されない)
  • スキル/ツール定義 — 1 つのマーカー (組み合わせで変更される可能性がある)
  • プロジェクトコンテキスト — 1 つのマーカー (切り替えまたは圧縮される可能性がある)
  • ユーザーメッセージ/ツール呼び出し — 1 つのマーカー (ターンごとに増加する)

例:この例では、3 つのキャッシュマーカーを使用して、システムペルソナとツール (マーカー 1)、ナレッジベース (マーカー 2)、会話履歴 (マーカー 3) を固定する、典型的なエージェントアーキテクチャをシミュレートします。ナレッジベースが独立したキャッシュブレークポイントを持つよう、ユーザーメッセージに配置されている点に注意してください — 複数のシステムメッセージは内部でマージされるため、個別のブレークポイントとして機能することはできません:

from openai import OpenAI
import os

client = OpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # WorkspaceId を実際のワークスペース ID に置き換えてください。
    base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1",
)

# レイヤー 1:システムペルソナ (ほとんど変更されない)
system_persona = """You are the senior AI support agent for "Model Studio Electronics". Your guidelines:
1. Answer questions based on the knowledge base
2. For information not in the knowledge base, say "Let me transfer you to a human agent"
3. Maintain a professional and friendly tone
4. If the user is unhappy, apologize first then resolve the issue

Below is your complete service specification and script guide:
""" + "Detailed service specification..." * 200  # 1024 トークンを超えることを確認

# レイヤー 2:ツール/スキル定義 (たまに変更される、例:新機能のリリース時)
tools_description = """### Available Tools
- search_product(query): Search product information
- check_inventory(sku, color): Check stock status
- create_ticket(type, description): Create a support ticket
- transfer_to_human(reason): Transfer to a human agent

### Tool Usage Rules
1. When user asks about product details, use search_product first
2. When user asks about stock/shipping, use check_inventory
3. When user requests return/exchange, use create_ticket
4. When a tool returns an error, apologize and transfer_to_human
""" + "Detailed tool usage examples..." * 150  # 1024 トークンを超えることを確認

# レイヤー 3:プロジェクトナレッジベース (半安定的、ユーザーが製品を切り替える際に変更される)
knowledge_base_product_a = """### Current product: Model Studio Pro Max Wireless Earbuds
- SKU: BL-PM-2024
- Price: CNY 599
- Colors: Night Black / Nebula White / Ice Blue
- Battery: 8 hours (ANC on), 12 hours (ANC off)
- Water resistance: IPX5
- Warranty: 1 year, 7-day no-questions-asked return
- Stock: Night Black (in stock) / Nebula White (low) / Ice Blue (out of stock)
""" * 50  # 1024 トークンを超えることを確認

def ask_agent(user_question, history=None):
    if history is None:
        history = []
    messages = [
        {
            "role": "system",
            "content": [
                {
                    "type": "text",
                    "text": system_persona + "\n\n" + tools_description,
                    "cache_control": {"type": "ephemeral"},  # マーカー 1:システムペルソナ + ツール
                }
            ],
        },
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": f"Here is the knowledge base for the current product:\n{knowledge_base_product_a}",
                    "cache_control": {"type": "ephemeral"},  # マーカー 2:ナレッジベース
                }
            ],
        },
        {"role": "assistant", "content": "Got it. I have the product details ready. How can I help you?"},
    ]
    messages.extend(history)
    # マーカー 3 を付けて現在の質問を追加
    messages.append({
        "role": "user",
        "content": [
            {
                "type": "text",
                "text": user_question,
                "cache_control": {"type": "ephemeral"},  # マーカー 3:会話履歴
            }
        ],
    })

    completion = client.chat.completions.create(
        model="qwen3.7-max",
        messages=messages,
        extra_body={"enable_thinking": False},
    )
    usage = completion.usage
    print(f"  Created: {usage.prompt_tokens_details.cache_creation_input_tokens}, "
          f"Hit: {usage.prompt_tokens_details.cached_tokens}")
    return completion.choices[0].message.content

# 最初のリクエスト
print("Q1: Is the Ice Blue color available?")
a1 = ask_agent("Is the Ice Blue color available?")
print(f"A1: {a1}\n")

# 2 番目のリクエスト:同じ製品 (ペルソナ + ツール + ナレッジベースがすべてヒット)
history = [
    {"role": "user", "content": "Is the Ice Blue color available?"},
    {"role": "assistant", "content": a1},
]
print("Q2: When will it be back in stock?")
a2 = ask_agent("When will it be back in stock?", history)
print(f"A2: {a2}")

期待される出力:

Q1: Is the Ice Blue color available?
  Created: 7659, Hit: 0
A1: I'm sorry, but the Ice Blue color... is currently out of stock...

Q2: When will it be back in stock?
  Created: 73, Hit: 7659
A2: I don't have access to specific restock dates... Let me transfer you to a human agent...

Q2 では、マーカー 2 までのプレフィックス (ペルソナ + ツール + ナレッジベース = 7,659 トークン) は変更されていないため、完全なキャッシュヒットになります。マーカー 2 以降の新しいコンテンツ (会話履歴 + 新しい質問) のみが処理を必要とします。

複数マーカーキャッシュの仕組み:
  • ユーザーが同じ製品について質問し続ける場合:ペルソナ、ツール、ナレッジベースはすべて変更されず、マーカー 2 のキャッシュ (最長プレフィックス一致) にヒットするため、最大限の節約効果が得られます。
  • 会話のターン数が増える場合:以前のコンテンツ (ペルソナ + ツール + ナレッジベース + 履歴) は前のターンのキャッシュにヒットし、新しいコンテンツのみが新しいキャッシュを必要とします。

注記コンテンツを最も安定しているものから最も安定していないものへと配置します:キャッシュヒット率を最大化するために、最も変更が少ないコンテンツ (例:システムペルソナ) を先頭に、最も変更が多いコンテンツ (例:現在の会話) を末尾に配置してください。

バッチ処理 (タスク完了)

特徴:
  • 単一ターンのリクエストで、コンテキストメモリは不要です。
  • 固定の長いシステムプロンプト (タスク指示) + 可変のユーザー入力 (処理対象データ)。
  • 典型的なユースケース:テキスト分類、意図認識、データ抽出、コンテンツモデレーション

ベストプラクティス:cache_control マーカーはシステムプロンプトにのみ追加します。システムプロンプトが変更されない限り、後続のすべてのリクエストはキャッシュにヒットします。

例:
from openai import OpenAI
import os

client = OpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # WorkspaceId を実際のワークスペース ID に置き換えてください。
    base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1",
)

# 長いシステムプロンプト:詳細な分類ルール (1024 トークンを超える必要があります)
classification_prompt = """You are a product review classifier. Classify each review into one of these categories:
- Positive
- Negative
- Neutral
- Question
- Complaint

Output only the category name, nothing else.

Detailed classification rules and examples:
""" + """Rules:
1. Positive: Contains positive sentiment words (e.g., "great", "excellent", "recommend"), or expresses satisfaction.
2. Negative: Contains negative sentiment words (e.g., "terrible", "disappointed", "return"), or expresses dissatisfaction.
3. Neutral: No clear sentiment, merely states facts.
4. Question: Phrased as a question asking for product information.
5. Complaint: Expresses suggestions for improvement or lodges a complaint.
""" * 100

# 分類するレビュー (バッチ処理をシミュレート)
reviews = [
    "This product is amazing, great quality, highly recommended!",
    "Shipping took a week and the packaging was damaged",
    "Does this come in red? Does it run large or small?",
    "You should add more size options, medium is too big for me",
    "It's okay I guess, nothing special, does what it says",
]

print("=== Batch Classification (Explicit Cache) ===")
for i, review in enumerate(reviews):
    completion = client.chat.completions.create(
        model="qwen3.7-max",
        messages=[
            {
                "role": "system",
                "content": [
                    {
                        "type": "text",
                        "text": classification_prompt,
                        "cache_control": {"type": "ephemeral"},  # 分類ルールをキャッシュ
                    }
                ],
            },
            {"role": "user", "content": review},
        ],
    )
    result = completion.choices[0].message.content
    cached = completion.usage.prompt_tokens_details.cached_tokens
    created = completion.usage.prompt_tokens_details.cache_creation_input_tokens
    print(f"Review {i+1}: \"{review[:40]}...\" -> {result}")
    print(f"  Created: {created}, Hit: {cached}")

期待される出力:

Review 1: "This product is amazing, great quality, ..." -> Positive
  Created: 10353, Hit: 0
Review 2: "Shipping took a week and the packaging w..." -> Negative
  Created: 0, Hit: 10353
Review 3: "Does this come in red? Does it run large..." -> Question
  Created: 0, Hit: 10353
Review 4: "You should add more size options, medium..." -> Complaint
  Created: 0, Hit: 10353
Review 5: "It's okay I guess, nothing special, does..." -> Neutral
  Created: 0, Hit: 10353

最初のリクエストでキャッシュが作成された後、後続のすべてのリクエストがそれにヒットします。1,000 アイテムを処理する場合、後続の 999 件のリクエストでは、入力トークンコストが 99% 以上削減されます。

キャッシュされたツール定義での関数呼び出し

特徴:
  • 長いツール定義リストを持つ関数呼び出しを使用します。
  • ツール定義はリクエスト間で変更されません。

ベストプラクティス:tools パラメータのコンテンツは、キャッシュのためにシステムプロンプトの一部となります。ツール定義がリクエスト間で完全に同一であること (同じ順序、同じフィールド順序、同じ構造) を確認し、メッセージコンテンツに cache_control マーカーを追加します。

from openai import OpenAI
import os

client = OpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # WorkspaceId を実際のワークスペース ID に置き換えてください。
    base_url="https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1",
)

# 1024 トークンの最小要件を満たすための長いテキスト
long_text_content = "<Your Code Here>" * 400

# ツール定義:リクエスト間で完全に同一である必要があります
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Get the current weather for a given city",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "City name"},
                    "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
                },
                "required": ["city"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "search_flights",
            "description": "Search flights between two cities",
            "parameters": {
                "type": "object",
                "properties": {
                    "origin": {"type": "string", "description": "Departure city"},
                    "destination": {"type": "string", "description": "Destination city"},
                    "date": {"type": "string", "description": "Departure date in YYYY-MM-DD format"}
                },
                "required": ["origin", "destination", "date"]
            }
        }
    }
]

def ask(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.7-max",
        messages=messages,
        tools=tools,
        extra_body={"enable_thinking": False},
    )
    usage = completion.usage
    print(f"  Created: {usage.prompt_tokens_details.cache_creation_input_tokens}, "
          f"Hit: {usage.prompt_tokens_details.cached_tokens}")
    tool_calls = completion.choices[0].message.tool_calls
    if tool_calls:
        print(f"  Tools called: {[t.function.name for t in tool_calls]}")
    return completion

# 最初のリクエスト:キャッシュを作成 (ツール定義を含む)
print("Q1: What's the weather in Beijing today?")
ask("What's the weather in Beijing today?")

# 2 番目のリクエスト:キャッシュにヒット
print("\nQ2: Find flights from Shanghai to Beijing tomorrow")
ask("Find flights from Shanghai to Beijing tomorrow")

期待される出力:

Q1: What's the weather in Beijing today?
  Created: 1995, Hit: 0
  Tools called: ['get_weather']

Q2: Find flights from Shanghai to Beijing tomorrow
  Created: 0, Hit: 1995
  Tools called: ['search_flights']

重要関数呼び出しのキャッシュヒットを最大化するポイント:

  • 一貫したツールの順序:tools 配列内でツールの順序を同じに保ってください。
  • 一貫したフィールドの順序:各ツール定義内で JSON フィールドの順序を同じに保ってください。
  • 一貫した構造:フィールドがオプショナルまたは空であっても、リクエスト間でフィールドを追加、削除、または順序変更しないでください。

重要な注意事項

  • コンテンツフォーマットの要件: cache_control を追加する場合、content フィールドは配列形式である必要があります。文字列形式のコンテンツはキャッシュマーカーをサポートしていません。
  • キャッシュマーカーの粒度: Qwen 3.5 以降のモデルは、メッセージレベルのキャッシュブレークポイントのみをサポートしています。単一のメッセージの content 配列内に複数の cache_control マーカーを配置しても、個別のブレークポイントは作成されません。システムは、そのメッセージ内の最後のマーカー位置でのみキャッシュを保存し、中間コンテンツブロックでトランケートマッチができません。また、複数のシステムメッセージは内部的に単一のセグメントにマージされるため、個別のブレークポイントとして機能できません。複数の独立したブレークポイントを作成するには、異なるロールのメッセージに cache_control マーカーを分散させます (例:system に 1 つ、user に 1 つ)。 Qwen 3.5 より前のモデルは、コンテンツレベル (メッセージ内) のブレークポイントをサポートしています。
  • 暗黙的キャッシュとの相互排他性: リクエストでは、1 つのキャッシングモードのみを使用できます。リクエストに cache_control マーカーが含まれている場合は明示的キャッシュが使用され、それ以外の場合は暗黙的キャッシュが自動的に使用されます。

対応モデル

明示的なキャッシュをサポートするモデルの一覧については、「コンテキストキャッシュ」をご参照ください。