上原正吉(EarthLink Network Co., Ltd.)。Claude Codeを開発の主体に据え、20を超えるプロダクトを1人で同時に開発・運用しています。これは、その現場の実測記です。

2026年4月16日、SEO分析SaaS「AIO Helper」のAPIサーバーに、AI APIの月次利用額がサイトごとの上限(既定$50)を超える前に、処理を止める仕組みを入れました。見積額が残額を超える要求は、AIを呼ぶ前に止めます。利用額の記録は、AI呼び出しが成功した後です。各用語は本文の初出で説明します。
INSERTにまとめ、2つの処理へ分けない形にしました。ただし、同時実行時の厳密な上限保証は実際のPostgresで未確認です。また、見積もりを超えた実費や同時実行による超過は、事後の記録では止められません。対象は、AIO Helperという自社のSaaS(Software as a Service、インターネット経由で利用するソフトウェア)です。SEO(Search Engine Optimization、検索結果で見つけられやすくする最適化)の運用を支援します。Google Search Consoleなどからサイトのデータを取り込み、ページごとの改善案を出します。構成は、利用者が操作する管理画面と、処理を受け持つAPIサーバー(seo-api)の2つです。製品の全体像はAIO Helperの紹介記事にまとめています。
AI(Artificial Intelligence、学習済みモデルで推論や生成を行う技術)を使うのはAPIサーバー側で、2026年4月の時点で、文章を生成するAIを呼ぶ機能は次の3つでした。いずれも生成AIのAPI(Application Programming Interface、システム間で機能を呼び出す窓口)を呼びます。
POST /v1/page-goals/auto-generate)。ページのタイトルや本文から、狙うキーワード・ページの目的・想定読者を下書きします。POST /v1/suggest)。1ページ分の改善案を出します。POST /v1/suggest/batch)。クリック数の多いページから順に、まとめて提案を出します。このほかに、関連する文書を探すための検索用ベクトル(embedding、文章を数値の並びに変換したもの)を作る呼び出しがあります。提案の2機能が内部で使うものと、ベクトルを作り直すAPI(POST /v1/embeddings/rebuild)です。4月の仕組みは、これらを対象にしていません(後の「確認できていないこと」で説明します)。
使う人にとっては、分析が早く終わり、手作業で調べる時間が減るのが価値です。
ただし、AI APIは呼ぶたびに費用が増えます。利用者が増えたときだけでなく、バグで同じ処理を繰り返したときにも請求は増えます。管理画面に利用額を表示するだけでは、気づいた時点ではすでに費用が発生しています。
そこで、次の2つを作りました。

サイトごとの月次上限は、4月16日の時点ではAPI(PUT /v1/sites/:siteId/budget)で変更し、4月23日には管理画面に「AI Budget」タブも加えました。上限と利用記録はAPIサーバーのデータベースにあり、文章を生成するAIを呼ぶ3つの機能は、AIを呼ぶ直前に同じテーブルを見ます。
目的は、単に月$50で止めることではありません。どの機能がどれだけ費用を使ったかを追えるようにし、使い方を変えた後に本当に減ったかを確認することです。「止める」と「改善する」を同じ記録から行える状態を目指しました。
処理の順番は次のとおりです。

