AIに毎日仕事をさせるなら、予算の上限を必ず付ける|上限の決め方と切れたときに気づく方法

AIに毎日仕事をさせるなら、予算の上限を必ず付ける|上限の決め方と切れたときに気づく方法 AI導入の判断

AIに毎日仕事をさせるなら、1回あたりの利用料に上限を付けてください。付けないと、こちらが寝ている間に青天井で使われます。

ただし、この記事で本当に伝えたいのはその先です。

上限は「止める仕組み」であって、「知らせる仕組み」ではありません。

上限に当たってAIが仕事を途中でやめても、多くの場合、誰も気づきません。私は実際に気づけませんでした。上限の決め方と、切れたときに気づく作りを、うちで動いているスクリプトをそのまま出しながら書きます。


なぜ上限がいるのか|1回いくらか、事前には分からない

AIの利用料は「1回いくら」と決まっていません。読んだ資料の量、書いた文章の量、調べ直した回数で変わります。同じ指示を出しても、日によって金額が違います。

人が横で見ているなら、長引いた時点で止められます。問題は自動で動かすときです。うちは記事を書かせる処理を毎朝9時にmacOSのlaunchd(決まった時刻に処理を動かす仕組み)から呼んでいます。誰も見ていません。

指示の書き方をひとつ間違えて、AIが同じ調べ物を延々と繰り返す形になったとします。上限が無ければ、それは止まる理由がありません。気づくのは請求を見たときです。


上限の付け方|1行足すだけ

Claude Codeをスクリプトから呼ぶときは、--max-budget-usd に金額(ドル)を書きます。うちの記事作成スクリプト(~/scripts/media/1本作る.sh)は、この形で呼んでいます。

"$CLAUDE" -p \
  --permission-mode acceptEdits \
  --allowedTools "Read,Edit,Write,Glob,Grep,WebSearch,WebFetch" \
  --settings "$MEDIA_HOME/執筆時の権限.json" \
  --max-budget-usd "$BUDGET" \
  --no-session-persistence \
  "(ここに指示文)"

金額は決め打ちにせず、変数にしてあります。

# 記事1本あたりのAI利用上限(ドル)。環境変数で上書きできる
BUDGET="${MEDIA_BUDGET_USD:-10}"

${MEDIA_BUDGET_USD:-10} は「環境変数が指定されていればそれを使い、無ければ10」という書き方です。普段は10ドル、試すときだけ低くする、という使い分けができます。スクリプト本体を書き換えずに済むので、戻し忘れが起きません。


低すぎる上限は、高すぎる上限より厄介だった

ここからが本題です。上限を低くしておけば安全、ではありませんでした。

2026年8月26日、別に動かしている旅行メディア側の毎日の処理で、上限が10ドルから2ドルに戻ってしまっている状態のまま実行されました。そのときのログの1行目がこれです。

Error: Exceeded USD budget (2)

「2ドルの上限を超えました」。AIは記事を書いている途中で打ち切られました。ここまでは想定どおりです。問題はこの次でした。同じログの続きを、実物のまま貼ります。

毎日運転を開始: 2026-08-26 11:04:53
Error: Exceeded USD budget (2)検品OK
  WordPress: output/wordpress/(記事名).html
  note: output/note/(記事名).md
  管理データ: output/meta/(記事名).json
  記事候補の状態: 要確認
英語版検品OK
  ...
完了: (記事名)
投稿完了: 下書き
毎日運転を完了: 2026-08-26 11:14:29

読んでください。上限に当たったのに、そのあと検品が通り、「完了」と記録され、WordPressに下書きまで投稿されています。

このスクリプトの先頭には、失敗したら止まるための2行がちゃんと書いてあります。

set -eu
set -o pipefail

それでも止まりませんでした。予算切れは、スクリプトから見て「失敗」になっていなかったということです。エラー文は画面に出るのに、終了の合図としては伝わらない。だから後ろの工程が普通に動いてしまう。

上限を付けた安心感が、いちばん危ない。「止まったら気づくはず」は成り立ちません。

止まった位置によっては、書きかけの記事がそのまま公開の列に並びます。金額は守られたのに、成果物は壊れている。青天井より、この静かな失敗のほうが後始末は面倒でした。


上限はいくらにするか|推測で決めない

