はじめに
Claude Code v2.1.236 で ANTHROPIC_DEFAULT_MODEL という環境変数が増えました。CHANGELOG には「新しいセッションが開始するモデルを設定する」と書いてあります1。ところが手元にはすでに ANTHROPIC_MODEL、.claude/settings.json の model、--model フラグという指定経路があります。公式の環境変数ドキュメントには「環境変数は設定キーより優先される。ただし ANTHROPIC_DEFAULT_MODEL は例外」という一文があるだけで2、4経路を並べたときの順位も、エイリアス表記が経路ごとに同じように解決されるのかも書かれていません。4つ全部を設定したプロジェクトで、実際に課金されるのはどのモデルなのでしょうか。
対象読者は、Claude Code を複数プロジェクトやCI・スケジュール実行で使っていて、モデルの取り違えがコストに直結する開発者です。
同じ環境で11パターンを実行し、レスポンスの modelUsage キーから「実際に使われたモデル」を取り出して突き合わせました。結果、優先順位そのものよりも、ANTHROPIC_DEFAULT_MODEL に haiku と書いたときだけ、警告もエラーも出さずに既定の Sonnet で動く という挙動のほうが実害の大きい発見でした。
実測結果の一覧
検証環境は Claude Code 2.1.237 / Node.js v22.22.2 / Linux(クラウド実行環境)です。各ケースは独立した一時ディレクトリで claude -p "hi" --output-format json を実行し、返ってきた JSON の modelUsage のキー名を「実際に使われたモデル」として読み取っています。
| # | --model |
ANTHROPIC_MODEL |
settings.json model
|
ANTHROPIC_DEFAULT_MODEL |
実際に使われたモデル |
|---|---|---|---|---|---|
| 1 | — | — | — | — | claude-sonnet-5 |
| 2 | — | — | haiku |
— | claude-haiku-4-5-20251001 |
| 3 | — | — | — | haiku |
claude-sonnet-5 |
| 4 | — | — | — | opus |
claude-opus-5 |
| 5 | — | — | — | claude-haiku-4-5-20251001 |
claude-haiku-4-5-20251001 |
| 6 | — | — | opus |
sonnet |
claude-opus-5 |
| 7 | — | — | opus |
haiku |
claude-opus-5 |
| 8 | — | haiku |
opus |
— | claude-haiku-4-5-20251001 |
| 9 | — | haiku |
— | opus |
claude-haiku-4-5-20251001 |
| 10 | sonnet |
— | opus |
— | claude-sonnet-5 |
| 11 | sonnet |
haiku |
— | — | claude-sonnet-5 |
この11行から読み取れることは2つです。ひとつは優先順位が一本の鎖になっていること、もうひとつは3行目と5行目の差、つまり同じ Haiku を指しているはずの2つの書き方で結果が割れていることです。
1. 優先順位は「フラグ > ANTHROPIC_MODEL > settings.json > ANTHROPIC_DEFAULT_MODEL」
ケース8〜11が示すとおり、上位の指定は下位を完全に上書きします。図にすると次の順で解決されていました。
注目したいのは、ANTHROPIC_DEFAULT_MODEL が 4経路の中でいちばん弱い ことです。ケース6では ANTHROPIC_DEFAULT_MODEL=sonnet を設定しているのに、プロジェクトの settings.json に "model": "opus" があるだけで Opus が使われました。「シェルの環境変数はプロジェクト設定より強い」という直感は、この変数に限っては通用しません。
ANTHROPIC_MODEL(ケース8)は逆に settings.json を上書きします。名前が似ている2つの環境変数が、settings.json を挟んで正反対の位置にいる、というのが実測から出てきた地図です。
この非対称は公式ドキュメントの記述とも一致していました。環境変数のページには「環境変数と設定キーの両方を設定した場合は環境変数が優先される。ただし ANTHROPIC_DEFAULT_MODEL は例外」と書かれています2。例外がどちらに転ぶのか(設定キーが勝つのか、無視されるのか)は文面から読み取れませんが、実測では「設定キーが勝つ」でした。
2. haiku エイリアスだけ、無言で既定モデルに落ちる
いちばん困るのがケース3です。
$ ANTHROPIC_DEFAULT_MODEL=haiku claude -p "hi" --output-format json
modelUsage は claude-haiku-4-5-20251001 ではなく claude-sonnet-5 を返しました。標準エラー出力に警告はなく、終了コードも 0 です。同条件でもう一度実行しても結果は同じで、再現します。
一方で同じエイリアス表記でも、
-
settings.jsonに"model": "haiku"と書いた場合(ケース2)は Haiku が使われる -
ANTHROPIC_DEFAULT_MODEL=opusと書いた場合(ケース4)は Opus が使われる -
ANTHROPIC_DEFAULT_MODELにフル IDclaude-haiku-4-5-20251001を書いた場合(ケース5)は Haiku が使われる
つまり「この変数が効かない」のでも「エイリアスが使えない」のでもなく、ANTHROPIC_DEFAULT_MODEL × haiku というこの組み合わせだけ が解決に失敗し、既定の Sonnet にフォールバックしていました。
理由は実測では特定できていませんが、公式の環境変数一覧に手がかりがあります。ANTHROPIC_DEFAULT_HAIKU_MODEL の説明が「haiku エイリアスの解決先であり、バックグラウンド機能でも使われるモデル ID」となっており2、haiku が「セッションのモデル」とは別枠のエイリアスとして予約されていることが読み取れます。ここでの衝突が無言フォールバックの原因ではないか、というのが筆者の仮説です(検証はしていません)。
実害は分かりやすい形で出ます。コスト削減のつもりで export ANTHROPIC_DEFAULT_MODEL=haiku を CI やスケジュール実行の環境に置くと、失敗した形跡を残さないまま Sonnet で走り続けます。筆者は今回、--output-format json の modelUsage を見るまでこの取り違えにまったく気づけませんでした。
3. 設定が効いているかを確認する方法
推測を挟まずに確認する手段は、実行結果の JSON を見ることです。
claude -p "hi" --output-format json | python3 -c "import sys,json;print(list(json.load(sys.stdin)['modelUsage'].keys()))"
['claude-haiku-4-5-20251001'] のように、実際に課金対象となったモデル ID が返ります。modelUsage には costUSD や contextWindow も入っているため、「意図したモデルで動いているか」と「1回あたりいくらか」を同時に確認できます。設定を変えたら1回だけこのコマンドを通す、というのが今回いちばん費用対効果の高かった検証手順でした。
エイリアスの解決に不安があるなら、ANTHROPIC_DEFAULT_MODEL にはフル ID を書くのが確実です。ケース5のとおりフル ID は素直に通ります。
4. どの経路を使うべきか
実測を踏まえた使い分けは次のとおりです。
| 用途 | 推奨する経路 | 理由 |
|---|---|---|
| CI・スケジュール実行で確実に固定したい |
--model フラグ |
最強で、他のどの設定にも上書きされない |
| シェル単位で一時的に切り替えたい | ANTHROPIC_MODEL |
settings.json を上書きできる |
| プロジェクトごとの既定を決めたい |
settings.json の model
|
リポジトリにコミットでき、チームで共有できる |
| 個人の「開始時の既定」を決めたい | ANTHROPIC_DEFAULT_MODEL |
最弱なので、プロジェクト設定を邪魔しない |
ANTHROPIC_DEFAULT_MODEL が最弱であること自体は、設計として筋が通っています。個人の好みがチームのプロジェクト設定を勝手に上書きしないからです。CHANGELOG が説明しているとおり、この変数の狙いは「新しいセッションが開始するモデル」を決めることであって、実行中の指定を押しのけることではありません1。問題は、その弱さと haiku の無言フォールバックが重なると、設定したつもりの人がどこにも気づく手がかりを持てない 点にあります。
5. 検証していない範囲
今回測ったのは claude -p(ヘッドレス実行)だけです。CHANGELOG には「/model での選択は ANTHROPIC_DEFAULT_MODEL を上書きし、再起動をまたいで保持される(ANTHROPIC_MODEL と違って)」とあります1が、対話セッションでの /model 選択との優先関係は今回のヘッドレス検証の対象外です。対話利用が中心の方は、この一段を自分の環境で確かめてください。
また、haiku の無言フォールバックはバージョン 2.1.237 での挙動です。今後のリリースで解決対象が広がる可能性はあります。
おわりに
11パターンを同じ条件で走らせて分かったのは、「4経路の優先順位」という当初の問いよりも、エイリアスの解決範囲が経路ごとに違う という一段細かい事実のほうが実務に効く、ということでした。settings.json で通る haiku が環境変数では通らない、しかもエラーにならない。優先順位のほうは公式ドキュメントに例外規定として一行だけ書かれていましたが、このエイリアス解決の非対称は公式の説明を読んでも出てきません。
モデル指定を変えたら modelUsage を1回確認する。今回の実測から持ち帰れる習慣は、結局これに尽きます。
関連記事
- Claude Codeのauto mode既定化、denyとhookは4モードとも効いた
- Claude Code v2.1.222実機検証、新フラグ2つは2バージョン前の機能だった
- Claude CodeをOllama v0.14に直結する、--bareが鍵だった
-
Claude Code CHANGELOG v2.1.236 https://raw.githubusercontent.com/anthropics/claude-code/main/CHANGELOG.md ↩ ↩2 ↩3
-
Environment variables - Claude Code Docs https://code.claude.com/docs/en/env-vars ↩ ↩2 ↩3