M
masaki.work

AIにAPIを叩かせるなら、コストは自分で見ろ

ai api cost-optimization claude-code

この記事の全文をコピーして、AIに「この通りに設定をガイドして」と渡すと便利です

📊この記事の図解版があります。内容を視覚的にまとめたページで、全体像をサッと把握できます

図解を見る

AIにAPIを叩かせるなら、コストは自分で見ろ

「クレジットが足りない」という警告が出た。

想定より、明らかに早い。

X API を Pay-per-use(従量課金)で使っている。自作の投稿支援ツールを1日2〜3回動かす程度だ。月のクレジットが余裕で足りる計算だった。なのに、まだ月の半ばで警告が飛んできた。

「まあ、もう少し課金すればいいか」とは思わなかった。計算が合わないなら、原因がある。原因があるなら、直せる。

この記事は、AIツールが裏で叩いているAPIのコストを可視化し、キャッシュで9割削減した実践記録だ。技術的には地味な話だが、小さな違和感をスルーしないという姿勢の話でもある。


AIは気前よくAPIを叩く

僕は x-post というCLIツールを自作して使っている。X(旧Twitter)への投稿をAIが支援してくれるツールだ。投稿案の生成、エンゲージメント分析、フォロワーの増減トラッキング——ひと通りの機能が揃っている。

このツールはX APIを従量課金プランで叩いている。1日2〜3回実行する程度だから、月のクレジットには余裕があるはずだった。

問題は、AIが毎回律儀に全データを取りに行く設計になっていたことだ。

フォロワーリストの取得を例にとる。フォロワー660人。APIは1回のリクエストで最大100件しか返さない。つまり全件取得するには7回のAPIコール(ページネーション)が必要になる。これを毎回の実行でやっていた。

さらにエンゲージメント(いいね・リポスト・返信の数)も、30日以内の全投稿を毎回取得していた。朝に取得したデータを、昼にもう一度取りに行く。数時間で劇的に変わるわけがないのに。

内訳はこうだ。フォロワーリスト取得に7コール、エンゲージメント取得に1コール、自分のプロフィール情報取得に1コール。合計9コール。1日3回実行すれば27コール。月810コール。クレジットが減るのは当然だった。


原因は「キャッシュがない」だけだった

原因を調べるのに30分もかからなかった。

コードを読めば一目瞭然だ。フォロワーリスト取得のロジックに、前回取得したデータを再利用する仕組みが一切なかった。毎回APIを叩いて、毎回全件取得して、毎回保存する。正直で愚直な実装だ。

面白いことに、前回の実行結果(スナップショット)には follower_ids というフィールドが保存されていた。データはあるのに、次の実行時に参照していなかった。宝の持ち腐れだ。

問題を3つに分解する。

#無駄内容
1フォロワー全件取得660人を毎回7 APIコールで取得。前回データを使わない
2エンゲージメント毎回取得6時間前に取ったデータをまた取りに行く
3既存データ未活用スナップショットに follower_ids があるのに無視

3つとも、答えは同じだった。キャッシュを入れればいい。

キャッシュとは、一度取得したデータを手元に保存しておいて、次回はそれを使い回す仕組みのことだ。ウェブ開発の世界で何十年も使われてきた、古典中の古典。TTL(Time To Live = データの有効期限)を設定して、期限内なら前回の結果をそのまま返す。それだけの話だ。


古い技術が、ちゃんと効く

実装した対策は3つ。

1. フォロワーリストに24時間キャッシュ(効果: 最大)

前回の取得から24時間以内なら、APIを叩かずにキャッシュを使う。判定ロジックはシンプルだ。

優先度条件判定
1前回データなし or 空API取得
2前回取得から24時間超API取得
3最新のフォロワー数とキャッシュの件数が5件以上乖離API取得
4上記いずれにも該当しないキャッシュ使用

優先度3がポイントだ。プロフィール情報(meコマンド)で取得した最新のフォロワー数と、キャッシュに保存されているフォロワーIDリストの件数を比較する。フォロワーが急に増減した場合は、TTL内でもAPIを叩き直す。「24時間キャッシュだからフォロワーが100人増えても気づかない」ということは起きない。

