賢いことをしたつもりでした。AIパイプラインのために、コンテキストウィンドウのちょうど30%を思考予算(thinking budget)として確保するヘルパー関数を書いたのです。それはクリーンで予測可能であり、Opus 4.5では見事に動作していました。ところが、Opus 4.8に切り替えた途端、すべてのリクエストが400エラーで停止してしまったのです。私が丹念に作り上げたトークンの計算式は、一夜にしてゴミ同然になってしまいました。
以前のパターンは単純でした。budget_tokens の値を設定すれば、モデルはその上限内に収まるように思考を配分してくれました。もし128Kのコンテキストを渡せば、私のコードはおよそ38,000トークンを推論用に切り出し、残りを回答用に残すようになっていました。それは責任ある設計だと感じていました。車の速度制限を守るようなものです。
しかし、そのモデルはもう存在しません。Opus 4.7や4.8のような新しいリリースでは、「適応型思考(adaptive thinking)」が採用されています。もはや数値を指定するのではなく、代わりに「エフォート(effort)」の調整つまみを渡すことになります。これは単なる名称変更のように聞こえるかもしれませんが、この2つの制御方法は全くの別物です。budget_tokens はモデルが思考できる量にハードな上限を設けるものでした。一方、エフォートはモデルがそもそもどのように考え、どのように行動するかを制御します。前者はガソリンポンプのメーターであり、後者はエンジンマップなのです。
Effortを実際の業務にマッピングする
制御方法が変わったことで、私のこれまでの直感は通用しなくなりました。それぞれの設定が実際に何をもたらすのかを学び直す必要がありました。私は社内のトラフィックを用いてテストを行い、各エフォートレベルが実務においてどこに該当するかを突き止めました。
分類とルーティングには、ほぼ常に low エフォートを使用すべきです。これらのタスクは迅速な判断を要します。「これは返金リクエストか、それとも販売に関する質問か?」「このログエントリはエスカレーションが必要か?」といった内容です。長々と独白してもらう必要はありません。low エフォートにすることで、レイテンシを抑え、コストを極めて小さく保つことができます。
アプリケーションの主要なトラフィック、つまり要約、書き換え、サポートへの返信、コンテンツ抽出といった日常的な業務には、medium から high エフォートが適しています。ここがバランスの取れたポイントです。モデルは、長い思考の連鎖(chain of thought)を必要としないタスクにトークンを浪費することなく、実際の曖昧さを解消するために十分なスペースを確保できます。
コーディングとエージェント的なループには、xhigh エフォートが必要です。ここではミスが連鎖(compound)します。もしツール呼び出しのループの最初のターンでモデルが不適切な計画を立ててしまうと、続く3ステップはすべてそのダメージを修復するために費やされることになります。さらに悪いことに、間違ったツールを呼び出したり、パラメータをハルシネーション(幻覚)させたりして、ユーザーが壊れたワークフローを前に立ち尽くすことになりかねません。事前に優れた推論を行わせることで、こうした負のスパイラルを防ぐことができます。
クリティカルなタスクには max エフォートを割り当てるべきです。ただし、何にでもこれを使わないでください。誤った回答によるコストが、どんなトークン料金よりも高くつくような瞬間のために取っておいてください。財務照合、安全確認、アーキテクチャの決定、医療のトリアージなどがこれに当たります。もしエラーが発生した際に、人間が何時間もかけて混乱を解きほぐさなければならないような状況であれば、追加の思考にコストを支払う価値があります。
コストに関する意外な発見
ここで、私のメンタルモデルが崩れた部分があります。私は、エフォートを最大にすれば常にコストが膨れ上がると想定していました。単一のターンで見れば、その通りです。推論のトレースは長くなります。しかし、多段階のエージェントタスクにおいては、総額の請求額がむしろ下がることが多かったのです。
モデルは最初からより優れた計画を立てます。ツール呼び出しの回数も減ります。行き止まりの道に迷い込むこともなくなります。あるデータ抽出エージェントを観察していたところ、通常は5回のやり取りが必要なものが、わずか2回で完了しました。モデルが最初にスキーマを正しく解析するための十分な推論スペースを持っていたからです。コストを測定する際は、リクエスト単位ではなく、ジョブの完了単位で見てください。ステップあたりの思考予算を増やすことは、全体のステップ数を減らすことにつながるのです。
他の機能を壊さずに移行する方法
もし、まだコードベースのどこかに budget_tokens が残っているなら、以下の手順で確実に移行してください。ステップ3とステップ5は飛ばさないでください。私は飛ばしてしまい、デバッグに丸一日費やすことになりました。
コード内で budget_tokens を検索する。 すべての箇所を削除する必要があります。このパラメータは新しいモデルでは機能せず、400エラーを引き起こします。
budgetオブジェクトを適応型思考ブロックに置き換える。 thinking: { type: "adaptive" } を使用してください。
各呼び出しに対して、明示的なエフォートレベルを指定した output_config を追加する。 トラフィックが混在している場合、これをグローバルなデフォルト設定に任せてはいけません。軽量な分類エンドポイントが、誤ってコーディングエージェントと同じエフォート設定を継承してしまうようなことがあってはなりません。呼び出し箇所で明示的に指定してください。
budget計算用のヘルパー関数を削除する。 分かります。おそらくユニットテストも書かれているでしょう。私のコードもそうでした。しかし、それは今や不要な重荷です。プラットフォームはあなたのトークン計算を必要としていません。モデル自身が、自身のペースを管理するのです。
temperature、top_p、top_kを削除してください。 Opus 4.7および4.8では、これらのサンプリングパラメータを指定すると400エラーが発生します。この世代のモデルでは、プラットフォーム側でこれらが削除されました。以前のtemperature調整のテクニックはここでは通用しません。これらを残したままにすると、移行が気づかないうちに失敗することになります。
各モデルを個別にテストしてください。 Opus 4.5と4.8は全くの別物です。片方で動作する設定が、もう片方でも必ずしも動作するとは限りません。複数のバージョンをサポートする場合は、ロジックを分岐させるか、それぞれを個別のバックエンドとして扱ってください。
UIのフリーズを修正する
対処しないとユーザーを混乱させるストリーミング動作が1つあります。新しいモデルでは、thinking blocksがストリーム出力されますが、デフォルトではテキストは空の状態です。インターフェース上では、進捗が見えないまま、不自然に長い一時停止が発生しているように見えます。ユーザーはアプリがフリーズしたと判断するでしょう。
これを修正するには、thinking: { type: "adaptive", display: "summarized" } を渡してください。これにより、生の思考ストリームをチャットウィンドウにそのまま流し込むことなく、可視化された進捗インジケーターを表示できます。フロントエンドの応答性を維持しつつ、バックグラウンドで処理が進んでいることをユーザーに伝えることができます。
真の教訓
私は、ベンダーが永続させるつもりなどなかったパラメータの上に、抽象化レイヤー全体を構築してしまいました。プラットフォームよりもトレードオフを理解していると思い込み、独自のロジックで設定をラップしていました。しかし、実際にはそうではありませんでした。Adaptive thinkingの方が優れています。なぜなら、モデル自身が、いつ深く推論し、いつ省エネで進めてよいかを判断できるからです。私のコードベースは以前より小さくなり、結果はより鋭くなりました。時には、巧妙なコードを削除し、プラットフォームにその役割を任せることが、正しいエンジニアリングの判断となることがあります。
元の移行ノートを読みたい場合は、こちらから確認できます。このような実践的な議論をもっと行いたい場合は、TelegramのGyaanSetu AIコミュニティに参加してください。
