この記事のポイント
- ✓tool_useループは会話履歴が雪だるま式に積み上がり、トークン消費がO(n²)で増える。並列フェッチ+LLM呼び出し1回の構成に変えて、1回あたり実測$0.20→$0.019になった
- ✓日付フィルタのような機械的な仕事はプロンプトではなくコードでやる。LLMに任せるのは「編集」だけ、が一番安い
- ✓prompt cachingは検討の末に見送った。1日1回のバッチではTTL 5分のキャッシュが再利用されない——流行りの最適化ではなく、自分のワークロードの形で選ぶ
動いた後に来る問題——「で、いくらかかってるの?」
毎朝6:30に、その日のニュースをまとめたメールが届く。朝刊エージェントを3日で作った話の続きだ。
作る話はよく記事になる。でも個人開発のAIエージェントには、作った後にしか出会えない問題がある。それが「このメール1通、いくらかかってるのか」だ。
月額固定のサブスクと違って、LLM APIは従量課金。プロンプトをちょっと変えただけで、翌月の請求が倍になることも普通にありえる。逆に言えば、仕組みを1ヶ所変えるだけで請求が1/10になることもある。この記事は、それが実際に起きた記録だ。
先に効いた前提をひとつ。設計段階のADRで「LLM呼び出しごとにトークン数とコストを構造化ログに残す」と決めて、CloudWatch Logsに{ inputTokens, outputTokens, costUsd }を毎回出力していた。
測れないものは、削れない。
この後の改善はすべて「実測値があったから気づけた・効果を確認できた」もの。観測の仕込みはコスト最適化の前提条件だった。
最初の請求書——tool_useループの罠
初版のWebニュース収集は、Claude APIのtool_use(関数呼び出し)をループで回す構成だった。LLMに「このURL一覧から情報を集めて」と頼み、LLMが「次はこのページを取得して」とツールを呼び、結果を会話履歴に積んでまた考える。エージェントらしい、教科書どおりの作りだ。
実測コストは1回あたり約$0.20。当時は朝刊・夕刊の2便体制だったから、1日$0.40、月に換算すると約$12。個人の趣味ツールとしては「うーん」という金額だった。
ログを見て原因はすぐわかった。tool_useループでは、毎回のLLM呼び出しにそれまでの会話履歴がまるごと入力トークンとして再送される。取得したWebページ本文が履歴に積まれていくので、n回目の呼び出しの入力には1〜n-1回目の全取得結果が含まれる。
ツールループのトークン累積(イメージ)
各呼び出しの入力トークン量。履歴が再送されるため、呼び出し回数nに対して総トークン消費はO(n²)で膨らむ。
ツール呼び出しが10回あれば、総入力トークンはおおよそ二乗のオーダーで効いてくる。「賢いやり方」が「高いやり方」だったわけだ。
一手目: ループをやめて、LLMの仕事を「編集」に絞る
考えてみると、ニュース収集においてLLMが本当に必要な仕事はひとつしかない。集まった記事を読んで、重要なものを選び、要約すること。つまり「編集」だ。
どのURLを取得するかはトピック設定に書いてある。取得自体はただのHTTPリクエストだ。そこにLLMの判断はいらない。
そこでtool_useループを廃止し、こう変えた。
BEFORE
LLMがツールを呼びながら逐次収集。
取得のたびに履歴ごと再送。
LLM呼び出し: n回
AFTER
コードが全URLを並列HTTPフェッチ。
結果をまとめて1回だけLLMに渡す。
LLM呼び出し: 1回
あわせて、入力に載せるRSSの取得上限を半分に、max_tokensを8192→4096に絞った。出力トークンは入力の5倍の単価なので、出力の上限管理は地味に効く。
結果は実測で$0.20 → $0.019/回。約90%の削減だった。しかも収集はPromise.allの並列実行になったので、実行時間もむしろ短くなった。品質面でも、編集に専念させたほうが出力が安定した。
エージェント設計の問いは「LLMに何をさせるか」ではなく「LLMにしかできない仕事はどこか」。
自律的なツールループが必要な場面はもちろんある。ただ、収集対象が事前に決まっている定時バッチでは、ループは過剰だった。
二手目: 機械的な仕事はコードに引き取らせる
90%削減のあとも、ログを眺めていると細かい無駄が見えてくる。
たとえば記事の鮮度。当初は「2日以内の記事だけを選んでください」とプロンプトで指示していた。これはつまり、古い記事の本文まで律儀に入力トークンとして送りつけて、LLMに捨てさせていたということだ。日付の比較なんてコードの得意分野なのに。
RSSのパース段階で日付フィルタをコード側に移し、古い記事は入力に載せないようにした。配信済み記事の除外も同じで、URL正規化による突き合わせはコードでやり、LLMには判断が必要な分(続報の扱いなど)だけを残した。
もうひとつ効いたのがstructured outputs(JSONスキーマ強制)への置き換え。それまで「JSONで出力して」とお願いベースで生成させていた箇所は、たまにパースに失敗してリトライが走る。リトライは丸ごと追加コストだ。出力形式をAPIレベルで強制すれば、この再試行コストが消える。
プロンプトの指示は「入力トークンを払ったあと」に効く
「〜は無視して」「〜だけ選んで」という指示は、無視させる対象のトークン代を払った上での後処理になる。フィルタリングは可能な限り入力を作る前=コード側へ。LLMの入力に載った時点で、それはもう課金されている。
三手目: 計測の式そのものが間違っていた
これは少し恥ずかしい話。6月にコスト周りを総点検したとき、コスト計算式に入れていたモデル単価が間違っていたことに気づいた。
使っているHaiku 4.5の単価を「入力$0.8/出力$4(per 1Mトークン)」で計算していたが、これはひと世代前のHaiku 3.5の価格。正しくは入力$1/出力$5だった。つまりダッシュボード上のコストは、実際より2割ほど安く見えていた。
さらに、ニュースの鮮度を補強するために導入したweb_searchツールの課金も計上漏れしていた。web_searchは$10/1,000検索(=1検索$0.01)の固定料金で、トークン代とは別枠。しかも検索結果はモデルへの入力トークンとしても課金されるので、実際の負担は「$0.01+結果ぶんのトークン代」になる。1回の検索$0.01は、本体のLLM呼び出し$0.019の半分以上に相当する。「検索を何回まで許すか」は、このシステムの最大のコストレバーになる。
だから検索回数の上限はWEB_SEARCH_MAX_USESという設定値(デフォルト1回)としてコードの外に出した。コストに直結するパラメータは、プロンプトの中ではなく設定値として握っておく。これで「ちょっと検索を増やしてみる」が、料金影響を見積もれる変更になる。
コスト管理は「測る式が正しい」ことに依存する。
モデルの価格改定・新ツールの追加のたびに計算式の前提は崩れる。LLMの料金表を確認する習慣は、思った以上に大事だった。
prompt caching はなぜ見送ったか
LLMのコスト削減を調べると、必ず出てくるのがprompt cachingだ。プロンプトの共通部分(システムプロンプトや長い前置き)をキャッシュしておき、2回目以降の読み込みを約1/10の単価にする仕組み。うまくハマれば9割引きという、いかにも魅力的な機能である。
当然うちの朝刊にも入れたくなる。でも、検討した結果見送った。理由はキャッシュの2つの性質にある。
キャッシュの寿命は基本5分
キャッシュは最後に使われてから約5分で消える(延長オプションはあるが書き込み単価が上がる)。1日1回のバッチでは、今日書いたキャッシュを明日読むことはできない。
書き込みは通常より高い(1.25倍)
キャッシュへの書き込みには通常入力の1.25倍の料金がかかる。再利用されなければ、単に25%の割増を払っただけで終わる。
朝刊エージェントの実行は1日1回。1回の実行内でLLMを呼ぶのは数回で、しかも各呼び出しの入力の大部分はその日のニュース本文=毎回まったく違う内容だ。共通プレフィックスといえるシステムプロンプトは短い。キャッシュしても読み戻す機会がほぼなく、計算するまでもなく書き込み割増のほうが勝つ。
prompt cachingが輝くのは、長いシステムプロンプトや資料を短時間に何度も使い回すワークロード——チャットボット、対話型エージェント、同じ文書への連続質問など。1日1回・毎回入力が異なる定時バッチは、ちょうどその対極にいる。
「使える最適化」と「自分に効く最適化」は別物。
機能の説明ではなく、自分のワークロードのアクセスパターンから逆算する。導入しなかった判断も、検討の過程ごと記録しておけば次に活きる。
まとめ——個人開発LLMコスト最適化の3原則
現在の朝刊エージェントの運用コストは、1回あたり$0.02前後+web_search分。朝刊のみの月30回配信で、月額はおよそ$1弱。缶コーヒー1本分で、毎朝自分専用の新聞が届く計算になった。初版の構成のままなら月$12だったから、同じ機能を約1/10のコストで動かしていることになる。
ふりかえると、効いた打ち手は3つの原則に集約できる。
測れる状態を先に作る
呼び出しごとのトークン・コストを構造化ログに。実測がなければ、どの変更が効いたかは永遠にわからない。そして計算式の単価は定期的に料金表と突き合わせる。
LLMの仕事を「LLMにしかできないこと」に絞る
取得・フィルタ・突き合わせ・形式検証はコードへ。編集・要約・判断だけをLLMへ。ツールループが本当に必要かは、毎回疑っていい。
コストレバーを設定値として握る
max_tokens、検索回数の上限、入力に載せる件数。料金に直結するパラメータを設定値に出しておけば、機能追加のたびにコスト影響を見積もれる。
そしてコストを測れるようにした次は、品質を測れるようにする番だった。同じシステムに評価ハーネスを組み込んだ話は、別の記事に書いた。
本稿の数値について
コストはすべて自分の構成(Haiku 4.5・日本語ニュース・トピック5系統)での実測値ないし実測ベースの概算です。$0.20→$0.019は2026年4月時点の実測。モデル単価・web_search料金は2026年6月時点の公式料金表に基づきます。価格は変わるので、最新の料金表を必ず確認してください。
著者: しきぴょんた / 2026年6月