この順番で重要なのは、止める判断を「AI APIがエラーを返した後の後処理」にしないことです。外部へ送った後では費用を取り消せません。アプリの入口で止めることで、初めて上限が制御として機能します。
一方で、この記録は請求書の代わりではありません。アプリは自分が把握しているトークン数と価格表から見積もります。プロバイダ側の最終的な請求と完全に一致するとは限りません。アプリ内台帳は早く止めるための数字、請求書は最終的に支払う数字と役割を分けます。
発端はテスト監査でした。AIO Helperの管理画面には「今月のAI利用額」を表示するパネルがありましたが、上限を強制するテストは0件でした。利用額を計算できても、上限を超える前に止められなければ、従量課金の生成AIモデルを呼び続けてしまいます。
そこで最初にやったのは、料金計算とデータモデルの分離です。価格表は外部 API に問い合わせず、コードに静的に持つと決めました。理由は3つあります。
// ai-cost.ts — 未知モデルはわざと高く見積もる
const FALLBACK_PRICE = { input: 0.02, output: 0.08 };
// calcCost() は 6 桁に丸め、負値は 0 にクランプし、決して throw しない
// estimateCostFromBytes() は 3 bytes/token(英語 ~4・日本語 ~1.5-2 の中間)
// 出力は入力の 25% と仮定してプリフライト見積もりに使う
FALLBACK_PRICE を意図的に高く($0.02/$0.08 per 1K)したのがポイントです。新しいモデルを追加したのに価格表への登録を忘れると、コストが 0 と見なされて上限がすり抜けます。だから未知モデルは「高い」と扱うのが安全側です。
課金を止める本体は budget.ts に置きました。テーブルは2つです。
-- seo_site_budgets: サイトごとの月次上限(デフォルト $50)
-- monthly_usd_cap NUMERIC(10,2)
-- seo_ai_usage: 1コールごとの追記専用台帳
-- cost_usd NUMERIC(10,6), created_at timestamptz
金額をFLOATではなくNUMERICにしたのは、数百万回積み上がったときの丸め誤差を避けるためです。一番悩んだのは、同時に2つの要求が上限ぎりぎりに来た場合の制御でした。SELECT FOR UPDATEとトランザクションを使う案ではなく、上限確認を含む単一のINSERT文を選びました。
INSERT INTO seo_ai_usage (site_id, model, endpoint, input_tokens, output_tokens, cost_usd)
SELECT $1::text, $2::text, $3::text, $4::int, $5::int, $6::numeric
WHERE (
COALESCE((SELECT monthly_usd_cap FROM seo_site_budgets WHERE site_id = $1), $7::numeric)
- COALESCE((
SELECT SUM(cost_usd) FROM seo_ai_usage
WHERE site_id = $1
AND created_at >= date_trunc('month', NOW())
), 0)
) >= $6::numeric
RETURNING id;
$7は、サイトに予算行が無いときの既定上限($50)です。事前の残額確認はcheckBudget()が行い、不足なら上流の AI fetch を呼ばずに止めます(1ページ単位の2機能は HTTP 402 Payment Required を返します)。AI呼び出し成功後のrecordUsage()は、この INSERT が 0 行を返したら{ ok: false }を返します。この時点では費用がすでに発生しているため、要求は失敗にせず、警告ログを出します。台帳には記録されないので、その呼び出しの費用は全額が台帳から抜けます。台帳の利用額が増えないため、その後の上限確認にもこの費用は反映されません。cap = 0 は「1円も使わせない」停止設定として機能させました。
上限チェックを別のSELECT文にせず、INSERTのWHERE句へ相関サブクエリとして含めています。これにより、1つの文の中では集計と書き込みの間にアプリケーション側の別処理が入りません。
ただし、独立に確認できたのはこのSQLの構造までです。同時に始まった2つの文が必ず先行行を集計へ含めることは、実際のPostgresを使った競合テストで確認できていません。厳密な上限保証が必要なら、予算行のロック、直列化可能な分離レベル、またはアドバイザリーロックなどで、サイト単位の処理順を明示する必要があります。
この設計では、テスト環境にも問題がありました。テストはpg-mem(メモリ内で動くPostgres)で回していましたが、date_trunc('month', NOW())が未実装だったため、当時の記録では18件中12件が500で失敗しました。
12 out of 18 tests in integration-ai-cost-cap.test.ts failed
Only the 3 pure calcCost unit tests pass
記録の時点で通っていたのは、データベースへ触れないcalcCostの単体テストだけでした。500とは別の要因で失敗したテストもあり、記録に残っているのは、PUT budgetが入力検証の問題で400を返した件です。
当時のテスト記録では、db.public.registerFunction()でdate_truncを登録すると失敗は5件に減りました。残りはINSERT...SELECTの中で値の型を解決できない問題です。node-postgresは型を指定していない値を文字列として送るため、$1::textのように明示的な型変換を足して解消しています。
当時のテスト記録では、意図的に date_trunc の WHERE 句を壊す実験も行っています。18件中17件は月次の抽出条件が壊れても通り、「先月分は数えない」テストだけが失敗しました。前月の行を60日前の日付で追加し、集計されないことを確認するテストです。月次フィルタを誤って削除した場合、この1件しか検知できません。重要な条件を検証するテストが1件に集中していると分かりました。
上限で止めるだけでは、使う側には突然 402 が返り、なぜ止まったのか分かりません。そこで残額が 10% を切ったら警告フラグを立てる soft-warning を追加しました。
export const WARNING_REMAINING_PCT = 0.1;
function isNearLimit(cap: number, remaining: number): boolean {
if (cap <= 0) return false; // キルスイッチは「警告」ではない
return remaining / cap < WARNING_REMAINING_PCT;
}
cap <= 0を明示的に除外したのは、「利用を停止している」状態と「上限が近い」状態を別の通知として扱うためです。当時の実行記録では、失敗するテスト4件を先に書き、警告条件の実装後に240件のテストが通っています。変更はfeat: AI budget soft-warning flag at <10% remainingとしてコミットしました。

