TL;DR
- モデル更新で壊れるのは「モデル名を書いた場所」ではなく、そのモデルの出力形式を前提に組んだ資産です。
- 自リポジトリで棚卸ししたところ、エージェント定義 25 本の frontmatter に直書きされたモデル ID は 0 件(24 本が
inherit)。一方、散文に書かれたモデル名はエージェント資産側 6 箇所に対し、記事側 93 箇所でした。作業量は下流に偏ります。 - 移行の可否は「動いた気がするか」ではなく、決定的(deterministic)な回帰テストで判定します。本リポジトリの全記事評価は 212 本を 0.8 秒で採点でき、ゲート全体でも 8.6 秒です。
- その回帰テスト自体が信用できるかを mutation で測ったところ、13 の変異のうち検知は 8、見逃しは 5 でした。見逃しの内訳がそのまま、次に足すべきテストの設計図になります。
- 検証の途中で、ガード分岐が正規表現の欠陥で一度も発火していない実例(
\s*が改行を飲み込む)も見つかりました。テストを書いた≠テストが効いているです。
はじめに:モデルが変わると、何が壊れるのか
Coding Agent を業務に組み込むと、遅かれ早かれ「使っているモデルが更新される」「旧世代が廃止される」という日が来ます。このとき現場で起きるのは、次のような分かりにくい壊れ方です。
- エージェントは今日も動いている。エラーも出ない。ただし出力の形が少しずつ違う。
- 出力形式に依存した後段の自動化(パーサー、CI ゲート、テンプレート)が静かに落ちる、あるいは落ちずに誤った結果を通す。
- 「前のモデルのほうが良かった気がする」という感想が出るが、比較できる数字がない。
この記事は、AI Platform / Tech Lead / EM に向けて、この状況を運用設計の問題として扱うためのものです。個別モデルの性能比較はしません。ツール選定そのものは Codex と Claude Code の使い分け2026、費用面は Codex コスト最適化2026 に委ねます。
扱うのは 4 つだけです。依存の棚卸し / Model Matrix / 回帰テスト / 移行手順。すべて、このブログのリポジトリ(本記事を追加する直前で記事 212 本、エージェント定義 25 本、スキル 89 本)で実際に計測した数字を根拠にします。計測日はすべて 2026-09-06 です。
1. まずモデル依存を棚卸しする — 3 層に分けて数える
「モデルを変えたら何が壊れるか」を議論する前に、モデルに依存している箇所を数えるのが先です。依存は次の 3 層に分かれます。
| 層 | 何がモデルに依存しているか | 更新時の作業 | 自動検出 |
|---|---|---|---|
| 参照層 | エージェント定義に書かれたモデル ID | 文字列置換 | 容易(grep) |
| 契約層 | 出力の形式・粒度・語彙への暗黙の期待 | テストの再設計 | 困難 |
| 記述層 | 記事・ドキュメント本文に書かれたモデル名 | 記述の更新 or 一般化 | 容易(grep) |