「相場はいくらですか」と聞かれても、答えられません。使い方で変わるからです。推測で決めずに、自分のところの実費を1回測ってください。

Claude Codeは --output-format json を付けると、結果と一緒に実費を返してきます。その中の total_cost_usd が今回かかった額(ドル)です。ターミナルにそのまま貼れます。

~/.local/bin/claude -p --output-format json "こんにちは、と1行だけ返して" \
  | ~/scripts/keiri/.venv/bin/python -c 'import json,sys; print(json.load(sys.stdin)["total_cost_usd"], "ドル")'

これで数字が1つ出ます。あとは本番と同じ仕事を数回やらせて、いちばん高かった回の2〜3倍を上限にするのが私の決め方です。理由は単純で、上限は「普段の費用」ではなく「異常を止める非常ブレーキ」だからです。普段の費用ぴったりに設定すると、少し重い日に毎回引っかかります。

そして実費は毎回記録します。うちの記事作成スクリプトは、AIが終わるたびに実費を読み取って、1行ずつ表に足しています。

COST_USD=$("$MEDIA_PY" -c "
import json,sys
try: print(json.load(open(sys.argv[1],encoding='utf-8')).get('total_cost_usd',0))
except Exception: print(0)
" "$LOG_DIR/生成_$STAMP.json")
COST_YEN=$(hiyou_kiroku "事務自動化ラボ" "記事作成" "$COST_USD")

失敗した回も記録します。途中で打ち切られても、そこまでの分は使っているからです。「失敗したから0円」という数え方をすると、月末に合わなくなります。

正直に書くと、うちはこの記録の仕組みを入れたばかりで、まだ実績が貯まっていません。だから「1本いくらでした」という数字はこの記事に書けません。書けるようになったら別記事にします。


上限は2段構えにする|1回分と、1か月分

--max-budget-usd が守るのは1回分だけです。1回10ドルでも、毎日動けば月に300ドルになります。1回の上限だけでは、月の総額は守れません。

そこでうちは、月の上限を別に持たせています(~/scripts/media/費用ガード.sh)。設定はこの3行だけです。

MEDIA_TSUKI_JOUGEN_YEN="${MEDIA_TSUKI_JOUGEN_YEN:-50000}"   # 月の上限(円)
MEDIA_DOLLAR_YEN="${MEDIA_DOLLAR_YEN:-150}"                 # 円換算レート(概算)
MEDIA_KEIKOKU_WARIAI="${MEDIA_KEIKOKU_WARIAI:-80}"          # 何%で警告を出すか

※ 月5万円は2026年8月26日時点のうちの設定値です。円換算は概算レートなので、実際の請求額とは一致しません。あくまで「使いすぎを止めるための目安」として持っています。

やっていることは2つだけです。

  1. 走る前に、今月いくら使ったか数える。今回の見込み額を足して上限を超えるなら、AIを呼ばずに終わる。
  2. 走ったあと、実費を1行書き足す。

記録の置き場所は、意図的に事務自動化ラボ側でも旅行メディア側でもない場所(~/.ai-shared/)にしてあります。2つの自動化が同じ財布を見るためです。別々に持つと、片方だけ見て「まだ余裕がある」と誤解します。

判定は、実行前にこう呼ぶだけです。

MIKOMI_YEN=$(awk -v u="$BUDGET" -v r="$MEDIA_DOLLAR_YEN" 'BEGIN{printf "%d", u*r}')
if ! YOSAN_MSG=$(yosan_check "$MIKOMI_YEN"); then
  # 上限を超えるので、AIを呼ばずに知らせて終わる
fi

切れたときに気づく作り方|3つ

上限そのものより、こちらのほうが大事です。順番に足せば、今日中に3つとも入ります。

1. 「終わったか」ではなく「増えたか」で判定する

終了コード(処理が終わるときに返す数字。0が成功)を信用しないことにしました。前の章のとおり、予算切れは0で返ってくることがあるからです。代わりに成果物を数えます。

BEFORE=$(find "$MEDIA_KIJI_DIR" -maxdepth 1 -type f -name '*.html' | sort)
# ここでAIに書かせる
AFTER=$(find "$MEDIA_KIJI_DIR" -maxdepth 1 -type f -name '*.html' | sort)

NEW=$(comm -13 <(print -r -- "$BEFORE") <(print -r -- "$AFTER") | head -1)
if [ -z "$NEW" ]; then
  echo "記事が作られませんでした。ログ: $LOG"
  exit 1
fi

ファイルが1本増えていなければ失敗。これなら、予算切れだろうが指示ミスだろうが、理由を問わず引っかかります。

2. 後始末まで終わったかを確かめる

記事が1本できていても、まだ安心できません。うちの場合、AIには記事のほかに3つの表の更新を頼んでいます。予算が切れると、記事は書けたが表の更新まで届かなかった、という中途半端な状態になります。だから最後に確かめます。

grep -q "^${FILE}	" "$MEDIA_LIST" || { echo "★ 記事一覧.tsv に行が足されていません"; NG=1; }
grep -qx "$FILE" "$JUNBAN"        || { echo "★ 公開順.txt に行が足されていません"; NG=1; }

ひとつでも欠けていたら、「後始末が終わっていません。上の★を人が直してください」と出して失敗で終わります。途中で力尽きた仕事を、完了として流さないためです。

3. 成功でも失敗でも、必ず1通知らせる

これが決め手でした。何も来ない日があってはいけません。「通知が来ない=うまくいっている」と思い込むと、止まっていることに気づけないからです。

うちは処理の途中でこけても必ず知らせるように、スクリプトの頭でこう仕掛けています。

trap shippai_wo_shiraseru EXIT

trap ... EXIT は「どんな終わり方をしても、最後にこの処理を通す」という指定です。途中で止まっても通知だけは必ず出ます。成功時の通知には、実費と今月の使用状況を必ず入れています。

今回の費用: 約◯◯円
今月のAI利用料: ◯◯円 / 上限 50000円(◯%)

毎日これを見ていれば、月末に驚くことはありません。「使いすぎていないか」を月1回調べる作業そのものが消えます。


上限をゼロにしたときに何が起きるか

ついでに書いておきます。月の上限が0円になった状態で走らせると、AIは呼ばれず、何も作られません。当然です。大事なのは、そのとき黙って終わらないことです。

うちのログには、この1行が残りました。

[2026-08-26 12:03] 予算のため見送り: 今月のAI利用料: 0円 / 上限 0円(0%)

同時に「今月は記事作成を止めました」という通知が出る作りにしてあります。止めたことを知らせない安全装置は、故障と見分けが付きません。止める仕組みを入れるときは、必ず「止めました」と言わせてください。


上限を下げるのは即決、上げるのは相談

最後に運用の決めごとをひとつ。うちではAIへの指示ファイルに、こう書いてあります。

上限を上げるときは人に相談する。下げる・止める方向は相談不要。

AI自身にスクリプトを触らせていると、「予算が足りないので上限を上げておきました」が起こり得ます。お金が増える方向の変更だけは、機械の判断で通さない。逆に下げるのは安全側なので、いつでも勝手にやってよいことにしています。

この非対称が効きます。判断に迷ったとき、機械は必ず安いほうへ倒れます。


まとめ

  • AIを自動で動かすなら、1回あたりの上限(--max-budget-usd)は必ず付ける
  • 金額は決め打ちにせず変数にする。試すときだけ下げて、戻し忘れを防ぐ
  • 上限は「止める仕組み」で「知らせる仕組み」ではない。上限に当たっても、後ろの工程がそのまま動いて「完了」と記録されることが実際にあった
  • 上限額は推測で決めない。--output-format json の total_cost_usd で実費を測り、いちばん高かった回の2〜3倍を非常ブレーキにする
  • 1回分の上限だけでは月の総額は守れない。月の上限を別に持ち、走る前に残りを確かめる
  • 気づくための3点セット … 成果物が増えたかで判定/後始末まで確認/成功でも失敗でも必ず通知
  • 止めたときは必ず「止めた」と知らせる。黙って止まる安全装置は故障と区別が付かない
  • 上限を上げるのは人の決裁、下げるのは即決。この非対称をルールにしておく

まずは --max-budget-usd の1行を足してください。そのうえで、今日の自動化から「今日は何もしませんでした」という通知が来るかどうかを確かめてみてください。来ないなら、止まっても気づけない状態です。

なお「上限に当たったのに完了と記録された」件は、終了コードの扱いという、もっと根の深い問題とつながっています。続きは 自動化が「成功」と嘘をつくとき|終了コードが当てにならない話 をどうぞ。

コメント

タイトルとURLをコピーしました