Skip to main content
舞台裏
舞台裏EngineeringDecisions

AI プロバイダーがモデルを廃止したとき

モデルの入れ替え、エラーなしで返ってくる空の応答、そして突然何倍にも膨らんだ請求額。何が壊れたのか、そしてなぜ原因がこれほど見えにくかったのか。

公開日 著者: AlphaCloud6 分で読めます

2026年7月、いくつもの機能が一斉に動かなくなりました。AI チャット、チケットでの AI 応答、チケットの要約、サーバービルダー、そしてアイデアとバグ報告のモデレーションと翻訳です。

原因は私たちのコードではありませんでした。私たちが使っていたモデルを、AI プロバイダーが廃止していたのです。

その1:モデルがなくなった

これは分かりやすい部分で、すぐに直りました。プロバイダーがモデルを終了したら、後継のモデルを指定すれば終わりです。

本当のインシデントは、その後に始まりました。

その2:エラーのない空の応答

入れ替えたあと、応答は返ってくるようになりました。ただし、ときどき空でした。途中で切れているのでも、形式が崩れているのでもなく、エラーが一切ない完全に空の応答です。

原因は、モデル名からは分からない違いにありました。後継モデルは推論モデルだったのです。実際の回答の前に、まず内部の思考過程を別のフィールドに書き出します。そして、その両方が同じトークン予算から消費されます。

思考で予算を使い切ってしまうと、形式上は問題のない応答が返ってきます。プロバイダーは「長さの上限に到達」と報告し、内容のフィールドは空です。エラーも手がかりもなく、try/catch で捕まえられるものは何もありません。

私たちは実際のテストで再現しました。予算を5トークンにするだけで、すべてのリクエストで空の応答が返ってきます。

その3:請求額

最も高くつく呼び出し箇所である AI サーバービルダーでは、長い回答を生成するため、予算を多めに設定していました。そのため、思考は上限にぶつからず、ただ延々と続きました。

その結果は、2つの方向から同時にやってきました。リクエストに時間がかかりすぎてタイムアウトになりました。そして、毎回目に見えない思考過程をまるごと支払っていたため、費用が何倍にもなりました。最後には、想定していなかったエラーメッセージが届きました。残高不足です。

修正は1行です。リクエストの本文で思考を無効にでき、そうするとモデルは再び以前のモデルのように振る舞います。それ以来、この1行はすべての呼び出し箇所に必須となっています。リポジトリの中には、そうした箇所が数えるほどどころではなくあります。

その4:片付けの中で見つかったもの

どうせすべての AI 呼び出し箇所に手を入れるなら、中身も見ることになります。そこで、インシデントとは無関係ながら、同じくらい高くつく2つ目のテーマが見つかりました。

プロバイダーは、冒頭部分が変わらずキャッシュから返せるプロンプトについて、料金をかなり安くしています。ヒットとミスの差はおよそ30倍です。

この割引はフラグでは得られません。私たちは具体的にテストしました。そのためにあるはずのリクエスト本文のフィールドはまったく効果がなく、キャッシュはいずれにせよ自動で適用されます。唯一の手段はプロンプト内の順序で、安定したものから変わりやすいものへと並べることです。

私たちがまさに逆のことをしていた箇所が4つありました:

固定の指示ブロックの中にある、変わりやすい値。 バグ報告の重複チェックでは、指示文の中にモジュール名が入っていました。そのため、それ以外は同一のブロックが、モジュールごとに別のキャッシュ行を持っていました。その値は、どうせ変わる可変部分に置くべきものです。

安定したものより前に置かれた新しいもの。 同じチェックが、新しいバグ報告を、最大50件の比較候補の前に送っていました。その結果、API で最大のプロンプトが常に完全なミスになっていました。

固定部分に入ったユーザーごとのデータ。 公開の AI チャットでは、個々のユーザーについてのメモが指示ブロックの中、つまり共有のチャンネル履歴の前にありました。そのため、同じチャンネルのユーザー一人ひとりが独自の冒頭部分を持つことになり、共有の履歴はユーザーごとに別々に支払われていました。

履歴に対するスライディングウィンドウ。 メッセージのたびに直近 N 件を送ると、すべてのメッセージで冒頭部分がずれます。そうなると履歴全体が常にミスになります。正しいやり方はブロック単位で削ること、つまり、まれに、まとめて削ることです。

さらに、細かすぎるように見えて実はそうではない点が1つあります。プロンプト内のリストを1つの基準だけで並べると、同順位のときに順序が入れ替わることがあります。指示ブロックの途中で1行入れ替わるだけで、その後ろのすべてのヒットが失われます。プロンプト内の並べ替えには、一意に決まる第2の基準が必要です。

そこから得たこと

モデルの入れ替えは設定変更ではない。 名前は変数の中の値のように見えます。その裏には違う振る舞いがあり、その振る舞いが壊したのはインターフェースではなく、私たちのコードでした。

危険な障害は静かなほうだった。 古いモデルがなくなったことはすぐに目に見え、数分で直りました。空の応答は形式上有効な応答として返ってきたので、いつまでもそのままになっていた可能性があります。

計測可能性は呼び出し箇所に置くべき。 現在は、すべての呼び出し箇所でキャッシュのヒット率を記録しています。正しく作られた箇所は最初のリクエストのあと高いヒット率に落ち着き、まずく作られた箇所は0のままです。どちらも動いているので、それが見えるのはログの1行の中だけです。

そして居心地の悪い結論: 他社のモデルを使うということは、製品の一部が、よそで下される判断に左右されるということです。だからこそ8月以降、どのサーバーも、私たちの環境に頼る代わりに、AI 機能を自分のエンドポイントに向けられるようにしています。

その他の記事