◉CLAUDE LABEN
●2.1.292 — Claude Code 2.1.292(10月6日)。cloud session が許可プロンプトへの回答を落とす不具合と、終了時に直近メッセージが失われる不具合を直しました●MODELS API — thinking を無効にできるモデルかどうかを、Models API の capabilities で確認できるようになりました(10月)●11/30 — Sonnet 4.5 の Claude API 提供終了まで残り54日。移行先は Sonnet 5.5 で、呼び出し側の確認点は thinking の指定と tool_choice です●MODS — Claude Code の Mods をどう安全に入れるか、という手順の記事が Zenn に出ています。論点は導入前に確認する項目と戻し方です●NEW — Pro を払ったのに無料のままに見えるとき、買った場所が Web かストアかで見る画面が変わります。その切り分けをまとめました●THINKING — Sonnet 5.5 の thinking ブロックは、作ったアカウントでしか使えません。別のアカウントから送ると黙って落とされます●2.1.292 — Claude Code 2.1.292(10月6日)。cloud session が許可プロンプトへの回答を落とす不具合と、終了時に直近メッセージが失われる不具合を直しました●MODELS API — thinking を無効にできるモデルかどうかを、Models API の capabilities で確認できるようになりました(10月)●11/30 — Sonnet 4.5 の Claude API 提供終了まで残り54日。移行先は Sonnet 5.5 で、呼び出し側の確認点は thinking の指定と tool_choice です●MODS — Claude Code の Mods をどう安全に入れるか、という手順の記事が Zenn に出ています。論点は導入前に確認する項目と戻し方です●NEW — Pro を払ったのに無料のままに見えるとき、買った場所が Web かストアかで見る画面が変わります。その切り分けをまとめました●THINKING — Sonnet 5.5 の thinking ブロックは、作ったアカウントでしか使えません。別のアカウントから送ると黙って落とされます
記事一覧/API & SDK
⬡ API & SDK/2026-10-07中級

モデルを切り替える前に、自分の呼び出しの形を候補モデルへ1トークンで再生する

モデルIDを書き換えて本番を回すと、400 は最初のリクエストで返ります。thinking の指定や tool_choice など自分の呼び出しの形を、max_tokens 16 の再生で先に確かめる小さな仕組みを書きました。

Claude API125モデル移行3Models APIプリフライト設計6

モデルIDの文字列を1行書き換えて、スクリプトを走らせた夜がありました。

返ってきたのは 400 でした。メッセージを読むと、モデルが悪いのではなく、私の呼び出しの側に残っていた指定がひとつ、新しいモデルの受け付ける形から外れていたのです。直すこと自体は数分で済みました。胃のあたりが重くなったのは、そのリクエストが「本番で最初に走る1通」だったからです。

そのときから、切り替えの前に 自分の呼び出しの形を、候補モデルへ先に再生しておく ことを習慣にしました。大がかりな評価基盤ではありません。1トークンに近い小さなリクエストを数本流すだけです。

切り替えで壊れるのは、モデルの性能ではなく呼び出しの形です

モデルを替えるとき、私たちはつい出力の品質を気にします。精度は落ちないか、費用はどうか、と。もちろん大事です。

ただ、品質を比べる段階に進む前に、リクエストそのものが受け付けられるかどうかという入口があります。ここで引っかかると、品質の比較どころではありません。

入口で止まる原因は、だいたい次の三つに収まります。

原因手元のコードでの見え方気づくタイミング
パラメータの形が合わないthinking の指定、temperature など、以前から付けていた引数最初のリクエストで 400
組み合わせが合わないtool_choice で特定のツールを強制しつつ別の機能を併用している特定の経路を通ったときだけ 400
能力の有無が違う前のモデルでは使えた機能が、候補では使えない機能を使う画面・バッチに到達したとき

二つ目と三つ目が厄介です。普段通らない経路で起きるので、動作確認を1回通しただけでは見つかりません。

公式の移行ガイドは「地図」で、自分の呼び出しは「現在地」です

移行ガイドには、モデルごとに変わった点が整理されています。ありがたい資料です。けれど、ガイドが挙げる変更点のうち、自分のコードが 実際にどれを踏んでいるか は、ガイドからは分かりません。