「24時間」という値に深い根拠はない。フォロワーリストは1日に何度も確認するものではないから、1日1回の更新で十分だろう、という判断だ。厳密に計算して出した数値ではなく、まず入れてみて、問題があれば調整すればいい。キャッシュTTLは設計書で決めるものではなく、運用で育てるものだ。

2. エンゲージメント取得に6時間TTL(効果: 中)

こちらも同じ考え方だ。投稿してから30日以内のツイートのエンゲージメントを追跡しているが、数時間で劇的に変わることは少ない。6時間のTTLを設定して、その間は再取得をスキップする。

条件判定
エンゲージメント未取得取得
投稿から30日超スキップ(確定値)
前回取得から6時間以内スキップ
上記以外再取得

3. usage サブコマンドの追加(効果: 可視化)

python3 x-api-client.py usage --days 7

実行すると、日ごとのAPI使用量が棒グラフで表示される。

日次使用量(直近 7 日):
日付             件数  グラフ
------------------------------------------
2026-03-05        12  ######
2026-03-06         8  ####
2026-03-07        15  ########
2026-03-08         3  ##
2026-03-09         2  #
2026-03-10         1  #
2026-03-11         2  #
合計: 43 件(直近 7 日)

月次のリセット日、日ごとの消費トレンドが一目でわかる。見えないものは管理できない。 コストの可視化は、最適化の第一歩であり最後の砦でもある。

キャッシュを入れるときの注意

キャッシュは万能ではない。24時間の間にフォロワーが入れ替わっていても、キャッシュ内のデータは古いままだ。今回の用途——投稿支援ツールのフォロワー分析——ではこの程度のズレは許容できる。しかし、課金判定や認証に関わるデータに同じ設計を適用してはいけない。「このデータが古くても、何が困るか?」を考えてからTTLを決める。答えが「特に困らない」なら、キャッシュを入れていい。


9コールが2コールになった

改善前後の比較をまとめる。

指標改善前改善後
1回あたりのAPIコール約9回1〜2回(通常時)
フォロワー取得(日次)14〜21コール最大7コール
エンゲージメント取得(日次)実行回数 × 投稿数最大4回/日
月間推定(1日3回実行)約810コール約90コール

月810コールが90コールになった。約89%の削減。通常の実行——フォロワーリストのキャッシュが有効で、エンゲージメントのTTLも切れていない状態——では、APIコールは自分のプロフィール情報の取得(1コール)だけだ。

この変更はClaude Codeのサブエージェント機能を使って、シニアエンジニア役のAIにレビューさせた。2ラウンドのレビューでMedium指摘が2件出て、修正してGoをもらった。AIが書いたコードを、別のAIがレビューする。人間の仕事は「違和感に気づくこと」と「最終判断を下すこと」だ。


小さな違和感をスルーするな

クレジットの警告が出たとき、「まあ、追加課金すればいいか」と思うこともできた。月数百円の話だ。ビジネスインパクトは小さい。

でも、「計算が合わない」という違和感をスルーしなかったから、原因を30分で特定できた。キャッシュという古典的な手法で9割削減できた。

これはAPIコストの話だけではない。

「テストが1件だけ落ちてるけど、関係なさそうだから無視しよう」 「レスポンスが少し遅くなったけど、まあ許容範囲か」 「エラーログが増えてるけど、動いてるから大丈夫だろう」

こういう「まあいっか」の積み重ねが、コードの品質を静かに蝕む。小さな違和感をスルーする目は、大きなバグもスルーする。

AIにAPIを叩かせる時代だからこそ、コストの感覚は人間が持っていないといけない。AIは「このAPIコール、本当に必要ですか?」とは聞いてくれない。気前よく、正直に、愚直にAPIを叩く。それを監視し、最適化の判断を下すのは、人間の仕事だ。

もしあなたもAIツールを作っているなら、まず1つだけやってみてほしい。ツールが1回の実行で何回APIを叩いているか、数えてみろ。 想定より多かったら、そこにキャッシュの余地がある。

違和感を感じたら、立ち止まれ。30分の調査が、月のコストを9割減らすこともある。


関連記事