Prompt Caching でドキュメント分析の API 費用を8割減らした話
Claude Opus 4.6 の Prompt Caching を使い、業務委託先から届く仕様書・契約書の分析コストを月10万円台から2万円台に落とした実装と運用の記録
先月の API 請求を見て「あれ、安くない?」と二度見した。4月に月10万円を超えていたドキュメント分析の費用が、7月は2万円を切っていた。やったことは Prompt Caching の導入と、リクエストの投げ方を少し変えただけ。
自分の業務では、クライアントから届く仕様書・契約書・技術マニュアルを Claude Opus 4.6 に読ませて要点抽出やリスク洗い出しをしている。1ドキュメントあたり数万トークンになるものを、質問を変えながら何度も叩く。これが地味に高い。
なぜドキュメント分析は費用がかさむのか
Claude Opus 4.6 の入力トークン単価は $5/MTok(100万トークンあたり5ドル)。40ページの仕様書をトークンに変換するとだいたい5万〜8万トークンになる。これに対して「セキュリティ要件を抽出して」「納期に関するリスクを洗い出して」「見積もりに影響する曖昧な記述を指摘して」と3〜5回質問すると、同じドキュメントを毎回フルで送り直すことになる。
月に15〜20件のドキュメントを扱い、それぞれ平均4回の質問を投げると、入力だけで計算してもこうなる:
- 1ドキュメント平均 6万トークン × 4回 = 24万トークン
- 月20件で 480万トークン(4.8 MTok)
- 入力だけで $24、出力を加えると1ドキュメントあたりの出力が数千トークンなので合計で月 $50〜70 程度
実際にはシステムプロンプトやツール定義のトークンも加わるし、やり直しや追加質問もある。4月の請求は $680 ほど(約10万円強)だった。
Prompt Caching で何が変わるか
Prompt Caching の仕組みはシンプルで、リクエストの「変わらない部分」をキャッシュに保存し、2回目以降はキャッシュから読み出す。キャッシュヒット時の入力トークン単価は $0.50/MTok。通常の10分の1になる。
つまり、同じドキュメントに対して2回目以降の質問では、ドキュメント部分のトークンが9割引きで処理される。
初回のキャッシュ書き込みには 1.25倍(5分TTL)または 2倍(1時間TTL)のコストがかかるが、2回目の質問でもう元が取れる。ドキュメント分析のように「同じ文書に繰り返し質問する」パターンは、Prompt Caching の最も効きやすいユースケースの一つ。
実装:明示的キャッシュブレークポイントを使う
自動キャッシュ(リクエストのトップレベルに cache_control を置く方式)でも動くが、ドキュメント分析ではシステムプロンプトとドキュメント本文を明示的に分けてキャッシュした方がヒット率が安定する。
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
async function analyzeDocument(document: string, question: string) {
const response = await client.messages.create({
model: "claude-opus-4-6",
max_tokens: 4096,
system: [
{
type: "text",
text: "あなたは業務委託契約・仕様書の分析に特化したアシスタントです。リスク、曖昧な記述、見積もりへの影響を具体的に指摘してください。",
},
{
type: "text",
text: document,
cache_control: { type: "ephemeral" },
},
],
messages: [
{ role: "user", content: question },
],
});
return response;
}
ポイントは cache_control: { type: "ephemeral" } をドキュメント本文のブロックに付けること。システムプロンプトの指示部分は短いのでキャッシュの恩恵が小さく、ドキュメント本文(数万トークン)にキャッシュを効かせるのが費用的に一番効く。
Opus 4.6 ではキャッシュの最小トークン数が 1,024トークン なので、数万トークンの仕様書なら余裕でキャッシュ対象になる。
1時間TTLを選んだ理由
デフォルトのキャッシュ有効期間は5分間。キャッシュ書き込みコストは 1.25倍で済むが、5分はドキュメント分析には短すぎる。仕様書を読みながら質問を考え、結果を見て次の質問を練る——この一連の作業に20〜30分はかかる。
1時間TTLに変えた:
cache_control: { type: "ephemeral", ttl: "1h" },
書き込みコストは2倍($10/MTok)になるが、1時間以内に複数回質問できる安心感がある。3回以上質問すれば5分TTLより安くなる計算で、実際には1ドキュメントあたり平均4回は質問するのでこちらの方が得。
実際のコスト変化
7月の最初の2週間で計測した結果(手元の管理画面から拾った数字):
| 項目 | キャッシュなし(4月実績) | キャッシュあり(7月前半) |
|---|---|---|
| 月間ドキュメント数 | 約20件 | 約18件 |
| 1件あたり平均質問数 | 4回 | 4回 |
| 月間入力トークン(概算) | 4.8 MTok | 初回1.2 MTok + キャッシュ読み3.6 MTok |
| 入力コスト | 約 $24 | 初回書き込み $12 + キャッシュ読み $1.8 = 約 $14 |
| 出力コスト | 約 $30 | 約 $28 |
| その他(ツール・システム) | 約 $16 | 約 $10 |
| 月間合計(見込み) | $680前後 | $120〜140前後 |
入力コストだけ見ると劇的ではないように見えるが、実は4月の $680 には「同じドキュメントの微妙に異なるバージョンを何度も送り直した分」や「質問のやり直し」がかなり含まれていた。キャッシュ導入後はドキュメントを一度キャッシュに載せれば気軽に質問を投げ直せるようになり、無駄な再送が減ったのが大きい。心理的に「もう1回聞いてみよう」のハードルが下がった結果、質問の質も上がって、かえってトータルのリクエスト数は微減した。
ハマったところ
キャッシュが効かないと思ったらシステムプロンプトの順序だった。 キャッシュはプレフィクスマッチで動く。システムプロンプトの最初のブロック(指示文)を少しでも変えると、その後ろのドキュメントキャッシュも無効になる。ある日、指示文の末尾に一文足したら、その日のリクエストが全部キャッシュミスになっていた。usage レスポンスの cache_read_input_tokens が 0 になっていて気づいた。
対策はシンプルで、指示文を変更するときはドキュメント分析のキャッシュが切れるタイミング(次の新規ドキュメント)に合わせる。あるいは指示文自体もキャッシュブレークポイントを付けて2段構えにする。
ツール定義を変えてもキャッシュが壊れる。 tools 配列の内容が変わるとキャッシュの先頭から再計算になる。ツール定義はドキュメントキャッシュより前に評価されるので、ツールを追加したり説明文を修正するとドキュメントのキャッシュも巻き添えで無効になる。ツール定義は安定させてから運用に入れるべき。
キャッシュの効果を確認する方法
レスポンスの usage フィールドを見れば一目瞭然:
{
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 62500,
"input_tokens": 150
}
cache_read_input_tokens に数字が入っていればキャッシュヒットしている。cache_creation_input_tokens が 0 なら、新規書き込みなしでキャッシュから読めている。自分は簡単なログを仕込んで、ヒット率を週次で見ている。7月前半のヒット率はだいたい7〜8割といったところ。
この方法が向いているケース
- 同一ドキュメントに対して複数の観点で質問する業務(契約書レビュー、仕様書分析、マニュアル校正)
- ドキュメントが数万トークン以上ある
- 質問のたびにドキュメント全文を送り直している
逆に、毎回異なるドキュメントを1回だけ処理して終わるようなパイプラインでは、キャッシュ書き込みコストの分だけ割高になる。その場合は Batch API(入出力50%オフ)の方が合う。
月10万円が2万円になったのは、Prompt Caching 単体の効果というより、キャッシュ前提でリクエストの構造を整理し直したことの副産物でもある。無駄な再送をなくし、質問の粒度を揃え、ツール定義を安定させる——地味だけど、これが一番効いた。