如果您使用MCP,每次存取MCP工具資訊時都會消耗一定數量的代幣。
為了解決此問題,您可以使用 Prompt Caching 來降低成本。
在本文中,我們將透過 Amazon Bedrock 使用 Claude Sonnet 4 來驗證這一點。
簡單來說,如果重複使用同一個token,那麼就存放在快取中,從第二次開始就可以降低成本。
更多資訊請見官方資訊。
總的來說,您可以在兩次會議中收回您的投資。
估算一下,如果使用10次的話,費用大約是不使用現金時價格的22%。
<
詳情>
計算依據
| 專案 | 價格(每1000個代幣)|
|---------------|--------------------------|
| 輸入(正常)| 0.003 美元 |
| 現金寫入 | 0.00375 美元 |
| 快取讀取 | 0.0003 美元 |
準確資訊請以官方網站為準。
https://aws.amazon.com/jp/bedrock/pricing/
無緩存:0.06
現金:0.0405(約為無現金金額的67%)
每次使用:0.03 = 0.003 * (10,000 / 1,000)
計:0.06 = 0.03 * 2
第一次:0.0375 = 0.00375 * (10,000 / 1,000)
第二次:0.003 = 0.0003 * (10,000 / 1,000)
計:0.0405
無緩存:0.3
現金:0.0645(約為無現金金額的22%)
每次使用:0.03 = 0.003 * (10,000 / 1,000)
計:0.3 = 0.03 * 10
第一次:0.0375 = 0.00375 * (10,000 / 1,000)
從第二次開始:0.027 = 0.0003 * (10,000 / 1,000) * 9
計:0.0645
請注意,這取決於您使用的平台模型,因此請檢查您使用的產品和型號的價格表以了解具體細節。
就 Playwright MCP 而言,23 種工具的價格約為 3,000 個代幣。
此外,Playwright MCP 在內部依照指令(HumanMessage)多次存取 LLM,每次都會消耗令牌。
如果您像這樣列印它...
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#'}
...(省略するが23個目まで続く)
## 参考:Bedrockのプレイグランドでの計測
Bedrockのプレイグランドでトークン数を計測したところ、**2911**でした。

(後続で実際に動かしてみた際とは若干トークン数が異なりますが、ここではjson形式になっていないため等、微妙にフォーマットが異なるためだと解釈しています。)
# Prompt Caching を有効にする方法
では、Prompt Caching を有効にしましょう。
Claude Sonnet 4 を利用しますが、Amazon Bedrock 経由であるため、Amazon のドキュメントを参照します。
[AWS公式](https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-caching.html#prompt-caching-get-started)(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公式](https://docs.anthropic.com/ja/docs/build-with-claude/prompt-caching)の例でも後者です。
([LangChain公式](https://python.langchain.com/docs/integrations/chat/anthropic/#messages)でも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経由の場合には、設定する内容を間違えないようにだけ気を付けていただければです。
(私は当初なかなか気づかずにはまってしまいました🐶)
# 補足情報
### Prompt Caching に対応している基盤モデル
[Bedrock](https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-caching.html#prompt-caching-models)と[Anthropic](https://docs.anthropic.com/ja/docs/build-with-claude/prompt-caching#%E3%83%97%E3%83%AD%E3%83%B3%E3%83%97%E3%83%88%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5%E3%81%AE%E5%AE%9F%E8%A3%85%E6%96%B9%E6%B3%95)の公式サイトによると微妙に異なるようです。
(Claude Opus 3、Claude Haiku 3 は Anthropic にしか記述がないため、Bedrock経由の場合は利用できなさそうです。)
### 最小トークン数
キャッシュ可能なトークンは最小があり、それより少ないトークン数はキャッシュされません。
Claude Sonnet 4 の場合は1,024です。
設定したはずなのになぜか反映されないんだが???という場合は、これも疑ってみてください。
なお、モデルごとの最小値は[公式](https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-caching.html#prompt-caching-models)に記載されています。
# 参考にさせていただいた記事
- Prompt Caching 関連
- [Amazon Bedrock の Prompt Caching が GA したっぽいからためそうぜ](https://qiita.com/kazuneet/items/23c23fe4a450c46d8b94)
- [MCPサーバーを使うなら Prompt Caching が大切だと思い知った話](https://zenn.dev/ncdc/articles/26165a6fedd7e4)
- LangGraph を利用した Playwright MCP 実装
- [【Playwright MCP】を利用したエージェントを【LangGraph】で構築する](https://zenn.dev/asap/articles/59b8dd06d44754)
- [LangChain × Playwright MCP セッション管理を知らないとハマる落とし穴とその解決策](https://qiita.com/rairaii/items/27e24c07cb1c7ae11d6f)