Claude CodeのSavings Plansカバレッジ試算 — 買い増し量は安定使用量で決める
Cost Explorer APIのカバレッジ、利用率、購入推奨のJSONをclaude -pに渡し、Savings Plansの買い増し量を安定使用量から試算します。RIとの指標の違いと、購入前の確認点もまとめました。
Savings Plans(SP)を買い増すかどうかは、カバレッジの数字だけでは決まりません。カバレッジが低くても、増やした分が使い切れなければ余りが出ます。決め手は、時間帯が変わっても下回らない安定使用量です。
Cost Explorer APIは、カバレッジ、利用率、購入推奨の3つをJSONで返します。この3つをClaude Codeの非対話モード(claude -p)に渡せば、買い増し量の試算まで一気に進みます。算術はスクリプトに任せ、Claudeには読み解きと確認項目の洗い出しを担当させる分担にします。
買い増しの前に見る指標は3つある
指標の役割は次のとおりです。
| 見るもの | AWS CLIコマンド | 答える問い |
|---|---|---|
| カバレッジ | AWS CLIコマンドget-savings-plans-coverage | 答える問い対象になる使用量のうち、SPで賄えている割合は |
| 利用率 | AWS CLIコマンドget-savings-plans-utilization | 答える問いすでに買ったコミットを使い切れているか |
| 購入推奨 | AWS CLIコマンドget-savings-plans-purchase-recommendation | 答える問いAWSが示す時間あたりコミット額の目安は |
カバレッジの CoveragePercentage は、SPで賄えた使用量を、SP対象の使用量全体で割った割合です。計算はSP利用分のオンデマンド換算額に基づきます。利用率の UtilizationPercentage は逆向きの見方で、買ったコミットがどれだけ消費されたかを示します。未消費分は UnusedCommitment に出ます。
買い増しの順序はこうなります。先に利用率を見て、既存コミットが余っていないか確かめます。余っていれば、買い増しではなく現状の見直しが先です。次にカバレッジで未カバーの量を把握し、最後に購入推奨と突き合わせます。
3つのJSONを取得する
取得は人間のシェルで行い、Claudeには結果のファイルだけを渡します。AWS CLIのコマンドを許可する権限設計を省けるからです。
mkdir -p sp-review && cd sp-review
# 月次のカバレッジ(サービス別)
aws ce get-savings-plans-coverage \
--time-period Start=2025-10-01,End=2026-10-01 \
--group-by Type=DIMENSION,Key=SERVICE \
> coverage-by-service.json
# 日次のカバレッジ(全体。granularityとgroup-byは併用できない)
aws ce get-savings-plans-coverage \
--time-period Start=2026-09-01,End=2026-10-01 \
--granularity DAILY > coverage-daily.json
# 日次の利用率
aws ce get-savings-plans-utilization \
--time-period Start=2026-09-01,End=2026-10-01 \
--granularity DAILY > utilization-daily.json2本目のコマンドで --group-by を外しているのは、get-savings-plans-coverage が「GroupByを指定した場合はGranularityを指定できない」仕様だからです。利用率のほうは、そもそもどの軸でもグループ化できません。サービス別の利用率が欲しいときも、このAPIでは出せません。
期間にも制約があります。開始日は現在から13か月以内で、終了日は現在より前でなければなりません。つまり季節性を見るために使える遡り幅は約1年です。
購入推奨は期間を変えて3回取る
購入推奨は、取得の前に生成を依頼する2段構成です。公式の説明では、先に StartSavingsPlansPurchaseRecommendationGeneration で新しい推奨を作り、その後に GetSavingsPlansPurchaseRecommendation で取り出します。生成は1つの一括請求ファミリーあたり1日3回まで更新できます。
取得コマンドの必須オプションは、SPの種類、期間、支払い方法、遡り期間の4つです。遡り期間に指定できるのは7日、30日、60日の3択です。この3択を全部取るのが、このワークフローの肝になります。
aws ce start-savings-plans-purchase-recommendation-generation
for d in SEVEN_DAYS THIRTY_DAYS SIXTY_DAYS; do
aws ce get-savings-plans-purchase-recommendation \
--savings-plans-type COMPUTE_SP \
--term-in-years ONE_YEAR \
--payment-option NO_UPFRONT \
--lookback-period-in-days "$d" > "rec-$d.json"
done--savings-plans-type には COMPUTE_SP、EC2_INSTANCE_SP、SAGEMAKER_SP、DATABASE_SP が指定できます。ここでは例として COMPUTE_SP を使っています。
推奨は生成時点の使用量と契約済みSPの在庫を反映して作り直されます。取得ファイルには、いつ生成して取ったかを自分でファイル名や記録に残しておくと、後で突き合わせられます。
遡り期間ごとの差が「安定度」を教えてくれる
購入推奨の各要素には、次の値が入っています。
HourlyCommitmentToPurchase: 推奨される時間あたりのコミット額EstimatedAverageUtilization: 推奨どおり買った場合の推定利用率CurrentMinimumHourlyOnDemandSpend/CurrentAverageHourlyOnDemandSpend/CurrentMaximumHourlyOnDemandSpend: 遡り期間内の時間あたりオンデマンド支出の最小、平均、最大
3つの遡り期間で HourlyCommitmentToPurchase がほぼ同じなら、使用量が安定している目安になります。7日だけ突出しているなら、直近の一時的な負荷が推奨を押し上げている可能性があります。最小と平均が離れている場合も、時間帯による山谷が大きい状態です。
次の jq で3本を1表に並べます。
for d in SEVEN_DAYS THIRTY_DAYS SIXTY_DAYS; do
jq -r --arg d "$d" '
.SavingsPlansPurchaseRecommendation
.SavingsPlansPurchaseRecommendationDetails[]
| [$d, .HourlyCommitmentToPurchase, .EstimatedAverageUtilization,
.CurrentMinimumHourlyOnDemandSpend,
.CurrentAverageHourlyOnDemandSpend,
.CurrentMaximumHourlyOnDemandSpend] | @tsv' "rec-$d.json"
done > rec-compare.tsv出力は次のような形になります(数値は説明用の架空の値です)。
SEVEN_DAYS 6.20 97.1 4.10 7.80 15.30
THIRTY_DAYS 4.80 98.4 3.90 6.10 12.00
SIXTY_DAYS 4.70 98.6 3.80 5.90 11.50この架空の例なら、30日と60日はほぼ一致し、7日だけ上振れしています。直近1週間の負荷が一時的に高かったと読み、30〜60日側の約4.7〜4.8ドル/時を候補にして、買い増し量の検討を進める形になります。
Claudeの非対話モードに読ませる
整理したファイルをClaudeに渡します。標準入力で渡せば、ファイルを読ませるための権限設定が不要です。公式ドキュメントでも、差分を標準入力に流すとBashの許可がいらなくなると説明されています。標準入力の上限は10MBなので、サービス別の月次JSONが大きいときはjqで必要な項目に絞ってから渡します。
出力はスキーマで固定します。--output-format json に --json-schema を組み合わせると、結果が structured_output フィールドに入ります。
{
echo "## utilization"; jq -c '.Total' utilization-daily.json
echo "## coverage-daily"
jq -c '.SavingsPlansCoverages[]
| {d: .TimePeriod.Start, p: .Coverage.CoveragePercentage}' coverage-daily.json
echo "## recommendations"; cat rec-compare.tsv
} | claude -p "上の3種類の指標から、買い増し前に確認すべき点を挙げる。\
金額の計算はしない。計算が要る箇所は式だけ書く" \
--output-format json \
--json-schema '{"type":"object","properties":{"commitment_stable":{"type":"boolean"},"unused_risk":{"type":"string"},"checks_before_purchase":{"type":"array","items":{"type":"string"}}},"required":["commitment_stable","unused_risk","checks_before_purchase"]}' \
| jq '.structured_output'プロンプトで「金額の計算はしない」と縛っているのは、CLIの出力値が文字列で返るためです。ドキュメント上、HourlyCommitmentToPurchase や UtilizationPercentage はいずれも文字列型です。小数の掛け算を言語モデルに任せると桁がずれる余地があるので、数値の合成は jq かスクリプトで行い、Claudeには「何を確かめるべきか」の抽出を頼みます。
公式ドキュメントによれば、スキーマに合う結果が得られなかった場合は structured_output フィールド自体が付きません。スクリプトに組み込むときは、フィールドの存在を先に確認してください。
買い増し量は「下回らない時間額」から逆算する
コミットは時間あたりの金額で買います。使い切れない時間帯があれば、その分は未消費のコミットになります。ここから、試算は次の順序になります。
- 安定使用量を決める。遡り期間3本の最小オンデマンド支出と平均を見て、下回らない水準を見積もる
- 既存コミット額を引く。
get-savings-plans-utilizationのTotalCommitmentが現在のコミット額で、買い増しはその上積みになる - 候補額を推奨値と比べる。
HourlyCommitmentToPurchaseと自分の見積もりの差が大きければ、前提(対象サービスや期間)がずれていないか確かめる - 推奨額との差で利用率の下がり方を見る。
EstimatedAverageUtilizationは推奨額で買った場合の推定値で、自分の候補額に対する値ではない。候補額が推奨額より大きいときは、この値より利用率が下がる側に振れるので、差額分を最小オンデマンド支出の範囲で消費できるか確かめる
注意点は金額の基準です。カバレッジの計算はオンデマンド換算額に基づきます。オンデマンド支出の最小値と、コミット額が同じ基準の金額なのかは、出力項目の説明だけでは判断できません。両者を直接引き算せず、自作の見積もりは推奨値の妥当性を確かめる用途に留めます。
RIは指標が時間ベースで、見方が少し違う
リザーブドインスタンス(RI)も同じ型で確認できます。違いは指標の単位です。
| 項目 | Savings Plans | リザーブドインスタンス |
|---|---|---|
| カバレッジ | Savings Plansget-savings-plans-coverage(金額ベース) | リザーブドインスタンスget-reservation-coverage(--metrics にHour、Unit、Cost) |
| 利用率 | Savings Plansget-savings-plans-utilization | リザーブドインスタンスget-reservation-utilization |
| 余りの量 | Savings PlansUnusedCommitment | リザーブドインスタンスUnusedHours |
| 購入推奨 | Savings PlansSPの種類・期間・支払い方法を指定 | リザーブドインスタンスget-reservation-purchase-recommendation(--service が必須) |
RIの利用率には、購入した時間(PurchasedHours)と使用した時間(TotalActualHours)、未使用時間(UnusedHours)が含まれます。純粋な節約額は NetRISavings で、OnDemandCostOfRIHoursUsed から TotalAmortizedFee を引いた値です。RI側のカバレッジは対象がEC2、ElastiCache、RDS、Redshiftに限られます。
なお get-reservation-utilization が受け付けるグループ化は SUBSCRIPTION_ID のみです。個々の予約ごとの余りを見たいときは、この軸で分けて取ります。
購入前に確かめる6項目
試算結果をそのまま発注に回さず、次の6点を確認します。
発注前のチェック
- 既存コミットの利用率が100%近くで、余りが出ていない
- 遡り期間7日、30日、60日の推奨額が大きくずれていない
- 日次カバレッジで、平日と休日の落差が想定内に収まっている
- 13か月のカバレッジに、季節的な落ち込みの月がない
- 近いうちに止める予定のワークロードが、対象サービスに含まれていない
- 期間(1年か3年)と支払い方法の選択を、購入担当と合意している
推奨の遡り期間は最長60日です。つまり購入推奨だけでは、年に一度の閑散期は見えません。そこで13か月のカバレッジを補助線にします。月次カバレッジを --group-by なしで取り、最小の月に当たる使用量が推奨の前提を下回っていないかを、Claudeに表の形で列挙させる使い方が向いています。
落とし穴
推奨額をそのまま買うと、閑散期に余る
遡り期間の推奨は直近60日以内の使用量から作られます。年末年始や夏季など、60日より外の閑散期は推奨に反映されません。13か月の月次カバレッジで落ち込み月を確認し、その月の使用量でも消費できる額かを見てから決めます。
定期実行にするときの境界
月1回のレビューに組み込むなら、取得スクリプトと claude -p を同じシェルにまとめます。AWSの認証は専用の読み取りプロファイルに絞ります。
- 許可するのは参照系の
ce:Get*と、推奨の生成(ce:StartSavingsPlansPurchaseRecommendationGeneration)だけにする - 生成コマンド(
start-savings-plans-purchase-recommendation-generation)は1日3回までの更新制限があるため、リトライ処理に入れない - 購入は人が行い、スクリプトには含めない
請求データをMCP経由でClaudeに直接読ませる構成は、AWS Billing MCPサーバーの手順にまとめています。今回のようにJSONを前処理して渡す構成と比べると、MCPはClaudeが質問のたびにAPIを呼ぶ点が違います。急増の原因を分解したい場合はCSV起点の手順が向いています。
claude -p の基本オプションはClaude Codeのヘッドレスモードで整理しています。ログなどの大きな入力を渡すときの上限の扱いはclaude -pの10MB上限を参照してください。
まとめ
買い増しの判断は、カバレッジを上げることではなく、安定使用量にコミットを合わせることです。そのために、利用率で既存の余りを確かめ、遡り期間の違う3つの推奨で安定度を測り、13か月のカバレッジで閑散期を確認します。
Claudeに任せるのは、出力の読み解きと確認項目の洗い出しまでです。金額の合成は jq に寄せ、購入の最終判断は人が持ちます。この線引きなら、数字の取り違えと意図しない購入の両方を避けられます。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。
- code.claude.com/docs/en/headless
- docs.aws.amazon.com/cli/latest/reference/ce/get-savings-plans-coverage.html
- docs.aws.amazon.com/cli/latest/reference/ce/get-savings-plans-utilization.html
- docs.aws.amazon.com/cli/latest/reference/ce/get-savings-plans-purchase-recomme…
- docs.aws.amazon.com/cli/latest/reference/ce/get-reservation-utilization.html