私は読み合わせの作業を、次の順に分けるようになりました。

  1. 自分のコードが発行している呼び出しの「形」を、一覧にして書き出します
  2. その形を、そのまま候補モデルへ送って受理されるかを確かめます
  3. 受理されなかった形についてだけ、ガイドを読んで直します

ガイドを頭から読んで全項目を照合するより、はるかに短く済みます。照合の対象が、自分の呼び出しだけに絞れるからです。

呼び出しの形を1ファイルに書き出す

最初にやるのは、棚卸しです。自分のコードが発行している呼び出しを、引数の組み合わせごとに1行ずつ書き出します。

# call_shapes.py
# 本番コードが実際に発行している呼び出しの「形」を、1か所に集めたもの。
# モデルIDは入れない(候補モデルは再生時に差し込む)。
# max_tokens は受理判定のためだけなので、ごく小さくしておく。
 
DUMMY_TOOL = {
    "name": "ping",
    "description": "疎通確認用のダミーツール",
    "input_schema": {"type": "object", "properties": {}},
}
 
SHAPES = {
    # 一番ふつうの呼び出し
    "plain": {
        "max_tokens": 16,
        "messages": [{"role": "user", "content": "ok と返してください"}],
    },
    # 思考を明示的に切る呼び出し(自分のコードに同じ指定がある場合だけ残す)
    "thinking_disabled": {
        "max_tokens": 16,
        "thinking": {"type": "disabled"},
        "messages": [{"role": "user", "content": "ok と返してください"}],
    },
    # ツールを必ず使わせる呼び出し
    "tool_choice_any": {
        "max_tokens": 16,
        "tools": [DUMMY_TOOL],
        "tool_choice": {"type": "any"},
        "messages": [{"role": "user", "content": "ping を呼んでください"}],
    },
    # システムプロンプト付き(長さはダミーでよい)
    "system_prompt": {
        "max_tokens": 16,
        "system": "あなたは疎通確認用のアシスタントです。",
        "messages": [{"role": "user", "content": "ok と返してください"}],
    },
}

ポイントは、自分のコードに存在しない形は入れない ことです。使っていない引数まで網羅しようとすると、一覧が膨らんで、読み合わせの意味が薄れます。逆に、月に1回しか通らないバッチの呼び出しは、必ず入れます。普段通らない経路こそ、再生で拾いたいからです。

候補モデルへ再生して、受理・拒否・不明に分ける

次が再生の本体です。依存を増やしたくないので、SDK ではなく素の HTTP で書きました。

# replay.py
import json
import os
import sys
 
import httpx
 
from call_shapes import SHAPES
 
BASE = "https://api.anthropic.com/v1"
HEADERS = {
    "x-api-key": os.environ["ANTHROPIC_API_KEY"],
    "anthropic-version": "2023-06-01",
    "content-type": "application/json",
}
 
 
def replay(model: str) -> dict:
    """各 shape を max_tokens 16 で候補モデルに送り、受理されたかを返す。"""
    results = {}
    with httpx.Client(timeout=30) as client:
        for name, body in SHAPES.items():
            r = client.post(f"{BASE}/messages", headers=HEADERS,
                            json={"model": model, **body})
            if r.status_code == 200:
                results[name] = {"verdict": "accepted"}
            elif r.status_code == 400:
                # 形が受け付けられなかった。理由文をそのまま残す
                msg = r.json().get("error", {}).get("message", "")
                results[name] = {"verdict": "rejected", "reason": msg[:300]}
            else:
                # 429・529・5xx は形の問題ではないので「不明」に回す
                results[name] = {"verdict": "unknown", "status": r.status_code}
    return results
 
 
if __name__ == "__main__":
    model = sys.argv[1]
    out = replay(model)
    print(json.dumps(out, ensure_ascii=False, indent=2))
    # 1つでも rejected があれば、切り替えは止める(終了コード 1)
    sys.exit(1 if any(v["verdict"] == "rejected" for v in out.values()) else 0)

判定を「受理・拒否・不明」の三つに分けたのには理由があります。過負荷の 529 や、レート制限の 429 を「拒否」に数えてしまうと、混雑した日に切り替えが理由なく止まります。形の問題は 400 だけ、と決めておくと、判定がぶれません。

実行は、切り替え候補のIDを引数に渡すだけです。

python replay.py <候補モデルのID>
echo $?   # 0 なら全 shape が受理、1 なら拒否あり

