一覧に戻る
    Claude APIモデルの世代交代と、エイリアス設計が効いた2回目の移行
    AI開発
    PRこの記事には広告が含まれています

    Claude APIモデルの世代交代と、エイリアス設計が効いた2回目の移行

    15 分で読める

    LLMを組み込んだプロダクトを運用していると、避けて通れない問題があります。

    モデルの世代交代にどう追従するか、という問題です。

    新しいモデルが出るたびに、コードベースのあちこちに散らばったモデルIDを書き換えて、テストを直して、ドキュメントを更新して……。手作業でやると地味にしんどいし、漏れも怖い。

    今回は、自分が開発しているワークフローエンジンで Claude のモデルを一斉に上げた話を書きます。前回の記事(OpenAI Codex モデルの移行記録)の翌日にやった作業で、同じ設計が2回目でどう効いたか——という続きの話でもあります。

    前提:何を作っていて、なぜ Claude を使っているのか

    まず背景から。

    自分は ai-workflow-agent というワークフローエンジンを開発しています。GitHub Issue の内容をもとに、計画→設計→実装→テスト→ドキュメントまでを自動で回すツールです。

    内部では OpenAI の Codex モデルと Claude を使い分けています。コード生成は Codex、要件整理やレビューは Claude、という棲み分けです。それぞれのモデルを --codex-model max--claude-model opus のようにエイリアスで指定できるようにしていて、実際のモデルIDへの解決はコードの1箇所が引き受けます。

    // Claude 側のエイリアス定義(移行前)
    export const CLAUDE_MODEL_ALIASES: Record<string, string> = {
      opus: 'claude-opus-4-5-20251101',    // 最上位、複雑なタスク向け
      sonnet: 'claude-sonnet-4-20250514',  // バランス型
      haiku: 'claude-haiku-3-5-20241022',  // 軽量、コスト効率重視
    };

    このエイリアスシステムは、以前のモデル移行(gpt-5-codexgpt-5.1-codex-max)のときに「また同じ作業が発生するな」と感じて導入したものです。利用者はエイリアス(opus, sonnet, haiku)を使い、モデルIDの変更はこの定数だけで完結する——という設計にしています。

    前回、Codex 側を gpt-5.2-codex に上げたのが2月8日。その翌日に Claude 側も上げることにしました。

    なぜ上げるのか:Claude 4.5ファミリーの登場

    Anthropic から Claude のモデルラインナップが更新されました。

    • Claude Opus 4.6 — 最上位モデル(Opus 4.5 の後継)
    • Claude Sonnet 4.5 — バランス型(Sonnet 4 の後継)
    • Claude Haiku 4.5 — 軽量・高速(Haiku 3.5 の後継)

    モデルを上げるかどうかの判断で、まず気になったのはコストです。

    Opus 4.5 → Opus 4.6: Input $5 / Output $25 → 変更なし

    Sonnet 4 → Sonnet 4.5: Input $3 / Output $15 → 変更なし

    Haiku 3.5 → Haiku 4.5: Input $0.80 → $1 / Output $4 → $5(約25%値上がり)

    Opus と Sonnet はコスト据え置き。Haiku だけ若干の値上がりがありますが、Haiku 4.5 は Sonnet 4 と同等レベルの性能をSonnet の1/3の価格で使えるとされているので、十分にペイします。

    前回の Codex 移行では「5.2 系の軽量モデルがまだ公式に出ていない」という理由で mini を据え置きにしましたが、Claude 側は全モデル出揃っていたので迷いなく3モデルとも上げる方針に。

    フルIDか、エイリアスか——途中で方針を変えた

    ここからが実作業です。Claude Code(Sonnet 4.5)を使って進めました。

    最初に Claude Code に伝えた指示はこうです。

    claude-opus-4-5-20251101 → claude-opus-4-6
    claude-sonnet-4-20250514 → claude-sonnet-4-5-20250929
    claude-haiku-3-5-20241022 → claude-haiku-4-5-20251001

    日付つきのフルモデルIDで指定しました。前回の Codex 移行でもフルIDを使っていたので、同じノリで。

    ただ、ここで手を止めました。

    Claude Code が影響範囲を検索して、ファイルを読み込んで、さあ置換——というところで、自分でキャンセルしました。

    理由は、「Sonnet と Haiku はエイリアスでよくないか?」と思い直したからです。

    Anthropic の公式でも claude-sonnet-4-5claude-haiku-4-5 のようなエイリアス形式での指定が案内されています。エイリアスは常にそのモデルファミリーの最新スナップショットを指すので、将来的なマイナーアップデートにも自動で追従してくれる。

    つまり、自分たちのコード内でやっていること(sonnet → 実際のモデルID)と同じことを、API プロバイダ側もやっている。ならば、その恩恵を受けない手はない。

    方針を切り替えました。

    claude-opus-4-6      ← エイリアス形式(これ自体が最新を指す)
    claude-sonnet-4-5    ← 日付なしエイリアス
    claude-haiku-4-5     ← 日付なしエイリアス

    ただし、これは「常に最新のモデルで最良の結果を出す」ことを優先するうちのプロダクトだから成り立つ判断です。生成結果の厳密な再現性が求められる場面では、日付つきのフルID(claude-sonnet-4-5-20250929)で固定するのが正解。どの層で固定するかは、プロダクトの要件次第です。

    結果として、エイリアスが2層になりました。アプリ内エイリアス(sonnet)→ API エイリアス(claude-sonnet-4-5)→ 実際のスナップショット。この構造は前回の Codex 移行時には意識していなかったもので、Claude 側をやってみて初めて気づいた視点です。

    影響範囲と、古いモデルIDの負債

    方針が決まったので、改めて置換を実行。影響範囲はこうでした。

    ソースコード(5ファイル):

    • エイリアス定義(本丸)
    • 型定義のコメント
    • ContentParser のデフォルトモデル
    • 認証検証用モデル
    • フォローアップ Issue 生成用モデル(2箇所)

    テストファイル(4ファイル)、ドキュメント(4ファイル)

    合計13ファイル、63行の変更。

    ここで気づいたのが、Claude 側には「レガシーモデル」が複数世代にわたって残っていたということです。

    Codex 側は gpt-5.1-codex-max の1種類を置き換えるだけでした。でも Claude 側は、開発初期に「とりあえず動くモデル」として指定された古い世代のIDが場所によってバラバラに残っていた。claude-3-sonnet-20240229 がフォローアップ Issue 生成に、claude-3-5-sonnet-20241022 が ContentParser のデフォルトに——という具合です。

    エイリアスシステムを導入する前に書かれたコードが、そのまま残っていたんですね。今回の移行で、これらも含めて claude-sonnet-4-5 に統一できたのは、地味ですが衛生面で大きい収穫でした。

    テストは全件パス——前回の教訓が効いた

    置換が終わったら npm test を実行。結果は全件パス。

    前回の Codex 移行では、ホワイトスペース付きエイリアスのテストケースが漏れて18件失敗する、というヒヤリがありました。今回は Claude Code がその類のテストも含めて更新してくれた——のですが、それは「たまたま」ではなく、自分が事前に「テストファイルの期待値も全部更新して」と明示的に伝えたからです。

    // 大文字・小文字の混在テスト
    expect(resolveClaudeModel('Opus')).toBe('claude-opus-4-6');
    expect(resolveClaudeModel('SoNnEt')).toBe('claude-sonnet-4-5');
    
    // ホワイトスペース付きテスト
    expect(resolveClaudeModel('  opus  ')).toBe('claude-opus-4-6');
    expect(resolveClaudeModel('\tsonnet\t')).toBe('claude-sonnet-4-5');

    前回つまずいたからこそ、「エイリアス名ではなく、解決後のモデル名でも検索しないと漏れる」という勘所が自分の中にありました。ツールが賢くなっても、過去の失敗から得た経験則は人間が持っておくべきものだと改めて思います。

    動作確認

    コミット後、実際にワークフローを回して動作確認。

    2026-02-10 03:44:00 [INFO ] Using model override for Claude Agent: claude-opus-4-6 (phase=requirements)
    2026-02-10 03:44:02 [INFO ] [AGENT SYSTEM] init
    2026-02-10 03:44:05 [INFO ] [AGENT THINKING] I'll start by exploring the codebase...

    Opus 4.6 が正しく認識されて、エージェントが正常に起動。問題なし。

    2回の移行を通して見えたこと

    Codex の移行と Claude の移行を2日連続でやって見えたのは、エイリアスシステムの設計は「2回目」で真価を発揮するということです。

    1回目(Codex)で設計を入れた。2回目(Claude)でそれが効いた。しかも Claude 側では「API プロバイダ自身が提供するエイリアス」という層が加わって、2層構造の設計に発展した。

    もうひとつ。「完璧な設計を最初から入れる」必要はなくて、2回目の移行で仕組みを整えるくらいのタイミングがちょうどいいのかもしれません。1回目は「この作業、また来るな」と気づく。2回目は「前回の仕組みが効いた。じゃあもう少し良くしよう」と改善する。そのサイクルが回っている限り、モデルの世代交代は怖くなくなります。

    次のモデル更新が来ても、エイリアスの解決先を1行変えるだけ。そのサイクルが OpenAI 側でも Claude 側でも回る状態になりました。

    Claude Code をさらに活用する

    今回の移行作業では Claude Code (Sonnet 4.5) を使用しました。Claude Code の実践的な活用方法に興味がある方には、以下の書籍が参考になります。

    より入門的な内容から学びたい場合は、こちらもおすすめです。

    設計の参考書籍

    エイリアスシステムのような設計パターンについて、より体系的に学びたい方には以下がおすすめです。

    この記事は役に立ちましたか?

    Coffee cup

    この記事が、何かの整理につながったら

    コーヒー1杯分の応援をもらえると嬉しいです。

    ※ これは応援とは別の話ですが、

    同じようなテーマを自分の文脈で整理したい場合は、 (文章だけだと詰まりやすい人向けに) 思考整理の壁打ちという形で対話の時間も取っています。

    対話の時間について