警告と停止を分けたことで、画面や通知の文言も分けられます。残額が少ないなら、利用者は処理量を減らすか、管理者へ上限変更を依頼できます。上限を0にした場合は、管理者が意図的に止めた状態です。同じ黄色い警告で見せると、利用者は「待てば戻る」と誤解します。
上限に達したことだけを通知しても、次に何を直すかは分かりません。運用で必要なのは、少なくとも次の5つです。
4月のseo_ai_usageは、このうち上の3つを出せる列(サイト・モデル・呼び出し先・トークン数・費用・日時)を持っています。日別の増え方や変更前後の比較を見る画面は、まだありません。それでも1回ごとの記録が残っていれば、後から集計して削減を「気分」ではなく数字で比べられます。
この記事を「同時実行でも絶対に予算を超えない完成版」とは書けません。理由は4つあります。
だから、この実装は終点ではなく、費用を制御対象として扱い始めた最初の段階です。後続の記事で、請求データとの照合、固定費の特定、変更後の再計測へ進みます。この順番を飛ばすと、削減効果を数字で説明できません。
この利用上限制御と台帳は、5月以降のコスト改善で使う計測・上限・記録の原形になりました。翌月にはCost Explorerが $0 を返す問題を調べ、その後「測定→修正→再測定」を記録に残す運用へ進みます。その考え方は、この4月にすでにありました。
一方、この仕組みが対象にするのはAIO HelperのAI API利用額です。Elastic Container Serviceの常時起動やNAT(Network Address Translation、内部ネットワークから外部への通信を中継する仕組み) Gatewayの固定費など、クラウド全体の請求は止められません。アプリケーションの外で発生する費用には、Cost Explorerや予算監視を別に用意する必要があります。
cap = 0(止まっている)を「もうすぐ」警告に混ぜません。このクラウドコストとの戦いについての記事は、帰属・実測・構造ガード・定点観測の方法論を、順次シリーズとして公開していきます。 興味のある方は、ぜひ「いいね」と記事の購読をお願いいたします。
この方法論をもとにしたコスト管理サービス Costwary を https://costwary.com で提供しています。 そのほかの自社プロダクトは https://www.eln.ne.jp/products にまとめています。
上原正吉。EarthLink Network Co., Ltd. でAI開発をしています。2025年からClaude Codeを開発の主体に据え、今は20を超えるプロダクトを1人で同時に開発・運用しています。この連載では、その現場で実際に起きたこと(うまくいったことも、失敗も)を、数字と一緒に書いていきます。
また、AIで業務や開発を組み替えたい会社・チーム向けに、AI活用のコンサルティングも受け付けています。ご相談は www.eln.ne.jp からどうぞ。
EarthLink Network は、会社の全業務を AI で回すために、必要になったものを自社で作っています。いま作っているプロダクトの一覧と概要は、こちらにまとめています。
→ EarthLink Network が自社でつくっている18のプロダクト
会社と各プロダクトの詳細は、公式サイト www.eln.ne.jp をご覧ください。