残高の画面を見て、そろそろだな、と思いました。裏で使っているAIのクレジットが、残り少なくなっていたのです。
あるスタートアップの情シスを兼ねていて、そこで動かしている業務ツールがいくつかあります。日次・月次でAIに要約や提案文を作らせるバッチ処理です。取引の要約を毎朝作るもの、月次でコストの削減案を出すもの、月次で数値集計とコメントを作るもの。全部が同じ提供元のAPIに乗っていました。クレジットが尽きれば、その日から全部止まります。
幸い、AIのベンダーはスタートアップ向けにクレジットを提供するプログラムを持っていることがあります。うちは複数のベンダーからそれを受けていて、別のクラウド側にはまだ残高がありました。つまり、尽きてから慌てるのではなく、尽きる前に移せる状況です。
問題は「じゃあ今から全部そっち向けに書き直すのか」ということでした。書き直したら、次にその移し先が同じように減ったとき、また同じ作業をやる羽目になります。
差し替えられる状態にする、という選択
やることを変えました。片方に移すのではなく、どちらでも動く形にして、既定を残高のあるほうにする。ここが一番の分かれ目でした。
AIに実際に頼んだ内容はこうです。
Azure OpenAIのモデルを使いたい。今使っているAPIのクレジットが残り少ないので、Azure側のクレジットで賄いたい。バックエンドのコードでは、これまでのAPIと両方切り替えられる仕様にしてほしい。UIで切り替えられるようにはなってなくていい。Azureにリソースが必要なら追加で作ってほしい。ツールごとに費用がわかるように、Azure OpenAIのリソースを分ける必要がある。
指示は3つに分けられます。両対応にすること、UIでの切り替えは要らないこと(設定ファイルで決めれば十分)、そしてツールごとに費用を分けて見えるようにすること。最後の一つは今回の本題ではないようで、実は一番効きました。
設計はこうなりました。
- 各ツールに切り替え用の設定値を1つ持たせる。既定値は残高のあるAzure側。設定自体が消えても、残りわずかなほうに戻らないようにするためです。
- Azure側の認証はキーを使わず、Azureのマネージドアイデンティティ(パスワードの代わりに、実行環境自体に権限を持たせる認証の仕組み)にしました。キーの管理や失効、漏えいの心配を1つ減らせます。
- Azure OpenAIのリソースをツールごとに分けて作りました。1つの窓口にまとめず分けたのは、後からコストを見たときに「どのツールがいくら使っているか」を素で追えるようにするためです。
ローカルで3つのツールを実際にAzure側で動かし、結果がちゃんとした中身で返ってくるのを確認してから、本番のジョブに設定を反映しました。3つとも手動で1回ずつ走らせて、すべて成功で終わるのを見届けました。
動作確認のその先の再点検
ここで終わっていたら、この記事は書いていません。動いた後にもう一段、厳しく見直しました。「動いた」と「壊れない」は別物だからです。
見つかったのは4つです。
1つ目は、コストツールの入り口にあった古い分岐でした。もともとのコードは「Anthropicのキーが正しく用意できたらAIの提案処理を動かす」という作りのままだったのです。切り替え先をAzureにしても、この古い判定はそのまま残っていました。つまりAnthropicのキーを完全に失効させた瞬間、Azureでは動くはずの削減案の生成が、エラーも出さずに黙って止まる状態でした。切り替えの本体は直したのに、呼び出す側が古い前提を握ったままだった、というやつです。判定をキーの有無ではなく、設定した提供元で分岐するように直しました。
2つ目は、型の話です。Claude APIは出力の型をこちらが指定した通りに強制してくれていました。Azure側の今回のモデルは、指示はできても強制まではしてくれません。結果、金額が「30,000」ではなく「¥30,000」という文字列で返ってくることがあり、それを数値として書式変換する処理がそこでエラーになって、削減案がまるごと消えていました。数値と難易度の表記ゆれを吸収する処理を足して直しました。
3つ目は、キャッシュの話です。月次レポートツールの一つは、AIが作ったコメントをファイルに保存して使い回します。ところがモデルが出力の枠を推論に使い切って空の応答を返すことがあり、その空の結果までキャッシュしていました。一度これが起きると、直す設定を入れ直すまで永久にコメントが出ない状態になります。空の応答は保存しない、に直しました。
4つ目は地味ですが実害があります。ツール別の費用を見るためのダッシュボードは、集計対象のリソース一覧を設定ファイルとしてDockerイメージに焼き込んでいました。新しく作ったAzure OpenAIのリソースをそこに登録し忘れると、費用は出るのに名前が生のリソース名のまま表示されます。「ツールごとに費用がわかるように」という最初の要望の核心部分が、ここだけ抜けていました。
どれも本番の3ジョブを再実行し、ログに出た実際の数字で確認しています。コストツールのログには「削減案 6 件を生成(合計 ¥15,610/月)」という行が出て、以前あったAnthropicのキーを読み込む行が消えていました。Claude側を経由せず、Azure側だけで最後まで通った証拠です。
差し替えられる、の中身
今回わかったのは、切り替え可能にするというのは、入口の分岐を1つ用意することではないということです。分岐の先にある呼び出し元、型の前提、キャッシュの挙動、集計側の設定まで、旧提供元前提のコードが他に残っていないかを全部洗う作業でした。入口だけ直して安心すると、一番弱いところで黙って止まります。
もう一つ、既定値をどちらにするかも軽視できません。今回は残高のあるほうを既定にしました。設定が消える、あるいは引き継がれないといった事故が起きたとき、残りわずかな側に戻るのではなく、動く側に転ぶようにするためです。どちらでも動く、を作ったら、次は「何も指定しなかったときどちらに転ぶか」まで決めておく必要があります。
使っているAIのAPIが使えなくなる場面自体は、避けられません。クレジットを使い切ることもあれば、規約が変わることも、値上げもあります。避けられるのは、そのときに自分たちの業務が止まるかどうかです。裏側のモデルを差し替えられる作りにしておけば、どちらが止まっても、その日のうちに動かし直せます。
そして今回いちばん効いたのは、切り替えを「尽きてから」ではなく「残りが見えた時点」で始めたことでした。止まってからでは、設計を考える時間ごと奪われます。
