まとまりのない文章になる可能性がありますが、わりと恥ずかしい失敗談なのでそのまま書きます。
AWSのコスト監視ツールで月末コストの予測機能を実装していたんですが、その予測ロジックがずっと自前計算でした。直近数日の平均を出して月の日数を掛けるだけの、単純な線形予測です。
これ、AWS Cost Explorer APIにget_cost_forecastという専用の予測APIが最初からあって、AWSコンソールに表示されているのと同じ予測値を取得できるんです。しかもその予測は機械学習ベースで、自前の線形予測とは精度が段違い。
つまり、最初からこれを使えばよかった。調べ不足のバグです。
自前計算でやっていたこと
もともとの実装はこうでした。
def calculate_forecast(daily_costs: list[float], days_in_month: int) -> float:
"""直近N日間の平均を使って月次予測を計算する"""
recent_days = daily_costs[-4:] # 直近4日分
daily_avg = sum(recent_days) / len(recent_days) if recent_days else 0.0
return daily_avg * days_in_month
月末予測 = 直近4日平均 × 月の日数
AWS Cost Explorer APIのget_cost_and_usageで日別コストを取得して、直近4日間の平均を出して、月の日数を掛ける。それだけです。
動いてはいました。数字も出ます。でも今思えば、「なぜ4日なのか」に根拠がないし、月の途中でコスト傾向が変わったときに追従できない。そもそもこの計算方法自体、AWSがすでにもっとちゃんとした予測を提供しているのに、わざわざ自前で劣化版を作っていたわけです。
気づいたきっかけ
AWSのコンソール(Cost Explorer画面)には月末予測の数字が表示されています。ある日、その数字と自前のモニタリングツールが出す予測値がズレていることに気づきました。
「どっちの数字が正しいんだっけ?」となって調べてみたら、AWSコンソールの予測は自前計算とはまったく違うロジックで作られていました。AWS公式ドキュメント(Forecasting with Cost Explorer)によると、Cost Explorerの予測は過去の利用データをもとに機械学習アルゴリズムで生成されていて、80%の予測区間(prediction interval)が設定されています。つまり「80%の確率で実際のコストがこの範囲に収まる」という統計的な裏付けがある予測です。
さらに、2025年11月のアップデート(AWS公式ブログ)では、分析対象の過去データが従来の6ヶ月から最大36ヶ月に拡大され、季節パターンや長期的な成長トレンドも考慮した予測が可能になっています。予測期間も12ヶ月から18ヶ月に延長されました。
そしてその予測値を取得するためのget_cost_forecastというAPIが普通にドキュメントに載っている。
ここ、罠です。get_cost_and_usage(コスト実績の取得)は知っていて使っていたのに、同じCost Explorer APIの中にあるget_cost_forecast(コスト予測の取得)を見落としていた。APIドキュメントをもう少しちゃんと読んでいれば、最初からこっちを使っていたはずです。
get_cost_forecast でやるべきだったこと
本来の実装はこれだけです。
def get_aws_forecast(start_date: datetime, end_date: datetime) -> float:
"""AWS Cost Explorer APIから月末予測を取得する"""
client = boto3.Session().client("ce")
response = client.get_cost_forecast(
TimePeriod={
"Start": start_date.strftime("%Y-%m-%d"),
"End": end_date.strftime("%Y-%m-%d"),
},
Metric="UNBLENDED_COST",
Granularity="MONTHLY",
)
total = response.get("Total", {})
return float(total.get("Amount", "0"))
自前計算とコード量はほとんど変わりません。むしろ「直近何日を使うか」「どう平均するか」といった、自分たちで決める必要のないパラメータがなくなるぶん、シンプルです。
graph LR
subgraph "自前計算(やっていたこと)"
A1[get_cost_and_usage<br/>日別コスト取得] --> A2[直近4日の平均計算]
A2 --> A3[平均 × 月日数]
end
subgraph "AWS予測API(やるべきだったこと)"
B1[get_cost_forecast<br/>を呼ぶだけ]
end
前述の通り、AWSの予測は最大36ヶ月の過去データを分析した機械学習ベースの予測です。「直近4日平均 × 日数」という自前の線形予測とは精度の次元が違う。そしてAWSコンソールの表示と一致する。いいことしかありません。
IAM権限は足りていた
修正にあたって心配だったのがIAMロールの権限です。get_cost_forecastを呼ぶにはce:GetCostForecastの権限が必要です。
確認したら、すでに付与済みでした。
# IAMポリシーの該当部分(簡略化)
Statement:
- Sid: AllowCostExplorerRead
Effect: Allow
Action:
- ce:GetCostAndUsage # 使用中
- ce:GetCostForecast # ← すでにある
- ce:GetDimensionValues
- ce:GetTags
Resource: '*'
つまり、権限を作った人はget_cost_forecastの存在を知っていて、使えるように準備していた。なのに実装する側がそれに気づかず自前計算を書いてしまった。コード側の修正だけで対応可能というのは助かりましたが、余計にもったいなさを感じます。
修正方針
修正はシンプルです。自前計算をAWS予測APIに置き換える。ただし、get_cost_forecastは80%の予測区間を満たすだけのデータがないとエラーを返す仕様です(請求サイクルが1回未満のアカウントや、月初のデータ不足時に起きやすい)。そのときだけ自前計算にフォールバックする形にしました。
graph TD
A[コスト予測の実行] --> B[AWS予測API呼び出し]
B --> C{API成功?}
C -->|Yes| D[AWS予測値を使用]
C -->|No| E[自前計算にフォールバック<br/>直近4日平均 × 月日数]
D --> F[予測値確定]
E --> F
設定ファイルで切り替えるオプションも用意しましたが、基本はAWS予測APIがデフォルトです。自前計算はあくまでフォールバック用。主従が逆転した形です。
教訓
「まずプラットフォームが何を提供しているか調べる」。これ自体は正しい教訓です。get_cost_and_usageを見つけた時点で「よし、コストは取れるな」と満足して、同じAPIの中に予測用のエンドポイントがあることを確認しなかった。
ただ、正直に言うと、AI駆動開発をやっていてこういう抜け漏れを完全にゼロにするのは難しいと思っています。AIと対話しながらコードを書いていると、目の前の課題が解決した瞬間に「できた」と満足して、周辺のAPIを網羅的に調べるステップを飛ばしがちです。開発のスピードが上がるぶん、確認の粒度が粗くなるというトレードオフがある。
むしろ大事なのは、抜け漏れを早く発見してリカバリーすることの方だと感じています。
今回で言えば、AWSコンソールの予測値とのズレに気づいて、get_cost_forecastの存在を知り、IAM権限が足りていることを確認し、フォールバック付きの修正方針を立てるまで、一連の流れとしてはかなり短時間で済みました。もし「完璧に調べてから作る」ことにこだわっていたら、最初の実装自体がもっと遅れていたかもしれない。
完璧な事前調査よりも、動くものを作って、ズレに気づいて、すぐ直す。AI駆動開発のスピード感を活かすなら、このサイクルの速さの方が価値があるんじゃないかと。自転車に乗る感覚と同じで、転ばないことより、転んだあとにすぐ起き上がれることの方が重要なのかもしれません。
参考:AWS運用について学ぶ
AWSのコスト管理やモニタリングを含む運用全般について体系的に学びたい場合は、以下のような入門書が参考になります。
[📦 商品リンク: moshimo-book-aws-operations]
Cost Explorer APIのような各種AWSサービスのAPIを活用した運用自動化の基礎を押さえることができます。