はじめに
MCPを利用した場合、MCPのツール一覧情報で毎回一定(それなり)のトークン数を消費することになります。
この対応として、Prompt Caching を用いることでコストを削減できます。
本記事では、Amazon Bedrock 経由で Claude Sonnet 4 を利用して確認します。
Prompt Caching とは
すごく簡単に説明すると、繰り返し同じトークンを利用するケースにおいて、キャッシュに乗せておくことで、2回目からコストを抑えることができるというものです。
詳しくは公式情報をご覧ください。
どれくらいコスト削減できるの?
結論としては2回で元が取れます。
そして10回だとキャッシュを使わない場合と比較して22%程度の料金となる試算です。
試算根拠
ベースの料金(Bedrock 経由の Claude Sonnet 4 の場合)
項目 | 料金(1000トークンあたり) |
---|---|
入力(通常) | USD 0.003 |
キャッシュ書き込み | USD 0.00375 |
キャッシュ読み取り | USD 0.0003 |
正確な情報は公式をご覧ください。
https://aws.amazon.com/jp/bedrock/pricing/
1万トークン×2回で試算
- キャッシュなし:0.06
- キャッシュあり:0.0405(キャッシュなしの約67%の金額)
計算式:キャッシュなし
- 1回あたり:0.03 = 0.003 * (10,000 / 1,000)
- 計:0.06 = 0.03 * 2
計算式:キャッシュなし
- 1回目:0.0375 = 0.00375 * (10,000 / 1,000)
- 2回目:0.003 = 0.0003 * (10,000 / 1,000)
- 計:0.0405
1万トークン×10回で試算
- キャッシュなし:0.3
- キャッシュあり:0.0645(キャッシュなしの約22%の金額)
計算式:キャッシュなし
- 1回あたり:0.03 = 0.003 * (10,000 / 1,000)
- 計:0.3 = 0.03 * 10
計算式:キャッシュなし
- 1回目:0.0375 = 0.00375 * (10,000 / 1,000)
- 2回目以降:0.027 = 0.0003 * (10,000 / 1,000) * 9
- 計:0.0645
なお、利用している基盤モデルにもよりますので、厳密な確認はご自身で利用する製品・モデルの料金表を確認してください。
MCPのTOOL一覧とは?どれくらいトークン数を消費するの?
LLMがMCPのどのツールをどのように利用するか?を判断する元情報となるツール一覧情報です。
Playwright MCPの場合は、ツール数24個で約3,000トークンでした。
Playwright MCPは、1回の指示(HumanMessage)につき内部的に複数回LLMにアクセスしますが、その各タイミングにおいてトークンを消費しています。
どんな内容を保持している?
こんな感じでprintすると...
tools = await load_mcp_tools(session)
for i, tool in enumerate(tools):
print(i+1)
print("name:" + tool.name)
print("description:" + tool.description)
print("args_schema:" + str(tool.args_schema))
print("")
model_with_tools = prompt | model.bind_tools(tools)
こういう内容が確認できます。
1
name:browser_close
description:Close the page
args_schema:{'type': 'object', 'properties': {}, 'additionalProperties': False, '$schema': 'http://json-schema.org/draft-07/schema#'}
2
name:browser_resize
description:Resize the browser window
args_schema:{'type': 'object', 'properties': {'width': {'type': 'number', 'description': 'Width of the browser window'}, 'height': {'type': 'number', 'description': 'Height of the browser window'}}, 'required': ['width', 'height'], 'additionalProperties': False, '$schema': 'http://json-schema.org/draft-07/schema#'}
3
name:browser_console_messages
description:Returns all console messages
args_schema:{'type': 'object', 'properties': {}, 'additionalProperties': False, '$schema': 'http://json-schema.org/draft-07/schema#'}
...(省略するが24個目まで続く)
なお、Playwright MCPでは、公式のGithubからも確認できます。
(より詳しく確認したい場合にご覧いただければと思います。)
Bedrockのプレイグランドでの計測
参考値程度ですが、Bedrockのプレイグランドでトークン数を計測したところ、3016でした。
(後続で実際に動かしてみた際とは若干トークン数が異なりますが、ここではjson形式になっていないため等、微妙にフォーマットが異なるためだと解釈しています。)
Prompt Caching を有効にする方法
では、Prompt Caching を有効にしましょう。
Claude Sonnet 4 を利用しますが、Amazon Bedrock 経由であるため、Amazon のドキュメントを参照します。
AWS公式(Getting started > Converse API > system checkpoints)に従って、以下のようにcachePoint部分を追記します。
message = [
SystemMessage(
content=[
{
"type": "text",
"text": "あなたは日本語で回答するAIアシスタントです。必要に応じて「PlayWright」ツールを使い、得られた情報のみを根拠に回答してください。",
},
{
"cachePoint": {
"type": "default"
}
}
]
),
MessagesPlaceholder("messages"),
]
ポイント1:system に対して有効に
公式によるとキャッシュを有効にする場所は、以下の3カ所がありますが、(動かしてみた限り)MCP TOOL一覧をキャッシュさせたい場合は、systemが対象のようです。
- messages checkpoints
- system checkpoints
- tools checkpoints
ポイント2:cachePoint を指定
AWS公式では、Converse API と InvokeModel API で設定する内容が異なります。
- Converse API:
"cachePoint": {"type": "default"}
- InvokeModel API:
"cache_control": {"type": "ephemeral"}
また、Anthropic公式の例でも後者です。
(LangChain公式でもBedrock経由ではないので後者)
※今回は 前者 を指定する必要があります。
実行してみる
では、実行してみましょう。
指示はあるWebサイトにアクセスしてから、スクリーンショットを撮るように指示したものです。
(内部的に3回LLMが呼び出されます。)
トークン数は、このような形でコンソールに出力して確認します。
response = await graph.ainvoke({"messages":input_query}, graph_config)
print("=================================")
for msg in response["messages"]:
if isinstance(msg, AIMessage):
print(msg.usage_metadata)
キャッシュOFF
まずはキャッシュOFFから。
cache_creation(キャッシュ書き込み)、cache_read(キャッシュ読み取り)ともに0です。
キャッシュが効いていないことがわかります。
{'input_tokens': 3329,(中略),'input_token_details': {'cache_creation': 0, 'cache_read': 0}}
{'input_tokens': 4637,(中略),'input_token_details': {'cache_creation': 0, 'cache_read': 0}}
{'input_tokens': 4980,(中略),'input_token_details': {'cache_creation': 0, 'cache_read': 0}}
キャッシュON
1回目はcache_creationが、2回目以降はcache_readが3,149となっています。
また、その分、各回のinput_tokensが減っています。
キャッシュが有効になっていることがわかります。
キャッシュしたMCP TOOL一覧だけで、それ以外よりトークン数を多く消費していることも驚きですね!
{'input_tokens': 180,(中略),'input_token_details': {'cache_creation': 3149, 'cache_read': 0}}
{'input_tokens': 1488,(中略),'input_token_details': {'cache_creation': 0, 'cache_read': 3149}}
{'input_tokens': 1831,(中略),'input_token_details': {'cache_creation': 0, 'cache_read': 3149}}
キャッシュON(2回目)
続けてもう1度実行した場合、1回目からキャッシュ読込がされているのがわかります。
(Prompt Cachingは5分間有効であるため)
というわけで、短時間で何度も指示するケースでも有効ですね。
{'input_tokens': 180,(中略),'input_token_details': {'cache_creation': 0, 'cache_read': 3149}}
{'input_tokens': 1488,(中略),'input_token_details': {'cache_creation': 0, 'cache_read': 3149}}
{'input_tokens': 1831,(中略),'input_token_details': {'cache_creation': 0, 'cache_read': 3149}}
まとめ
いかがだったでしょうか。
Prompt Caching 機能の存在はありがたいですね。
MCPを利用する場合には必須かなと思います。
設定は簡単ですが、Bedrock経由の場合には、設定する内容を間違えないようにだけ気を付けていただければです。
(私は当初なかなか気づかずにはまってしまいました)
補足情報
前提として利用可能なツール一覧は限定しましょう
本記事では、説明の都合上、Playwright MCPで利用可能なツールはすべてLLMに渡しています。
実際の運用時には、利用可能なツール一覧は必要なもののみに限定しましょう。
当然ですが、Prompt Caching に乗せてもコストはかかりますので。
最小トークン数
キャッシュ可能なトークンは最小があり、それより少ないトークン数はキャッシュされません。
Claude Sonnet 4 の場合は1,024です。
設定したはずなのになぜか反映されないんだが???という場合は、これも疑ってみてください。
なお、モデルごとの最小値は公式に記載されています。
Prompt Caching に対応している基盤モデル
BedrockとAnthropicの公式サイトによると微妙に異なるようです。
(Claude Opus 3、Claude Haiku 3 は Anthropic にしか記述がないため、Bedrock経由の場合は利用できなさそうです。)
参考にさせていただいた記事
- Prompt Caching 関連
- LangGraph を利用した Playwright MCP 実装