参照層は目立つので真っ先に手を付けますが、実際にコストが出るのは契約層と記述層です。自リポジトリで実測しました。
# 参照層: エージェント定義の model フィールド
ls .agents/agents/*.md | wc -l # => 25
grep -l '^model:' .agents/agents/*.md | wc -l # => 24
grep -h '^model:' .agents/agents/*.md | sort | uniq -c
# => 24 model: inherit
# 記述層: 本文中に直書きされたモデル識別子
MODEL_RE='claude-(opus|sonnet|haiku)-[0-9a-z.-]+|gpt-[0-9][0-9.a-z-]*|gemini-[0-9][0-9.a-z-]*'
grep -rhoiE "$MODEL_RE" .agents/ | wc -l # => 6
grep -rhoiE "$MODEL_RE" content/posts/ | wc -l # => 93
grep -rliE "$MODEL_RE" content/posts/ | wc -l # => 23(記事本数)
結果は 2026-09-06 時点の実測値です(社内データ)。読み方は次のとおりです。
参照層はすでに守られていました。 エージェント定義 25 本のうち 24 本が model: inherit、つまり具体的なモデル ID を持たず呼び出し側から継承する形になっており、frontmatter にハードコードされたモデル ID は 0 件でした。残り 1 本はエージェント本体ではなく索引の README.md です。frontmatter に限れば、モデルを切り替えるときに触るのは 25 ファイルではなく呼び出し側だけで済みます。ただし移行が楽になる裏返しとして、この inherit は「どのモデルが動いたか」の情報を一切残しません。同じ実測を出所の棚卸し側から見た話は AI-BOMで何がコードを書いたか可視化する にあります。
壊れやすいのは記述層でした。 上の grep が拾った .agents/ 配下の 6 箇所は frontmatter ではなく、すべて 散文・手順説明の中に書かれたモデル名です(レビュー担当エージェントの説明文、スキルの前提記述など)。同じ検索を記事側に掛けると 93 箇所・23 本。つまり同じ記述層の中でも、上流の 6 箇所に対して下流に 15 倍以上が溜まっています。
モデル世代交代のコストは、エージェントの設定ではなくエージェントが生産した資産のほうに集中します。そしてここは自動移行できません(本文の主張自体が旧モデルの挙動を前提に書かれているため、置換ではなく判断が要る)。
ここから引ける運用ルールは 2 つです。
- モデル ID は 1 箇所に集約する。
inherit相当の間接参照を使い、エージェント定義に直書きしない。Claude Code のサブエージェントは frontmatter のmodelフィールドで指定モデルまたは継承を選べます。 - 生産物にモデル名を書くときは、確認日とセットにする。 後から「いつ時点の話か」が判別できないと、棚卸しのたびに全文を読み直すことになります。これは コンテキスト負債 と同じ構図です。
Claude Code のサブエージェントでは model は任意フィールドで、inherit を指定すると「メインの会話と同じモデルを使う」意味になります(公式値、Create custom subagents、確認日 2026-09-06)。この間接参照が、参照層のモデル依存を 0 件に保っている実装上の理由です。
2. Model Matrix — 「どの役割をどのモデルで回すか」を表にする
棚卸しが済んだら、モデルを役割単位で割り当てます。1 つのモデルで全部を回す構成は、そのモデルが更新された瞬間に全機能が同時に揺れるので避けます。
| 役割 | 求める性質 | 現行 | フォールバック | 切り替え判定 |
|---|---|---|---|---|
| 実装・リファクタリング | 長い文脈保持、ツール実行 | 上位モデル | 同世代の中位モデル | 回帰テスト PASS + 所要時間 |
| レビュー・監査 | 指摘の再現性 | 上位モデル | 別ベンダーの上位モデル | 既知欠陥の検出率 |
| 定型変換・要約 | 単価と速度 | 下位モデル | 上位モデル(一時的に) | 出力スキーマ適合率 |
| ゲート判定 | 決定性 | モデルを使わない | — | — |
最後の行が要点です。合否判定にモデルを使わない設計にしておくと、モデルが変わっても判定基準は動きません。判定を LLM に任せると、モデル更新のたびに「基準が変わったのか、成果物が変わったのか」を切り分けられなくなります。ガードレールを入出力層に置く考え方は LLMガードレール設計 と共通です。
フォールバックは「上位が落ちたら下位へ」だけでなく、別ベンダーへの横移動も用意しておきます。単一ベンダーの廃止スケジュールに運用が直結している状態は、テクノロジーレーダー でいう Hold 相当のリスクです。
3. Agent の回帰テストは「決定的なゲート」から作る
モデル移行の可否判定に必要なのは、同じ入力に対して同じ答えを返す検査です。本リポジトリではすでに 2 系統が動いています。
pnpm test # frontmatter / Markdown 規約 / スキル定義 / 索引の一括検査
pnpm run eval:articles # 全記事のスコアリング(0-500)
実測(2026-09-06、社内データ)はこうです。
| ゲート | 対象 | 所要時間 | 出力 |
|---|---|---|---|
pnpm run eval:articles | 記事 212 本 | 0.8 秒 | 平均スコア 482.8 |
pnpm test 一式 | 記事 212 本 + スキル 89 本 | 8.6 秒 | exit 0 |
対象が 212 本なのは、本記事を追加する前に取ったベースラインだからです(本記事を含めると 213 本 / 平均 482.9)。移行前の数字を先に取るという手順そのものの実演でもあります。
10 秒足らずで全資産を検査できるので、モデルを切り替えた直後に何度でも回せます。LLM-as-judge を第一段に置かない理由もここにあります。評価者側もモデルなので、被評価物と評価基準が同時に動いてしまい、しかも遅くて高い。LLM 評価は決定的ゲートを通過した後の第二段に置くのが妥当です。KPI 側の設計は AIガバナンスKPIループ を参照してください。
4. その回帰テストは本当に効いているか — mutation で測る
ここからが本題です。回帰テストを用意しても、モデル更新で実際に起きるドリフトを検知できなければ意味がありません。そこで、既存記事 1 本を基準に、モデル更新でありがちな出力ドリフトを 13 種類注入し、ゲートが検知するかを測りました。
手順は単純です。基準ファイルをコピーして 1 箇所だけ変異させ、各ゲートを単一ファイルモードで走らせて exit を見ます。
# 各ゲートは単一ファイルパスを受け取れる
python3 scripts/validate_frontmatter.py /tmp/mut/M01_link_format.md
python3 scripts/audit_markdown_rules.py /tmp/mut/M01_link_format.md
python3 scripts/evaluate_articles.py /tmp/mut/M01_link_format.md
# 注意: evaluate_articles.py は単一ファイル指定でもレポートを無条件で書き出す。
# コミット済みの reports/ が 1 記事分で上書きされるので、実行後に戻す。
git checkout -- reports/
結果(社内データ、2026-09-06 実測):
| # | 変異(モデル更新で起きうる出力ドリフト) | frontmatter 検査 | Markdown 検査 | スコア | 判定 |
|---|---|---|---|---|---|
| M01 | 内部リンクを別形式で出力する | OK | FAIL | 500 | 検知 |
| M02 | リンクにせず生パスを本文に書く | OK | FAIL | 500 | 検知 |
| M03 | 未完了マーカーを本文に残す | OK | FAIL | 500 | 検知 |
| M04 | パッケージマネージャを取り違える | OK | FAIL | 500 | 検知 |
| M05 | 見出しレベルを 1 段下げる | OK | FAIL | 416 | 検知 |
| M06 | 配列をブロック形式で出力する | OK | OK | 500 | 見逃し |
| M07 | description を極端に短くする | OK | OK | 500 | 見逃し |
| M08 | 下書きフラグを残す | OK | OK | 500 | 見逃し |
| M09 | 必須フィールドを落とす | FAIL | OK | 444 | 検知 |
| M10 | キーを重複させる | FAIL | OK | 500 | 検知 |
| M11 | 存在しないコマンド名に書き換える | OK | OK | 500 | 見逃し |
| M12 | 実在しない記事へリンクする | OK | OK | 500 | 見逃し |
| M13 | 定型見出しの名前を変える | OK | OK | 459 | 検知(減点) |
13 中 8 検知、5 見逃し。 検知率は約 62% です。基準ファイル自体は全ゲート OK / スコア 500 なので、FAIL は変異由来だと確定できます。
ただしこの 62% には注釈が要ります。M13 はスコアの減点でしか検知していません(全ゲート OK、500 → 459)。ファイル単体で見れば 41 点の低下は明らかですが、後述する「平均スコアが前回比 5% 低下」というロールバック条件で見ると、212 本の母集団で 1 本が 41 点下がっても平均の低下は 0.04% 程度で、閾値には到底届きません。exit code だけで数えれば検知は 7/13=54% です。単体評価と集計値ゲートでは検知できる粒度が違う、という前提で数字を読んでください。
見逃した 5 件は、性質が 3 つに分かれます。
(a) ルールはあるが、ゲートに実装されていない(M07・M08)
編集ポリシーには「description は 100 字以上」「下書きフラグは残さない」と明記されていますが、pnpm test の構成にはこれを検査するコードがありませんでした。ドキュメント上のルールと実行時に適用される検査の乖離であり、宣言と実効の乖離 そのものです。
(b) ゲートは書かれているが、発火しない(M06)
これが一番厄介でした。frontmatter 検査にはブロック形式の配列を弾く分岐が書かれています。しかし変異を入れても素通りしました。原因は正規表現です。
# 意図: "series:" の後ろが空 = ブロック形式 → FAIL させたい
m = re.search(r"^series:\s*(.*)$", frontmatter_text, re.MULTILINE)
# 実際: \s* が改行まで飲み込むため、次の行の "- standalone" が (.*) に入る
# match = 'series:\n - standalone'
# group1 = '- standalone' → 空でないので FAIL しない
\s は改行を含むので、\s* が行末を越えて次行の先頭まで進みます。結果、この分岐は一度も発火しない死んだガードになっていました。該当分岐を踏むユニットテストも存在しません。「テストを書いた」と「テストが効いている」の間には距離があり、その距離は mutation でしか測れません。この「発火しないガード」は本リポジトリで 7 通りの型として観測できており、分類と検出手順は 効いていないガードを見つける7つの型 にまとめています。
(c) 決定的検査では原理的に届かない(M11・M12)
コマンド名の誤りや、実在しない記事へのリンクは、形式としては完全に正しいので構文検査には引っかかりません。ここは事実の検証が要る領域で、参照先の実在確認や、主張と一次ソースの突き合わせを別レイヤーで持つ必要があります。M12 のような参照切れは、リンク先 slug の実在チェックとして機械化できます。
# 見逃し M12 を塞ぐ最小の検査(本文中の内部リンク先が実在するか)
grep -ohE '\(/notionnext-blog/[a-z0-9-]+\)' content/posts/*/index.md \
| tr -d '()' | sed 's#.*/##' | sort -u \
| while read -r s; do
[ -f "content/posts/$s/index.md" ] || echo "MISSING: $s"
done
5. 移行手順 — 4 ステップとロールバック条件
ここまでを手順に落とします。所要はリポジトリ規模にもよりますが、この規模なら半日程度です。
- 棚卸し(30 分): 3 層それぞれで grep し、件数を記録する。ここで出た数字が移行コストの見積もりになる。
- ベースライン取得(10 分): 旧モデルのまま
pnpm testとpnpm run eval:articlesを回し、exit code と平均スコアを記録する。移行前の数字を取らないと before/after は作れません。 - 切り替えと再計測(1 時間): 呼び出し側のモデル指定を 1 箇所だけ変え、同じ 2 コマンドを回す。差分はスコアの絶対値ではなく、前回比で見る。
- 見逃し領域の手動確認(2 時間): 上の (c) に相当する箇所、つまり事実主張・参照先・コマンド名を人間が確認する。決定的ゲートが 62% しか見ないという前提に立てば、残り 38% をどこで拾うかは事前に決めておくべきです。
ロールバック条件は数値で先に決めます。 「品質が下がった気がする」では戻せません。決定的ゲートが 1 つでも FAIL、平均スコアが前回比 5% 以上低下、いずれかが起きたら旧モデルに戻し、原因を切り分けてから再挑戦します。切り戻し先が消えている(旧モデルが既に廃止済み)状態を作らないよう、廃止予定日から逆算して移行期間を確保するのが前提です。
猶予はベンダーと提供区分で異なります。Anthropic は一般提供モデルの廃止について、稼働中の顧客に少なくとも 60 日前に通知すると明記しています(公式値、Model deprecations、確認日 2026-09-06)。OpenAI は GA モデルで 6 か月以上、preview モデルでは 2 週間程度の告知としています(公式値、Deprecations、確認日 2026-09-06)。Google も preview モデルは 2 週間以上の予告で廃止しうるとしています(公式値、Gemini API models、確認日 2026-09-06)。preview 系のモデルを本番の自動化に組み込むと、移行に使える時間が 2 週間しかないという前提で設計する必要があります。
なお、公開されている廃止日は「最も早い日付」として提示される場合があります(公式値、Gemini deprecations、確認日 2026-09-06)。締切ぎりぎりに移行計画を置かないでください。
6. よくある失敗
- モデル更新を「アップグレード」だと思い込む。 新しい世代が、自分たちの用途で必ず良いとは限りません。判定するのは公式のベンチマークではなく自分たちの回帰テストです。
- ベースラインを取らずに切り替える。 これが最頻の失敗です。切り替え後に数字を取っても、比較対象がないので何も言えません。
- エージェント定義だけ直して終わりにする。 本記事の実測では、散文に書かれたモデル名は上流のエージェント資産 6 箇所に対し、下流の記事側に 93 箇所ありました。
- 合否判定に LLM を使う。 評価者と被評価者が同時に動くと切り分け不能になります。
- ゲートの検知率を測らない。 死んだガード(M06)は、通常のテスト実行では永久に「緑」のままです。
FAQ
モデルが更新されたら毎回この手順を回す必要がありますか
いいえ。パッチ相当の更新まで全部やると回りません。ベースライン取得(ステップ 2)と再計測(ステップ 3)は 2 コマンド・10 秒程度なので毎回回し、棚卸しと手動確認は世代交代(メジャー更新・旧世代の廃止告知)のときだけ実施する、という二段構えが現実的です。
回帰テストの「合格ライン」はどう決めればいいですか
絶対値ではなく前回比で決めます。本リポジトリでは「決定的ゲートが全て exit 0」かつ「平均スコアが前回比 −5% 以内」を採用しています。絶対値の閾値は資産が増えるほど意味を失うので、移行の判定には向きません。
mutation は毎回 13 種類も作るのですか
最初の 1 回だけ作れば十分です。目的は変異を量産することではなく、ゲートの穴の場所を特定することにあります。穴が分かったら、そこを塞ぐ検査を書いてゲート側に恒久化し、mutation スクリプトは検知率の定点観測に使います。
エージェント定義に model: inherit を使うと、役割ごとにモデルを変えられなくなりませんか
なりません。継承を既定にしたうえで、決定性やコストの都合で固定したい役割だけ明示指定する、という運用が扱いやすいです。重要なのは「モデル ID を書く場所を数えられる状態にしておく」ことで、ゼロにすることではありません。
スキルやプロンプト資産はモデル移行の対象になりますか
なります。本リポジトリのスキル 89 本のように、出力形式や語彙を細かく指示した資産ほど、モデル世代が変わったときの適合度が変わります。資産の設計指針は Agent Skills の定義 を参照してください。ただし「新しいモデルなら資産は減らせる」は自動的には成立しません。本記事の移行作業を含む期間を同じリポジトリで測ると、この 14 日間のファイル削除は 0 件でした(AI Harnessの技術的負債と削る基準)。
まとめ:次にやること
Coding Agent のモデル更新は、ライブラリのバージョン更新と同じ扱いにできます。ただし決定的に違う点が 1 つあります。セマンティックバージョニングでは、パッチ更新は後方互換のバグ修正だけを含むと定義されており、番号を見れば互換性の有無が読み取れます(公式値、Semantic Versioning 2.0.0、確認日 2026-09-06)。モデルのバージョン番号にはその保証がありません。 しかも壊れ方が例外ではなく品質の劣化として現れるので、気づくのが遅れます。だから回帰テストが要ります。
DORA の 2025 年レポートは AI を組織の強みと弱みの増幅器(amplifier)と位置づけています(State of AI-assisted Software Development 2025、確認日 2026-09-06)。検証の仕組みを持たないままモデルを更新し続ける運用は、増幅される側の弱みそのものです。
今日できることは 3 つです。
- モデル依存を 3 層で grep して件数を記録する(30 分)。参照層より下流のほうが多いはずです。
- いま動いている決定的ゲートの数字を控える(10 分)。これが次回の移行のベースラインになります。
- ゲートに変異を 5 つほど注入して、検知率を測る(1 時間)。62% だった、という数字が出た時点で、次に書くべきテストが決まります。
エージェントの権限や実行時ガードまで含めた設計は 権限マトリクスとガードレール設計、蓄積した知識の扱いは セッションメモリの設計 に続きます。
References
- Anthropic — Model deprecations(確認日 2026-09-06。Active / Legacy / Deprecated / Retired のライフサイクルと廃止日一覧)
- Anthropic — Create custom subagents(確認日 2026-09-06。frontmatter の
modelフィールドとinheritの定義) - OpenAI — Deprecations(確認日 2026-09-06。モデル/API の廃止日と推奨代替の一覧)
- Google — Gemini deprecations(確認日 2026-09-06。shutdown date は最も早い廃止日として提示される旨の記載あり)
- Google — Gemini API models(確認日 2026-09-06。preview モデルの告知期間)
- DORA — State of AI-assisted Software Development 2025(確認日 2026-09-06。AI を組織の強みと弱みの増幅器と位置づける主張)
- セマンティック バージョニング 2.0.0 日本語版(確認日 2026-09-06。メジャー/マイナー/パッチの定義)