拒否が出たら、reason に入っている理由文を読みます。そこで初めて移行ガイドを開き、該当の箇所だけを直します。

Models API の能力情報は「先に見る」ための近道にします

1通ごとに実際のリクエストを送るのは確実ですが、少し粗いやり方でもあります。10月7日の更新で、Models API の応答に、thinking の無効化(disabled)を受け付けるかどうかを示す能力情報が加わったと、リリースノートで読みました。

私は、これを「再生の前に走らせる早見表」として使うつもりでいます。ただし、応答の細かい形は版によって変わりうるので、決め打ちでは読みません。

# capabilities.py
import httpx
 
from replay import BASE, HEADERS
 
 
def thinking_disabled_supported(model: str):
    """True / False / None(情報なし)のどれかを返す。"""
    r = httpx.get(f"{BASE}/models/{model}", headers=HEADERS, timeout=30)
    if r.status_code != 200:
        return None
    node = r.json().get("capabilities", {})
    for key in ("thinking", "types", "disabled"):
        if not isinstance(node, dict) or key not in node:
            return None          # 見つからなければ「不明」にして、再生に任せる
        node = node[key]
    if isinstance(node, bool):
        return node
    if isinstance(node, dict) and "supported" in node:
        return bool(node["supported"])
    return None

None を返す道を最初から用意しているのが肝心です。能力情報が見つからないときは、「できない」と読むのではなく「不明」と読み、再生に判断を預けます。能力情報は先に見る近道、再生は最後の確認 — この二段にしておくと、どちらかが古くなっても事故になりません。

切り替えの手順は、4行で済ませています

自分の運用では、次の流れに落ち着いています。

  1. capabilities.py で能力情報を引き、False が出たら、その shape を使う箇所を先に直します
  2. replay.py を候補モデルで走らせます(所要は数秒、費用はほぼ無視できる程度です)
  3. 終了コードが 0 になってから、本番のモデルIDを書き換えます
  4. 書き換えの直後に、もう一度 replay.py を本番の設定で走らせます

最後の4番目は、地味ですが効きます。書き換えのミスや、環境変数の食い違いは、事前の検証では見えないからです。

再生でも拾えないものがあります

誤解のないように、限界も書いておきます。この再生が確かめるのは リクエストが受理されるか だけです。

出力の品質、費用の変化、応答の癖の違いは、別の確認になります。受理されたから安全、とはなりません。再生は「入口で転ばないための確認」であって、移行の完了を保証するものではないのです。

それでも、入口で転ぶ回数が減ると、品質の確認に使える気力が残ります。眠れない夜に本番のログを睨む時間を、少しでも短くしたい——私がこの小さな仕組みを置いている理由は、そこにあります。

切り替えるのは、モデルより先に自分の呼び出しです。 順番をこの一文に決めてから、本番で 400 を最初に見ることはなくなりました。いま思えば、あの夜の重さは、順番を決めていなかったことへの手応えだったのかもしれません。

次の一歩として、今日のうちに SHAPES へ、自分のコードで実際に使っている呼び出しを3本だけ書き出してみていただければと思います。3本あれば、再生は動き出します。

シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥2,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

⬡ API & SDK2026-09-28
Claude が 529 を返した夜、頼みのフォールバック先まで落ちました — cache_control は境界で剥がす
Claude API のフォールバック先で TypeError が出た原因は、cache_control 付きの content block をそのまま他社モデルへ渡していたことでした。境界で剥がす関数と送る直前の検問、そして発火する前にフォールバック経路を試す運用を書き残します。
⬡ API & SDK2026-09-17
画像は20枚ずつ送っています — 21枚目から全画像に別の上限がかかると知った日
素材フォルダの62枚を一度に送ったら invalid_request_error で落ちました。容量ではなく枚数が原因です。視覚トークンを28pxのパッチで数え直し、枚数・寸法・ペイロードの3つの上限を同時に見てバッチを組むまでの記録です。
⬡ API & SDK2026-09-06
訳文は自然なのに、実行時に落ちる翻訳がありました
多言語アプリの文言を Claude API で訳したとき、意味は正しいのに書式指定子だけが壊れることがあります。重大度で分けた受け入れ検査と、壊れた行だけを訳し直す修復ループを実装と実測でまとめました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます