Claude Opus 5.5 の破壊的変更は4つ。当たっていたのは、一覧にない1つと、使っていないはずの1つでした

プラグインから Claude Opus 5.5 へのリクエストが 400 で返される様子を表したアイキャッチ AI
この記事は約13分で読めます。

400 になる作りでした。

自作の WordPress プラグイン Rapls AI Chatbot に、Claude Opus 5.5 を足そうとしたときの話です。
モデル一覧に1行足せば終わる、と思っていました。
破壊的変更の一覧も読んで、うちには関係ないと判断していました。

コードを開いて照合したら、2か所で当たっていました。
1つは temperature。もう1つは tool_choice。
公式の移行ガイドどおりなら、どちらも 400 エラーで返されます。

しかも、そのとき訪問者に見えるのは汎用のエラー文言だけでした。
1行足していたら、Opus 5.5 を選んだサイトのチャットは、理由の分からないエラーを出し続けていたはずです。

以下は、どこで読み違えたか、どう直したか、まだ何を確かめていないかの記録です。

9月22日 Opus 5.5 公開

Claude Opus 5.5 は 2026年9月22日に公開されました。
モデル ID は claude-opus-5-5。料金は入力 $4、出力 $20(100万トークンあたり)で、Opus 5 の $5 / $25 より下がっています。

公式の「What’s new」には、破壊的変更が4つ並んでいます。

破壊的変更 当時の自分の判断
思考(thinking)を切れない 切っていないので関係ない
強制ツール選択(tool_choice の any / tool)がエラーになる 使っていないので関係ない
思考ブロックがモデルと会話に紐づく 思考ブロックを履歴に戻していないので関係ない
旧 computer use ツールを受け付けない 使っていない

4つとも関係ない、という判断でした。
この表の2行目が、そもそも間違っていました。
そして、この表に載っていない変更が、もう1つ当たっていました。

あとで気づいたのですが、この一覧の前置きにはこう書かれています。
「Four breaking changes affect code already running on Claude Opus 5」
Opus 5 ですでに動いているコードに効く変更が4つ、という意味です。
一覧は Opus 5 からの差分でしかありません。うちのプラグインは、Opus 5 で動いたことが一度もありませんでした。

Claude の Opus 4.6 から Opus 5.5 までを左から並べ、temperature の拒否が Opus 4.7 から始まっていること、Opus 5.5 の破壊的変更の一覧が Opus 5 からの差分しか扱っていないこと、プラグインの一覧が Opus 4.6 で止まっていたことを示した図
一覧が扱っているのは右端の1区間だけでした。プラグインは左端に立ったまま、間の2つの変更を飛び越えようとしていました

9月24日 コードと照合する

一覧に Opus 5.5 を足す前に、Claude プロバイダのクラスを上から読みました。
最初に引っかかったのは、モデル一覧でした。

Opus 4.6 までしか入っていませんでした。
Opus 5 は6月に出ています。3か月以上、一覧に足していなかったことになります。
Claude にはモデル一覧を返す API がないので、新しいモデルは手で足すしかありません。その手作業が止まっていました。

次に、リクエストの本体です。変更前はこうなっていました。

temperature を、どのモデルにも常に送っています。既定値は 0.7 です。

Opus 5.5 の移行ガイドには、temperature・top_p・top_k は省くか既定値のままにすること、それ以外の値は拒否される、とあります。
しかもこれは Opus 5.5 で始まった話ではありません。Opus 4.7 以降のモデルは、既定値以外の temperature を 400 で返します。
Opus 5 の時点ですでにそうだったので、5.5 の破壊的変更の一覧には載っていない。筋は通っています。

今まで表に出なかったのは、一覧の最上位が Opus 4.6 だったからです。4.6 は temperature を受け付けます。
一覧を更新していなかったおかげで、踏まずに済んでいた。あまり誇れる理由ではありません。

もう1つが tool_choice でした。

ナレッジベースに関係する情報がないとき、Web 検索を強制する機能です。
自分で書いた機能なのに、「強制ツール選択は使っていない」と思い込んでいました。
any は、Opus 5.5 では 400 になる値そのものです。

ここで少し寄り道をします。
temperature を送っていたのはチャットだけではありませんでした。FAQ を自動生成する機能は 0.4 を渡しています。
チャットの設定画面で温度をいじらない人でも、FAQ 生成のほうで踏む。1か所直して終わりにしなくてよかった、と思います。

9月24日 訪問者に何が見えていたか

400 が返ったとき、訪問者の画面には何が出るのか。
手順を書いた段階では「Claude API parameter error」のような具体的な文言が出ると想定していました。
違いました。

訪問者に見えるのは、これだけです。

具体的なメッセージはエラーログにだけ残ります。管理者としてログインしていれば request_id が併記されますが、訪問者には何も分かりません。

同じ汎用の文言に埋もれていたものは、400 だけではありませんでした。

起きたこと API の返し方 変更前の画面
パラメータが不正 HTTP 400 汎用のエラー
モデルが回答を断った HTTP 200、stop_reason: "refusal" 本文が空なら汎用のエラー
思考だけで上限に達した HTTP 200、stop_reason: "max_tokens" 本文が空なので汎用のエラー
返答の途中で上限に達した HTTP 200、stop_reason: "max_tokens" 切れた文を、完成した答えとして表示

stop_reason を、コードのどこでも見ていませんでした。
本文が空なら、理由を問わず「Failed to get response from AI.」という例外を投げ、それが画面では汎用のエラーになる。
最後の行はもっと悪くて、途中で切れた文が何の断りもなく出ます。

連載の第2回で、4社のエラーの種別がばらばらだという話を書きました。
種別を揃えるところまでは考えていたのに、エラーにならない失敗は勘定に入っていなかった。拒否も途中切れも、HTTP としては 200 で返ってきます。

9月24日 直した5か所

直した内容を先に表にしておきます。

箇所 変更
モデル一覧 claude-opus-5-5 と claude-opus-5 を、通常の一覧と画像対応の一覧の両方に追加
temperature 受け付けるモデルにだけ送る(許可リスト)
tool_choice Opus 5.5 では any を送らず、システムプロンプトで検索を指示する
max_tokens 既定で思考するモデルでは 16000 まで引き上げる
stop_reason 拒否と途中切れを、汎用のエラーと分けて表示する

モデル一覧は2か所にあります。get_available_models() と get_vision_models() です。
後者に入れ忘れると、管理画面で「画像非対応」扱いになります。

temperature は、送るかどうかを判定する関数を足しました。

ここは少し迷いました。
拒否するモデルを列挙するか、受け付けるモデルを列挙するか。
拒否リストにすると、次に知らないモデルが出たとき、そのモデルには temperature を送ります。そして 400 になる。
許可リストなら、知らないモデルには送りません。新しいモデルは、古い世代より新しい世代の振る舞いに倣う可能性のほうが高いと考えて、許可リストにしました。

判定の結果は、たとえばこう分かれます。

モデル ID temperature を送る tool_choice を強制できる 既定で思考する
claude-opus-5-5 送らない できない する
claude-opus-5 送らない できる する
claude-opus-4-8 送らない できる しない
claude-opus-4-6 送る できる しない
claude-sonnet-4-6 送る できる しない
claude-haiku-4-5-20251001 送る できる しない

まだ存在しない ID を入れてみると、temperature は送らず、強制もせず、思考する側に倒れます。
間違えるなら、この向きで間違えてほしい。

tool_choice は、強制できないモデルでは指示文に置き換えました。

移行ガイドも、auto にしてプロンプトで「いつそのツールを使うか」を書け、と言っています。
ただ、これは強制ではありません。検索せずに答える可能性が残ります。
「Web 検索を強制する」という機能名のまま、Opus 5.5 だけは強制ではなくなりました。

max_tokens は、既定値の 1000 が問題でした。

1000 は返答の長さのつもりで決めた値でした。
でも Opus 5.5 は思考が常にオンで、max_tokens は思考と返答の合計にかかる上限です。
思考で 1000 を使い切れば、返答は1文字も書かれません。

上限を上げても、課金されるのは実際に生成した分だけです。
16000 にしたのは、このプラグインがストリーミングを使っていないからです。上限を大きくするほど、1回のリクエストで待つ時間が延びうる。共用サーバーで待てる時間には限りがあります。
ストリーミングを使わないと決めたのは別の理由からでしたが、その判断がここで上限の決め方に効いてきました。

最後が stop_reason です。
拒否は、本文を読む前に見ます。拒否のときに何か文字が返っていても、それは答えではないので。

上限に達したときは、本文があるかないかで分けました。

訪問者に見える文言は、こう変わりました。

状況 HTTP 訪問者に見える文言
拒否 422 Sorry, I can’t answer this question.
思考だけで上限に達し、返答なし 422 The answer could not be completed because it ran too long. Please try asking in a narrower way.
返答の途中で上限に達した 200 本文のあとに「(This answer was cut off because it was too long.)」
変更前は、パラメータの不正・回答の拒否・思考だけで上限・返答の途中切れの4つが、訪問者の画面では同じ汎用のエラー文言か切れた文になっていたこと、変更後はそれぞれ別の文言で表示されることを左右に並べた図
左が変更前、右が変更後。400 だけは右側でも汎用のエラーのままですが、そもそも 400 を出さない作りにしたので、ここには来ない想定です

422 にしたのは、チャットの JavaScript が自動で再試行するのが 409 と 429 だけだからです。
同じ質問を繰り返しても、拒否は拒否のまま返ってきます。再試行させても料金がかかるだけです。

拒否と途中切れは、管理画面の「プロバイダーのエラー」にも数えないことにしました。プロバイダーの障害ではないからです。
エラーログには、拒否の分類(stop_details.category)を残します。

入れなかったものも1つあります。
Anthropic は Opus 5 以降、拒否されたときに別のモデルで再試行するサーバー側の仕組みを勧めています。
入れると、使われるモデルと料金が、利用者の知らないところで変わります。このプラグインは利用者が自分の API キーで動かすものなので、見送りました。

直したあとの見直しで、もう2つ引っかかりました。
1つは応答キャッシュです。途中で切れた返答までキャッシュに入り、同じ質問をした次の訪問者にも、切れたまま返る作りになっていました。stop_reason が max_tokens の返答は登録しないように直しています。
もう1つは会話履歴です。「(This answer was cut off…)」という注記まで履歴に保存され、次のターンで Claude に送り直されていました。画面には注記付き、履歴には注記なしの本文、と分けました。

9月24日 当たらずに済んだ1か所

全部が外れていたわけではありません。
応答の読み取りは、最初から type で選んでいました。

思考するモデルでは、応答の content の先頭に thinking ブロックが来ることがあります。
$data['content'][0]['text'] のように位置で決め打ちしていたら、返答が空になっていました。
この部分は1行も変えていません。

9月25日 まだ確かめていないこと

ここまでのテストは、すべて WordPress の pre_http_request で通信を差し替えたものです。

テスト 項目数 結果
プロバイダ単体 37 すべて通過
チャット API 経由 5 すべて通過
キャッシュと会話履歴 5 すべて通過

Opus 4.6 へのリクエストが変更前と何も変わっていないこと(temperature 0.7、tool_choice any、max_tokens 1000)も、テストで押さえています。

ただ、リクエストの形が正しいことと、Opus 5.5 がそれを受け付けることは別の話です。
気になっているのは3つあります。
Web 検索ツールを Opus 5.5 がそのまま受け付けるか。
Web 検索をしたとき、最後の答えが text ブロックとして返ってくるか。
思考が長引いたとき、共用サーバーの実行時間の上限に先に当たらないか。

3つ目はとくに気がかりです。
タイムアウトしたとき訪問者に出る文言は「Could not reach the AI service. Please check your connection and try again.」です。思考が長すぎただけなのに、訪問者の回線のせいに見えます。
しかも、こちらが待つのをやめても、Anthropic 側では生成が最後まで続き、その分は課金されるようです。

Opus 5 と 5.5 の比較もしていません。effort の既定値は Opus 5 が high、Opus 5.5 が medium です。何も指定しなければ、違う条件で比べることになります。

このパッチはまだコミットしていません。
開発環境には、OpenAI と Gemini、互換 API のキーしか登録されていません。
Opus 5.5 への実際のリクエストは、まだ1回も送っていません。

AI
この記事を書いた人
rapls

WordPress のプラグインを作っているフリーランスエンジニア、Rapls です。Web 開発は6年以上。WordPress.org でプラグインを6本公開・保守しながら、日本語ロケールの翻訳エディター(PTE)も務めています。このブログには、現場で実際にハマって、調べて、直した話を書いています。

raplsをフォローする
raplsをフォローする

コメント

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