Claudeコードモデルの選定:デフォルト設定、切り替え、およびコスト

Claudeコードモデルの選定:デフォルト設定、切り替え、およびコスト

Claudeコードモデルの選択にあたっては、小規模で検証可能な変更にはHaikuを、日常的な実装にはSonnetを、曖昧性が高い作業や推論を要する作業にはOpusを使用してください。. Anthropicでは現在、幅広い用途での導入の第一歩としてOpus 5.5を推奨しています。より小型のモデルの方が適しているかどうかは、業務内容、レビューの負担、および予算によって決まります。.

モデルを変更するには、以下を開いてください。 /モデル. プレス 入場 デフォルト値を保存するには、または s 現在のセッションのみを切り替えるには。1回限りの実行の場合は、以下を使用してください。 claude --model opus. これらの選択肢は保持時間が異なるため、スイッチをどのくらいの期間有効にするかを決定することは、モデルを選択することと同じくらい重要です。.

コーディング作業には、調査、説明、ドキュメント作成、クリエイティブ資産の作成なども含まれます。GlobalGPTは、最先端のAIモデルや複数のAIツールを1つの手頃な価格のダッシュボードに統合しており、そのCLIはこれらのツールをターミナルや開発ワークフローに連携させます。. GlobalGPTでワークフローを構築しましょう アイデアから実用的なコードへと進めていく過程で、関連するタスクを一箇所にまとめておくためです。.

Claudeコードでは、どのモデルを使用すべきでしょうか?

まずは作業の性質から考えましょう。期待される出力が明確な短い関数と、複数のサービスにまたがる断続的なバグとでは、評価の仕方が異なります。重要なのは、そのモデルが、妥当なレビューと反復を経て、許容できる変更を生み出せるかどうかという点です。.

現行モデルどのような用途を想定しているか実践的な最初の課題
クロード・ハイク 4.5範囲が限定された契約による、迅速かつ効率的な業務小規模なリファクタリング、反復的な変換、あるいは単純なテストケース
クロード・ソネット第5番日々のコーディングに最適な、知性とスピードのバランス定型的なパターンに基づく機能、日常的なバグ修正、またはコードの解説
Claude Opus 5.5複雑な推論や、より長時間の主体的コーディング作業曖昧な失敗、アーキテクチャ上のトレードオフ、あるいは相互に作用する制約を伴う変更
Claude Fable 5.1最も困難で、最も長期にわたる捜査困難な作業が、より高いレベルの「オパス」の取り組みを依然として上回ってしまうという状況の悪化
Anthropicのドキュメントに基づく、現在のモデルファミリーとタスクへの適合性。提案されているタスクは、実用的な出発点となります。.

Haikuは、ミスが容易に検出でき、変更の規模が小さい場合に検討する価値があります。Sonnetは、日常的な実装においてより多くの文脈や判断が必要とされる場合に、適切な選択肢となります。Opusは、問題の理解がタスクの重要な部分を占める場合に検討に値します。Fableは、高度な作業を要するため、別途検討すべきです。これは、私たちの3つのモデルを用いたコーディングテストの対象外でした。.

これらはあくまで出発点であり、品質が自動的に保証されるわけではありません。安価な回答であっても、何度も修正や徹底的なレビューが必要になれば、かえってコストがかさむ可能性があります。逆に、Claudeコードのチェックをすでに通過している単純な変換に対しては、より大規模なモデルを使用しても、ほとんど付加価値が得られない場合があります。Claudeコード以外のより幅広い用途については、, Claude モデルファミリーを比較する.

Anthropicによる、Fable 5.1、Opus 5.5、Sonnet 5、およびHaiku 4.5の最新モデル比較。.
Anthropicのモデルラインナップ(2026年9月28日時点)。Claudeコードでの利用可否は、ご利用のプロバイダーおよびアカウントによって異なります。.

について 公式モデル概要 Fable 5.1、Opus 5.5、およびSonnet 5については100万トークンのコンテキストウィンドウ、Haiku 4.5については20万トークンのコンテキストウィンドウが記載されています。これらはAPI仕様です。 セッションで利用可能なコンテキストオプションは、お使いの Claude コードプロバイダー、アカウント、および設定によって決まります。必要なコンテキストには大きなウィンドウが役立ちますが、無関係な情報でウィンドウを埋めてしまうと、モデルに余計な負荷がかかってしまいます。.

1回のセッションでモデルを切り替える方法

インタラクティブセッション内で、次のコマンドを実行します /モデル モデルピッカーを開くには、モデルの行を選択して、 s これが1回限りの変更である場合。を押すと 入場 選択範囲をユーザーのデフォルトとして保存します。入力すると /モデル・ソネット 現在のバージョンでは、直接保存することも可能です。.

変更をどのくらいの期間適用するかによって、コマンドを選択してください

Claudeコードの挙動を記録、2026年9月28日に確認済み
あなたの目標どうすればいいデフォルトの変更は保存されましたか?
この対話型セッションのみを切り替えるオープン /モデル, モデルを選択し、を押す s.いや。.
お気に入りのモデルを保存するオープン /モデル を押してください。 入場, 、または次のように入力してください /モデル・ソネット.はい、ユーザー設定が書き込み可能な場合です。.
Opusで単一のセッションを開始する打ち上げ claude --model opus.いや。.
アカウントの実行時のデフォルト設定に戻す用途 /モデルのデフォルト.モデルのオーバーライドを解除します。解決されたデフォルト値は、アカウントや組織の設定によって異なる場合があります。.
アクティブなモデルを確認する走る /ステータス.いや。.

プロジェクト設定や管理設定、環境のオーバーライド、および再開されたセッションは、次回の起動に影響を与える可能性があります。再現性が重要な場合は、アクティブなモデルを確認してください。.

出典:Claude コードモデルの構成.

新しいターミナルセッションを開く際は、起動時にモデルを選択してください。これらのコマンドは、Claude Code が VS Code の統合ターミナルで実行される場合にも適用されます。以下の例では、リリースを明示的に選択しています:

claude --model claude-opus-5-5
claude --model claude-sonnet-5

対象のセッションに対してコマンドを実行してください。例はいくつかの選択肢です。異なる設定で異なるターミナルを起動することもできます。 --モデル 共有された保存済みデフォルトを繰り返し変更することなく、値を指定します。次の方法を使用します。 /ステータス アクティブなモデルを確認するには。.

次のような姓など opus そして ソネット 新しいバージョンに移行できます。その解像度はプロバイダーによっても異なります。Anthropic APIでは現在、これらをOpus 5.5およびSonnet 5にマッピングしていますが、クラウドプロバイダーごとのマッピングは異なる場合があります。 再現性のある実行が必要な場合は完全なモデルIDを使用し、環境によってプロバイダー固有の名称が必要な場合は、それを確認してください。.

Opus 5.5 には Claude Code v2.1.280 以降が必要であり、Sonnet 5 には v2.1.197 以降が必要です。 モデル構成に関するドキュメント 現在のエイリアス、バージョン要件、およびプロバイダーのマッピングに関する参考資料です。ここにあるコマンドはドキュメント上の例であり、実践セクションでは生成されたコードを別途評価します。.

Claude コードのドキュメント。モデル選択および「Enter」キーと「s」キーの操作について解説しています。.
Enter キーを押すと、モデルがデフォルトとして保存されます。s キーを押すと、現在のセッションのみが変更されます。.

デフォルトのモデルを設定する方法

個人のデフォルトについては、以下のモデルから選択してください。 /モデル を押してください。 入場, 、または次のような選択内容を入力してください。 /モデル・ソネット. Claude コードは、 モデル そのファイルが書き込み可能な場合、ユーザー設定の該当フィールドに値が入力されます。新しいセッションを開き、そのアクティブなモデルを確認して、結果を確認してください。.

保存された設定は、他のすべての設定を上書きするわけではありません。起動フラグは、, ANTHROPIC_MODEL シェル、プロジェクト、または管理設定、あるいはユーザーの選択を上書きするように設定された組織のデフォルト設定では、起動時に別の項目を選択することができます。再開されたセッションでは、保存されたトランスクリプトのモデルが保持される場合もあります。起動時の情報を確認し、 /ステータス その選択が失われたと決めつける前に。.

/モデルのデフォルト モデルのオーバーライドを解除し、アカウントおよび設定のランタイムのデフォルト値に戻します。「この単語」 デフォルト これはリセット値であり、特定のClaudeモデルの名称ではありません。再現可能なモデル識別子として使用すべきではありません。.

詳細な設定を行うには、, ANTHROPIC_DEFAULT_MODEL v2.1.236 以降、フォールバック用の初期選択肢が提供されます。これは、明示的な起動、環境、設定、および組織の選択項目の下位に位置し、以下の値は無視されます。 俳句 そして opusplan. 一般的な個人的な好みとしては、ピッカーの方が確認しやすいです。参照: Claude のコード設定 共有設定が関係する場合。.

opusplanの実際の機能

opusplan 計画モードではOpusを、実行時にはSonnetを使用します。その魅力は単純明快です。つまり、より強力な推論モデルを用いてアプローチを練り上げ、その後、日常的なコーディングモデルを用いてその計画を実行に移すというものです。.

Opusplanは、以下の作業モードに従います

プランモード作品そのアプローチを順を追って進めていきましょう。.
実行ソネット計画を実行する。.

記録されたルーティングの挙動。これらのファミリー名の背後にあるバージョンは、プロバイダーや設定によって異なります。.

出典:Claude コードモデルの構成

これはモードに依存するルールです。すべてのプロンプトを精査して、自動的に最も安価な適切なファミリーを選択するわけではありません。基盤となるモデルに対しては、プロバイダーのマッピングやアクセス制限が引き続き適用されます。また、名称がコスト削減を保証するものでもありません。総コストは、そのタスクに必要な計画、実装、修正、およびコンテキスト処理の量によって異なります。.

今回は、より綿密な分析によって設計の質を高め、明確な計画に基づいて実装を進めるというアプローチを検討してみてはいかがでしょうか。些細な修正であれば、その余分な計画は不要かもしれません。.

2つのコーディング課題から明らかになったこと

モデル選択について具体的な見解を加えるため、要件が相互に影響し合う状況下で、限定的なUnicodeのリファクタリングとルートセレクタの修正を検証した。その結果、単純なスコアよりも、関数が正しいか、要求された出力が完全に実現されているかという点が重要であることが判明した。.

コーディング結果の検証方法

2026年9月28日、Claude Haiku 4.5、Claude Sonnet 5、およびClaude Opus 5.5に対し、GlobalGPTまでの同じ2つのJavaScriptタスクを与えました。 各モデルはソースコードを返しました。私たちはコードを検証し、ローカルでの固定チェックを実行しました。本ガイドの他の箇所にあるClaude Codeのモデル切り替え手順は、同製品の公式ドキュメントに基づいています。.

各リクエストの出力制限は4,096トークンで、ツールや会話履歴は使用せず、モデル設定はデフォルトのままとした。不完全な応答も含め、最初に評価可能な応答を1つ採用した。Sonnetのルーティングタスクで発生した1件のサービスエラーに対しては、許可されたリトライを1回実施した。7件のリクエストから6件の出力が得られた。.

これら2つの小規模なタスクでは、返されたコードと成果物の完成度を測定しています。Claude Codeのエージェントの実行状況、リポジトリの探索状況、あるいは開発セッション全体については測定対象外です。実際の料金については報告されていません。タスクごとに1件の観測データがあるだけでは、一般的な速度や信頼性の順位を決定づけることはできません。.

正確なモデルIDと評価条件を確認する

要求されたID: claude-haiku-4-5-20251001, claude-sonnet-5, そして クロード・作品第5番第5曲. ローカルでの検証は Node.js v24.19.0 で行われました。プロンプトは Node.js 18 以降を対象としていますが、Node.js 18 自体についてはテストされていません。.

ナメクジ課題では8つの行動グループが固定され、経路選択課題では12の行動グループが固定されました。フォーマット準拠と完全な提出については、それぞれ個別に報告されています。その後のコードレビューによるチェックは別途記載されており、これらの集計数には影響しません。また、提出されたソースコードを、基準を満たすように編集することは行っていません。.

課題 1: 小さなスラグのリファクタリングにおいて Unicode を維持する

この関数は、非ラテン文字や結合記号を保持し、分解されたアクセントを正規化し、既存のASCII動作を維持する必要がありました。.

ローカル動作のチェックを修正した最初の戻り値
モデル行動チェック回答形式ご指定の配送を完了する
クロード・ハイク 4.58/8失敗:Markdown ラッパーはい:関数を完了する
クロード・ソネット第5番8/8パス:生のJSONはい:関数を完了する
Claude Opus 5.58/8パス:生のJSONはい:関数を完了する

観測結果: 3つの機能すべてが、同じ8つのグループを処理しました。SonnetとOpusも、生のJSONレスポンスという要件を満たしていました。HaikuはレスポンスをMarkdownで囲んでいましたが、レビューノートではNFCを「文字の分解」と誤って記述していました。一方、そのコードではNFCが正しく呼び出されていました。.

この限定的なリファクタリングでは、アップグレードを行っても、テスト対象の関数の動作は改善されませんでした。書式要件や付随する説明の正確性については、依然として見直しが必要でした。.

共有されたプロンプトと入力コードの全文を表示する
SYSTEM
You are completing a bounded JavaScript coding task. Return only the requested JSON object with complete source files and brief review notes. Do not claim to have edited files, run commands, or used tools. You have no tool access. Do not include hidden reasoning.

USER
Implement the following Node.js 18+ CommonJS function from its current source. Return complete replacement source for src/slugify.js. Do not add dependencies, imports, I/O, or other files.

Required behavior:
1. slugify(value) returns an empty string for every non-string input.
2. Normalize string input to Unicode NFC, then lowercase it using JavaScript toLowerCase().
3. Preserve Unicode letters, numbers, and combining marks. Replace each consecutive run of all other characters with one ASCII hyphen.
4. Trim leading and trailing hyphens. Preserve the CommonJS export { slugify }.
5. Existing ASCII behavior must continue to work. Examples: Hello, World! -> hello-world; two   words -> two-words; null -> empty string.
6. Additional examples: Café déjà vu -> café-déjà-vu; decomposed Cafe\u0301 -> café; 中文 测试 42 -> 中文-测试-42; **hi___there** -> hi-there; only punctuation or whitespace -> empty string.

Current src/slugify.js:
```javascript
function slugify(value) {
  if (typeof value !== "string") return "";
  return value
    .trim()
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-+|-+$/g, "");
}

module.exports = { slugify };


```

Return exactly one JSON object with this shape:
{"files":{"src/slugify.js":"complete JavaScript source as a JSON string"},"review_notes":["at most four brief implementation or assumption notes"]}
No Markdown wrapper. You are returning code for someone else to evaluate locally; do not say that tests passed or that you ran them.
Claude Haiku 4.5の回答全文(返送されたもの)を表示する
```json
{
  "files": {
    "src/slugify.js": "function slugify(value) {\n  if (typeof value !== \"string\") return \"\";\n  \n  // Normalize to NFC and lowercase\n  const normalized = value.normalize(\"NFC\").toLowerCase();\n  \n  // Replace consecutive runs of non-letter, non-number, non-combining-mark characters with a single hyphen\n  // Unicode letter categories: L* (Lu, Ll, Lt, Lm, Lo)\n  // Unicode number categories: N* (Nd, Nl, No)\n  // Unicode combining mark categories: M* (Mn, Mc, Me)\n  const slugged = normalized.replace(/[^\\p{L}\\p{N}\\p{M}]+/gu, \"-\");\n  \n  // Trim leading and trailing hyphens\n  return slugged.replace(/^-+|-+$/g, \"\");\n}\n\nmodule.exports = { slugify };"
  },
  "review_notes": [
    "Uses String.prototype.normalize(\"NFC\") to decompose composed characters like é into base+combining mark, then toLowerCase() applies to normalized string",
    "Unicode property escapes (\\p{L}, \\p{N}, \\p{M}) with /u flag preserve all Unicode letters, numbers, and combining marks while replacing other consecutive characters with single hyphens",
    "Existing ASCII behavior is preserved: punctuation and whitespace are replaced with hyphens, then leading/trailing hyphens are trimmed",
    "Non-string inputs return empty string as required; normalized decomposed characters (e.g., Cafe\\u0301) are handled correctly by NFC normalization"
  ]
}
```
Claude Sonnet 5の回答全文を、提出されたままの形で表示する
{"files":{"src/slugify.js":"function slugify(value) {\n  if (typeof value !== \"string\") return \"\";\n  return value\n    .normalize(\"NFC\")\n    .toLowerCase()\n    .replace(/[^\\p{L}\\p{N}\\p{M}]+/gu, \"-\")\n    .replace(/^-+|-+$/g, \"\");\n}\n\nmodule.exports = { slugify };\n"},"review_notes":["Used Unicode property escapes (\\p{L}, \\p{N}, \\p{M}) with the u flag to preserve letters, numbers, and combining marks across scripts.","NFC normalization ensures decomposed sequences like Cafe + combining acute compose to café before lowercasing.","Runs of any other characters (punctuation, whitespace, symbols) collapse to a single hyphen, then leading/trailing hyphens are trimmed."]}
返送されたClaude Opus 5.5の回答全文を表示する
{"files":{"src/slugify.js":"function slugify(value) {\n  if (typeof value !== \"string\") return \"\";\n  return value\n    .normalize(\"NFC\")\n    .toLowerCase()\n    .replace(/[^\\p{L}\\p{N}\\p{M}]+/gu, \"-\")\n    .replace(/^-+|-+$/g, \"\");\n}\n\nmodule.exports = { slugify };\n"},"review_notes":["The input is normalized to NFC before lowercasing, so decomposed input like Cafe\\u0301 composes to café.","A Unicode property regex with the u flag keeps letters (\\p{L}), numbers (\\p{N}) and combining marks (\\p{M}). Each run of any other characters, including underscores and whitespace, becomes one hyphen.","The explicit trim() was removed because the final step strips leading and trailing hyphens, which covers surrounding whitespace.","Lowercasing happens after NFC normalization, as the spec orders. toLowerCase can occasionally produce non-NFC output for rare characters, and it is not re-normalized here."]}

課題 2: ルートセレクタを修正し、そのテストを提出する

この関数では、最長接頭辞の一致、メソッドの優先順位、セグメントの境界、不正な形式のルール、および不変の入力といった問題を処理する必要がありました。また、要求されたレスポンスには、新しいテストファイルも含まれていました。.

ローカル動作のチェックを修正した最初の戻り値
モデル行動チェック回答形式ご指定の配送を完了する
クロード・ハイク 4.512月12日はコンプリート機能のみエラー:JSONが切り詰められていますNo: テストファイルが途切れている
クロード・ソネット第5番12月12日はコンプリート機能のみエラー:JSONが切り詰められていますNo: テストファイルが途切れている
Claude Opus 5.512月12日はコンプリート機能のみエラー:JSONが切り詰められていますNo: テストファイルが途切れている

観測結果: どのモデルも、共有出力制限内で要求された2つのファイルに対する応答を完了できませんでした。3つすべてのモデルが、4,096個の完了トークンを報告した時点で停止しました。各モデルはすでに、12の固定動作グループに合格した完全なルーター関数を返していました。新しいテストファイルは不完全であったため、実行されませんでした。.

完全に閉じられたソースコードの文字列のみを抽出しました。元の切り詰められた応答は、以下にそのまま残しています。したがって、関数のスコアが合格基準を満たしても、リクエスト全体が成功したとは限りません。.

コードレビューで発見されたその他の問題点:同根の同点

定期的なチェックの後、Haikuが正規化されていることに気づきました /// ではなく、空の文字列に /. 別のローカルチェックでは、2つのGETルールが使用され、プレフィックスは /// そして /, 、対象として 第一 そして 秒 その順番で。なぜなら、 /何でも, 、契約では次のように定められている 第一.

ハイクが戻ってきた 秒; 「ソネット」と「オーパス」が戻ってきた 第一. この追加のチェックはコードレビューの結果として実施されたものであり、テスト前に設定された12項目のチェックとは別のもので、それらのスコアには影響しません。.

Sonnetは、許可された再試行によって表示された切り詰められた応答が返される前に、1回のサービスエラーに遭遇しました。このサービスエラーは、コードの品質とは無関係です。どのモデルも、回答を改善または完成させるための再試行の機会を与えられませんでした。.

共有されたプロンプトと入力コードの全文を表示する
SYSTEM
You are completing a bounded JavaScript coding task. Return only the requested JSON object with complete source files and brief review notes. Do not claim to have edited files, run commands, or used tools. You have no tool access. Do not include hidden reasoning.

USER
Repair a Node.js 18+ CommonJS route selector. Return complete replacement src/router.js and an additional test/router-added.test.js using node:test and node:assert/strict. Do not add dependencies or edit existing tests. Do not use I/O other than the test runner, network, child processes, timers, or any files beyond the two requested outputs.

Contract for chooseRoute(request, rules):
1. Invalid request or rules returns null, without throwing. Request must be a non-null, non-array object; method must be a nonempty ASCII-letter string; path must be a string beginning with /. Rules must be an array.
2. Before matching, remove the request path's query and fragment starting at the earliest ? or #. Do not URL-decode or collapse interior slashes.
3. Ignore invalid rules. A valid rule is a non-null, non-array object with method '*' or a nonempty ASCII-letter string, prefix a string starting with / containing neither ? nor #, and target a nonempty string.
4. Compare methods case-insensitively. Prefer any matching exact-method rule over all wildcard-method '*' rules, even if a wildcard has a longer prefix. Use wildcard rules only if no exact-method route matches the path.
5. Remove trailing slashes from a rule prefix, except that an all-slash prefix normalizes to /. A prefix matches the path only at a segment boundary: /api matches /api and /api/users, never /apix. Root / matches every valid request path.
6. Within the chosen method group, choose the longest normalized matching prefix. On equal prefix length, choose the earlier rule in the original input array. Return its target. Return null if none matches.
7. Do not mutate the request, rules array, or rule objects, including order or prefix strings. Preserve module.exports = { chooseRoute }.
8. Add tests for segment boundaries, query/fragment removal, method precedence, ties, malformed inputs and immutability. Existing simple GET /api/users and POST-no-match cases must still pass.

Current src/router.js:
```javascript
function chooseRoute(request, rules) {
  if (!request || !Array.isArray(rules)) return null;
  for (const rule of rules) {
    if (request.method === rule.method && request.path.startsWith(rule.prefix)) {
      return rule.target;
    }
  }
  return null;
}

module.exports = { chooseRoute };


```

Existing regression cases (unchanged): rules [{method:'GET',prefix:'/api',target:'api'},{method:'GET',prefix:'/api/admin',target:'admin'}]; GET /api/users returns 'api'; POST /api/users returns null.

Return exactly one JSON object with this shape:
{"files":{"src/router.js":"complete JavaScript source as a JSON string","test/router-added.test.js":"complete JavaScript tests as a JSON string"},"review_notes":["at most four brief implementation or assumption notes"]}
No Markdown wrapper. You are returning code for someone else to evaluate locally; do not say you edited files, ran tests, or observed passing results.
Claude Haiku 4.5の回答全文(返送されたもの)を表示する

これが受け取った応答のすべてです。制限に達したため、出力途中で終了しており、欠落している内容は補完されていません。.

```json
{
  "files": {
    "src/router.js": "function chooseRoute(request, rules) {\n  // Validate request\n  if (request === null || Array.isArray(request) || typeof request !== 'object') {\n    return null;\n  }\n  if (typeof request.method !== 'string' || request.method.length === 0 || !/^[a-zA-Z]+$/.test(request.method)) {\n    return null;\n  }\n  if (typeof request.path !== 'string' || !request.path.startsWith('/')) {\n    return null;\n  }\n\n  // Validate rules\n  if (!Array.isArray(rules)) {\n    return null;\n  }\n\n  // Remove query and fragment from path\n  const cleanPath = request.path.split(/[?#]/)[0];\n\n  // Filter and validate rules\n  const validRules = [];\n  for (const rule of rules) {\n    if (rule === null || Array.isArray(rule) || typeof rule !== 'object') {\n      continue;\n    }\n    \n    const method = rule.method;\n    if (typeof method !== 'string' || (method !== '*' && (method.length === 0 || !/^[a-zA-Z]+$/.test(method)))) {\n      continue;\n    }\n    \n    const prefix = rule.prefix;\n    if (typeof prefix !== 'string' || !prefix.startsWith('/') || prefix.includes('?') || prefix.includes('#')) {\n      continue;\n    }\n    \n    const target = rule.target;\n    if (typeof target !== 'string' || target.length === 0) {\n      continue;\n    }\n    \n    validRules.push(rule);\n  }\n\n  // Normalize prefixes and partition into exact-method and wildcard groups\n  const exactMethodRules = [];\n  const wildcardRules = [];\n  \n  for (const rule of validRules) {\n    const normalizedPrefix = rule.prefix === '/' ? '/' : rule.prefix.replace(/\/+$/, '');\n    \n    const entry = {\n      originalRule: rule,\n      normalizedPrefix: normalizedPrefix,\n      method: rule.method\n    };\n    \n    if (rule.method === '*') {\n      wildcardRules.push(entry);\n    } else {\n      exactMethodRules.push(entry);\n    }\n  }\n\n  const requestMethod = request.method.toUpperCase();\n\n  // Helper to check if a prefix matches the path at a segment boundary\n  function prefixMatches(prefix, path) {\n    if (prefix === '/') {\n      return true;\n    }\n    if (!path.startsWith(prefix)) {\n      return false;\n    }\n    // Check segment boundary: next character must be '/' or end of string\n    const nextChar = path[prefix.length];\n    return nextChar === undefined || nextChar === '/';\n  }\n\n  // Try exact-method rules first\n  let bestMatch = null;\n  let bestLength = -1;\n  \n  for (const entry of exactMethodRules) {\n    if (entry.method.toUpperCase() === requestMethod) {\n      if (prefixMatches(entry.normalizedPrefix, cleanPath)) {\n        if (entry.normalizedPrefix.length > bestLength) {\n          bestMatch = entry.originalRule;\n          bestLength = entry.normalizedPrefix.length;\n        }\n      }\n    }\n  }\n  \n  if (bestMatch !== null) {\n    return bestMatch.target;\n  }\n\n  // Try wildcard rules only if no exact-method match\n  bestMatch = null;\n  bestLength = -1;\n  \n  for (const entry of wildcardRules) {\n    if (prefixMatches(entry.normalizedPrefix, cleanPath)) {\n      if (entry.normalizedPrefix.length > bestLength) {\n        bestMatch = entry.originalRule;\n        bestLength = entry.normalizedPrefix.length;\n      }\n    }\n  }\n  \n  if (bestMatch !== null) {\n    return bestMatch.target;\n  }\n\n  return null;\n}\n\nmodule.exports = { chooseRoute };",
    "test/router-added.test.js": "const test = require('node:test');\nconst assert = require('node:assert/strict');\nconst { chooseRoute } = require('../src/router.js');\n\n// Regression: existing test cases\ntest('GET /api/users matches /api prefix (exact method)', () => {\n  const rules = [\n    { method: 'GET', prefix: '/api', target: 'api' },\n    { method: 'GET', prefix: '/api/admin', target: 'admin' }\n  ];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, rules), 'api');\n});\n\ntest('POST /api/users returns null (no matching method)', () => {\n  const rules = [\n    { method: 'GET', prefix: '/api', target: 'api' },\n    { method: 'GET', prefix: '/api/admin', target: 'admin' }\n  ];\n  assert.equal(chooseRoute({ method: 'POST', path: '/api/users' }, rules), null);\n});\n\n// Invalid request handling\ntest('null request returns null', () => {\n  assert.equal(chooseRoute(null, []), null);\n});\n\ntest('array request returns null', () => {\n  assert.equal(chooseRoute([], []), null);\n});\n\ntest('request with missing method returns null', () => {\n  assert.equal(chooseRoute({ path: '/api' }, []), null);\n});\n\ntest('request with empty method returns null', () => {\n  assert.equal(chooseRoute({ method: '', path: '/api' }, []), null);\n});\n\ntest('request with non-letter method returns null', () => {\n  assert.equal(chooseRoute({ method: 'GET-POST', path: '/api' }, []), null);\n});\n\ntest('request with numeric method returns null', () => {\n  assert.equal(chooseRoute({ method: '123', path: '/api' }, []), null);\n});\n\ntest('request with missing path returns null', () => {\n  assert.equal(chooseRoute({ method: 'GET' }, []), null);\n});\n\ntest('request with path not starting with / returns null', () => {\n  assert.equal(chooseRoute({ method: 'GET', path: 'api' }, []), null);\n});\n\ntest('null rules returns null', () => {\n  assert.equal(chooseRoute({ method: 'GET', path: '/api' }, null), null);\n});\n\ntest('non-array rules returns null', () => {\n  assert.equal(chooseRoute({ method: 'GET', path: '/api' }, { method: 'GET' }), null);\n});\n\n// Query and fragment removal\ntest('query string is removed before matching', () => {\n  const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api/users?foo=bar' }, rules), 'found');\n});\n\ntest('fragment is removed before matching', () => {\n  const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api/users#section' }, rules), 'found');\n});\n\ntest('earliest ? or # is used as boundary', () => {\n  const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api/users?foo#bar' }, rules), 'found');\n});\n\ntest('fragment before query is used as boundary', () => {\n  const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api/users#foo?bar' }, rules), 'found');\n});\n\n// Segment boundary matching\ntest('prefix /api matches /api/users at segment boundary', () => {\n  const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, rules), 'found');\n});\n\ntest('prefix /api does not match /apix (no segment boundary)', () => {\n  const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n  assert.equal(chooseRoute({ method: 'GET', path: '/apix' }, rules), null);\n});\n\ntest('prefix /api matches /api exactly at segment boundary', () => {\n  const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'found');\n});\n\ntest('root / matches any valid path', () => {\n  const rules = [{ method: 'GET', prefix: '/', target: 'root' }];\n  assert.equal(chooseRoute({ method: 'GET', path: '/anything/here' }, rules), 'root');\n});\n\ntest('root / matches /', () => {\n  const rules = [{ method: 'GET', prefix: '/', target: 'root' }];\n  assert.equal(chooseRoute({ method: 'GET', path: '/' }, rules), 'root');\n});\n\n// Prefix normalization (trailing slash removal)\ntest('trailing slash is removed from prefix', () => {\n  const rules = [{ method: 'GET', prefix: '/api/', target: 'found' }];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, rules), 'found');\n});\n\ntest('multiple trailing slashes are removed', () => {\n  const rules = [{ method: 'GET', prefix: '/api///', target: 'found' }];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, rules), 'found');\n});\n\ntest('all-slash prefix normalizes to single /', () => {\n  const rules = [{ method: 'GET', prefix: '///', target: 'found' }];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'found');\n});\n\n// Method case-insensitivity\ntest('method comparison is case-insensitive', () => {\n  const rules = [{ method: 'get', prefix: '/api', target: 'found' }];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'found');\n});\n\ntest('request method case does not affect matching', () => {\n  const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n  assert.equal(chooseRoute({ method: 'get', path: '/api' }, rules), 'found');\n});\n\n// Exact-method vs wildcard precedence\ntest('exact-method rule preferred over wildcard with longer prefix', () => {\n  const rules = [\n    { method: '*', prefix: '/api/admin/users', target: 'wildcard' },\n    { method: 'GET', prefix: '/api', target: 'exact' }\n  ];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api/test' }, rules), 'exact');\n});\n\ntest('wildcard rule used when no exact-method matches', () => {\n  const rules = [\n    { method: '*', prefix: '/api', target: 'wildcard' },\n    { method: 'GET', prefix: '/other', target: 'exact' }\n  ];\n  assert.equal(chooseRoute({ method: 'POST', path: '/api/users' }, rules), 'wildcard');\n});\n\n// Longest prefix matching\ntest('longest matching prefix is chosen', () => {\n  const rules = [\n    { method: 'GET', prefix: '/api', target: 'short' },\n    { method: 'GET', prefix: '/api/admin', target: 'long' }\n  ];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api/admin/users' }, rules), 'long');\n});\n\n// Tie-breaking (first rule wins on equal prefix length)\ntest('first rule wins on equal prefix length', () => {\n  const rules = [\n    { method: 'GET', prefix: '/api', target: 'first' },\n    { method: 'GET', prefix: '/api', target: 'second' }\n  ];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, rules), 'first');\n});\n\n// Invalid rules are ignored\ntest('null rule is ignored', () => {\n  const rules = [\n    null,\n    { method: 'GET', prefix: '/api', target: 'found' }\n  ];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'found');\n});\n\ntest('array rule is ignored', () => {\n  const rules = [\n    [],\n    { method: 'GET', prefix: '/api', target: 'found' }\n  ];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'found');\n});\n\ntest('rule with invalid method is ignored', () => {\n  const rules = [\n    { method: '', prefix: '/api', target: 'invalid' },\n    { method: 'GET', prefix: '/api', target: 'valid' }\n  ];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'valid');\n});\n\ntest('rule with non-letter method (if not wildcard) is ignored', () => {\n  const rules = [\n    { method: 'G3T', prefix: '/api', target: 'invalid' },\n    { method: 'GET', prefix: '/api', target: 'valid' }\n  ];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'valid');\n});\n\ntest('rule with prefix not starting with / is ignored', () => {\n  const rules = [\n    { method: 'GET', prefix: 'api', target: 'invalid' },\n    { method: 'GET', prefix: '/api', target: 'valid' }\n  ];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'valid');\n});\n\ntest('rule with query in prefix is ignored', () => {\n  const rules = [\n    { method: 'GET', prefix: '/api?foo=bar', target: 'invalid' },\n    { method: 'GET', prefix: '/api', target: 'valid' }\n  ];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'valid');\n});\n\ntest('rule with fragment in prefix is ignored', () => {\n  const rules = [\n    { method: 'GET', prefix: '/api#section', target: 
Claude Sonnet 5の回答全文を、提出されたままの形で表示する

これが受け取った応答のすべてです。制限に達したため、出力途中で終了しており、欠落している内容は補完されていません。.

{"files":{"src/router.js":"function isValidRequest(request) {\n  return (\n    request !== null &&\n    typeof request === 'object' &&\n    !Array.isArray(request) &&\n    typeof request.method === 'string' &&\n    request.method.length > 0 &&\n    /^[A-Za-z]+$/.test(request.method) &&\n    typeof request.path === 'string' &&\n    request.path.startsWith('/')\n  );\n}\n\nfunction isValidRule(rule) {\n  if (rule === null || typeof rule !== 'object' || Array.isArray(rule)) {\n    return false;\n  }\n  const { method, prefix, target } = rule;\n\n  if (typeof method !== 'string') return false;\n  if (method !== '*' && !(method.length > 0 && /^[A-Za-z]+$/.test(method))) {\n    return false;\n  }\n\n  if (\n    typeof prefix !== 'string' ||\n    !prefix.startsWith('/') ||\n    prefix.includes('?') ||\n    prefix.includes('#')\n  ) {\n    return false;\n  }\n\n  if (typeof target !== 'string' || target.length === 0) return false;\n\n  return true;\n}\n\nfunction normalizePrefix(prefix) {\n  if (/^\/+$/.test(prefix)) return '/';\n  return prefix.replace(/\/+$/, '');\n}\n\nfunction prefixMatches(normalizedPrefix, path) {\n  if (normalizedPrefix === '/') return true;\n  if (path === normalizedPrefix) return true;\n  return path.startsWith(normalizedPrefix + '/');\n}\n\nfunction stripQueryAndFragment(path) {\n  let cutIndex = path.length;\n  for (let i = 0; i < path.length; i++) {\n    const c = path[i];\n    if (c === '?' || c === '#') {\n      cutIndex = i;\n      break;\n    }\n  }\n  return path.slice(0, cutIndex);\n}\n\nfunction chooseRoute(request, rules) {\n  if (!isValidRequest(request) || !Array.isArray(rules)) return null;\n\n  const path = stripQueryAndFragment(request.path);\n  const reqMethodLower = request.method.toLowerCase();\n\n  let bestExact = null; // { len, idx, target }\n  let bestWildcard = null;\n\n  for (let idx = 0; idx < rules.length; idx++) {\n    const rule = rules[idx];\n    if (!isValidRule(rule)) continue;\n\n    const normPrefix = normalizePrefix(rule.prefix);\n    if (!prefixMatches(normPrefix, path)) continue;\n\n    const len = normPrefix.length;\n\n    if (rule.method === '*') {\n      if (\n        bestWildcard === null ||\n        len > bestWildcard.len ||\n        (len === bestWildcard.len && idx < bestWildcard.idx)\n      ) {\n        bestWildcard = { len, idx, target: rule.target };\n      }\n    } else if (rule.method.toLowerCase() === reqMethodLower) {\n      if (\n        bestExact === null ||\n        len > bestExact.len ||\n        (len === bestExact.len && idx < bestExact.idx)\n      ) {\n        bestExact = { len, idx, target: rule.target };\n      }\n    }\n  }\n\n  if (bestExact !== null) return bestExact.target;\n  if (bestWildcard !== null) return bestWildcard.target;\n  return null;\n}\n\nmodule.exports = { chooseRoute };\n","test/router-added.test.js":"const test = require('node:test');\nconst assert = require('node:assert/strict');\nconst { chooseRoute } = require('../src/router');\n\ntest('segment boundary: prefix matches at slash boundary only', () => {\n  const rules = [\n    { method: 'GET', prefix: '/api', target: 'api' },\n  ];\n  assert.equal(\n    chooseRoute({ method: 'GET', path: '/api/users' }, rules),\n    'api'\n  );\n  assert.equal(\n    chooseRoute({ method: 'GET', path: '/api' }, rules),\n    'api'\n  );\n  assert.equal(\n    chooseRoute({ method: 'GET', path: '/apix' }, rules),\n    null\n  );\n});\n\ntest('root prefix matches every valid path', () => {\n  const rules = [{ method: 'GET', prefix: '/', target: 'root' }];\n  assert.equal(chooseRoute({ method: 'GET', path: '/' }, rules), 'root');\n  assert.equal(\n    chooseRoute({ method: 'GET', path: '/anything/here' }, rules),\n    'root'\n  );\n});\n\ntest('trailing slashes in rule prefix are normalized', () => {\n  const rules = [{ method: 'GET', prefix: '/api///', target: 'api' }];\n  assert.equal(\n    chooseRoute({ method: 'GET', path: '/api/users' }, rules),\n    'api'\n  );\n  assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'api');\n});\n\ntest('all-slash prefix normalizes to /', () => {\n  const rules = [{ method: 'GET', prefix: '////', target: 'root' }];\n  assert.equal(\n    chooseRoute({ method: 'GET', path: '/whatever' }, rules),\n    'root'\n  );\n});\n\ntest('query and fragment are stripped before matching', () => {\n  const rules = [{ method: 'GET', prefix: '/api', target: 'api' }];\n  assert.equal(\n    chooseRoute({ method: 'GET', path: '/api/users?x=1&y=2' }, rules),\n    'api'\n  );\n  assert.equal(\n    chooseRoute({ method: 'GET', path: '/api/users#section' }, rules),\n    'api'\n  );\n  assert.equal(\n    chooseRoute({ method: 'GET', path: '/api/users?x=1#frag' }, rules),\n    'api'\n  );\n});\n\ntest('query/fragment stripping does not decode or collapse slashes', () => {\n  const rules = [{ method: 'GET', prefix: '/a//b', target: 'weird' }];\n  assert.equal(\n    chooseRoute({ method: 'GET', path: '/a//b?x=1' }, rules),
返送されたClaude Opus 5.5の回答全文を表示する

これが受け取った応答のすべてです。制限に達したため、出力途中で終了しており、欠落している内容は補完されていません。.

{"files":{"src/router.js":"'use strict';\n\nconst LETTERS = /^[A-Za-z]+$/;\n\nfunction isPlainObject(value) {\n  return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isMethodName(value) {\n  return typeof value === 'string' && value.length > 0 && LETTERS.test(value);\n}\n\nfunction stripQueryAndFragment(path) {\n  const q = path.indexOf('?');\n  const h = path.indexOf('#');\n  let cut = -1;\n  if (q !== -1 && h !== -1) cut = Math.min(q, h);\n  else if (q !== -1) cut = q;\n  else if (h !== -1) cut = h;\n  return cut === -1 ? path : path.slice(0, cut);\n}\n\nfunction normalizePrefix(prefix) {\n  let end = prefix.length;\n  while (end > 0 && prefix[end - 1] === '/') end -= 1;\n  return end === 0 ? '/' : prefix.slice(0, end);\n}\n\nfunction prefixMatches(path, prefix) {\n  if (prefix === '/') return true;\n  return path === prefix || path.startsWith(prefix + '/');\n}\n\nfunction chooseRoute(request, rules) {\n  try {\n    if (!isPlainObject(request) || !Array.isArray(rules)) return null;\n    const method = request.method;\n    const rawPath = request.path;\n    if (!isMethodName(method)) return null;\n    if (typeof rawPath !== 'string' || rawPath[0] !== '/') return null;\n\n    const path = stripQueryAndFragment(rawPath);\n    const upperMethod = method.toUpperCase();\n\n    let bestExact = null;\n    let bestWildcard = null;\n\n    const count = rules.length;\n    for (let i = 0; i < count; i += 1) {\n      const rule = rules[i];\n      if (!isPlainObject(rule)) continue;\n      const ruleMethod = rule.method;\n      const prefix = rule.prefix;\n      const target = rule.target;\n      const isWildcard = ruleMethod === '*';\n      if (!isWildcard && !isMethodName(ruleMethod)) continue;\n      if (typeof prefix !== 'string' || prefix[0] !== '/') continue;\n      if (prefix.indexOf('?') !== -1 || prefix.indexOf('#') !== -1) continue;\n      if (typeof target !== 'string' || target.length === 0) continue;\n\n      const normalized = normalizePrefix(prefix);\n      if (!prefixMatches(path, normalized)) continue;\n\n      const candidate = { length: normalized.length, target };\n      if (isWildcard) {\n        if (bestWildcard === null || candidate.length > bestWildcard.length) bestWildcard = candidate;\n      } else if (ruleMethod.toUpperCase() === upperMethod) {\n        if (bestExact === null || candidate.length > bestExact.length) bestExact = candidate;\n      }\n    }\n\n    if (bestExact !== null) return bestExact.target;\n    if (bestWildcard !== null) return bestWildcard.target;\n    return null;\n  } catch (err) {\n    return null;\n  }\n}\n\nmodule.exports = { chooseRoute };\n","test/router-added.test.js":"'use strict';\n\nconst test = require('node:test');\nconst assert = require('node:assert/strict');\nconst { chooseRoute } = require('../src/router.js');\n\nconst baseRules = [\n  { method: 'GET', prefix: '/api', target: 'api' },\n  { method: 'GET', prefix: '/api/admin', target: 'admin' }\n];\n\ntest('existing regression cases still hold', () => {\n  assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, baseRules), 'api');\n  assert.equal(chooseRoute({ method: 'POST', path: '/api/users' }, baseRules), null);\n});\n\ntest('longest prefix wins within method group', () => {\n  assert.equal(chooseRoute({ method: 'GET', path: '/api/admin/x' }, baseRules), 'admin');\n  assert.equal(chooseRoute({ method: 'GET', path: '/api/admin' }, baseRules), 'admin');\n});\n\ntest('segment boundaries', () => {\n  const rules = [{ method: 'GET', prefix: '/api', target: 'api' }];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'api');\n  assert.equal(chooseRoute({ method: 'GET', path: '/api/' }, rules), 'api');\n  assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, rules), 'api');\n  assert.equal(chooseRoute({ method: 'GET', path: '/apix' }, rules), null);\n  assert.equal(chooseRoute({ method: 'GET', path: '/ap' }, rules), null);\n});\n\ntest('trailing slashes in prefixes are normalized, all-slash is root', () => {\n  const rules = [{ method: 'GET', prefix: '/api///', target: 'api' }];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'api');\n  assert.equal(chooseRoute({ method: 'GET', path: '/apix' }, rules), null);\n  const rootRules = [{ method: 'GET', prefix: '///', target: 'root' }];\n  assert.equal(chooseRoute({ method: 'GET', path: '/' }, rootRules), 'root');\n  assert.equal(chooseRoute({ method: 'GET', path: '/anything/else' }, rootRules), 'root');\n  assert.equal(chooseRoute({ method: 'GET', path: '/x' }, [{ method: 'GET', prefix: '/', target: 'r' }]), 'r');\n});\n\ntest('query and fragment are removed at earliest ? or #', () => {\n  assert.equal(chooseRoute({ method: 'GET', path: '/api?next=/api/admin' }, baseRules), 'api');\n  assert.equal(chooseRoute({ method: 'GET', path: '/api#/admin' }, baseRules), 'api');\n  assert.equal(chooseRoute({ method: 'GET', path: '/apix?/api' }, baseRules), null);\n  assert.equal(chooseRoute({ method: 'GET', path: '/api/admin#frag?q' }, baseRules), 'admin');\n  assert.equal(chooseRoute({ method: 'GET', path: '/api?q#/admin' }, baseRules), 'api');\n});\n\ntest('no URL decoding and no slash collapsing', () => {\n  const rules = [{ method: 'GET', prefix: '/api/admin', target: 'admin' }];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api%2Fadmin' }, rules), null);\n  assert.equal(chooseRoute({ method: 'GET', path: '/api//admin' }, rules), null);\n  assert.equal(chooseRoute({ method: 'GET', path: '/api//admin' }, baseRules), 'api');\n});\n\ntest('methods compare case-insensitively', () => {\n  const rules = [{ method: 'get', prefix: '/a', target: 'lower' }];\n  assert.equal(chooseRoute({ method: 'GET', path: '/a' }, rules), 'lower');\n  assert.equal(chooseRoute({ method: 'gEt', path: '/a/b' }, rules), 'lower');\n});\n\ntest('exact method beats longer wildcard; wildcard used only as fallback', () => {\n  const rules = [\n    { method: '*', prefix: '/api/admin', target: 'wild-admin' },\n    { method: 'GET', prefix: '/', target: 'get-root' },\n    { method: 'POST', prefix: '/other', target: 'post-other' },\n    { method: '*', prefix: '/api', target: 'wild-api' }\n  ];\n  assert.equal(chooseRoute({ method: 'GET', path: '/api/admin/x' }, rules), 'get-root');\n  assert.equal(chooseRoute({ method: 'POST', path: '/api/admin/x' }, rules), 'wild-admin');\n  assert.equal(chooseRoute({ method: 'POST', path: '/api/x' }, rules), 'wild-api');\n  assert.equal(chooseRoute({ method: 'POST', path: '/other/1' }, rules), 'post-other');\n  assert.equal(chooseRoute({ method: 'PUT', path: '/nothing' }, rules), null);\n});\n\ntest('ties go to earlier rule in input order', () => {\n  const rules = [\n    { method: 'GET', pref

4,096トークンという上限は、このテストのために設定された出力予算であり、特定のモデルの仕様書に記載された最大値ではありません。ルーティングの結果から、より大規模なリクエストを行う前に、実装、テスト、および返される説明のサイズを見積もるといった実用的な確認を行うことが推奨されます。 成果物を分割したり、出力スペースをさらに確保したりすることが適切である可能性があります。なお、これらの出力について、異なる設定で再実行は行っていません。.

ご自身の課題については、次の3つの点を個別に判断してください。レスポンスが完全かどうか、コードが有用なチェックに合格しているかどうか、そしてレビューによってそれらのチェックで見落とされた不備が見つかるかどうかです。12の関数チェックに合格したとしても、2つのファイルに断片化されたレスポンスはいずれも、完成した成果物とはみなされませんでした。.

どのモデルを選択するかによって、コストにどのような変化が生じるか

Claude Codeはコーディングツールであり、Haiku、Sonnet、Opus、Fableは、サポート対象環境内で選択可能なモデルです。認証方法や支払い方法も選択可能です。モデルを変更しても、サブスクリプションがAPIアカウントに変わるわけではなく、すべての利用制限が解除されるわけでもありません。.

請求ルート注目ポイントモデルの選択をどう解釈すべきか
Claudeのサブスクリプションアクセスプランに含まれる利用分および別途有効化された利用クレジット機種によって割当量の消費方法が異なる場合があります。プランで利用可能な機種と制限を確認してください。
Anthropic APIへのアクセス入出力トークン、キャッシュ、および適用されるAPI利用料現在の料金表と実際の利用状況に基づき、請求コンソールで請求額を確認してください
クラウドプロバイダーまたはゲートウェイご利用のプロバイダーが対応しているID、料金、および請求記録Anthropicの定価の例は、プロバイダーが請求する金額と一致しない場合があります
モデルの選択と課金は関連していますが、課金ルートによって利用量の課金方法が決定されます。.

Claudeコードでは、, /使用 セッショントークンの情報と、該当する場合はサブスクリプションの利用状況バーが表示されます。表示されている金額は、料金表または設定されたレートに基づいてローカルで算出された概算であり、請求書ではありません。ProおよびMaxプランの加入者にとって、このセッションの数値は、サブスクリプションに追加のAPI利用料が課金されたことを意味するものではありません。詳細については、 Claude コードの価格設定および請求ルート お支払い方法をお決めになる場合は。.

現在のAPI価格と等価トークンの例

Anthropicの入力/出力トークン100万単位あたりの通常基本料金は、以下の通りです。 Haiku 4.5: $1/$5; Sonnet 5: $2/$10; Opus 5.5: $4/$20; Fable 5.1: $10/$50, 、2026年9月28日確認。以下のグラフでは、計算の比較が容易になるよう、トークンの取引高を一定に保っています。.

同じトークン量で、4種類の異なるAPI料金

例 キャッシュされていない入力トークン 100,000 個 + 出力トークン 10,000 個, 、2026年9月28日時点で確認されたAnthropicの通常のAPI定価に基づいています。.

俳句 4.5$0.15
ソネット第5番$0.30
作品第5.5番$0.60
Fable 5.1$1.50
料金と計算方法を確認する
100万トークンあたりの米ドル額と計算例
モデル入力 / 1M出力 / 1M合計の例
俳句 4.5$1$5$0.15
ソネット第5番$2$10$0.30
作品第5.5番$4$20$0.60
Fable 5.1$10$50$1.50

計算式:0.1 × 入力レート + 0.01 × 出力レート。Opus 5.5の場合:0.1 × $4 + 0.01 × $20 = $0.60。.

これは固定トークン数の例です。実際のタスクでは消費されるトークン総数が異なります。キャッシュへの書き込みや読み取り、再試行、ツール、プロバイダーへの課金、およびサブスクリプションの制限については、別途集計する必要があります。.

ソース: Anthropic APIの価格設定.

AnthropicのAPI料金表(入力、出力、プロンプトキャッシュの各料金)。.
通常のAPI定価は100万トークンあたりで表示されており、キャッシュへの書き込みと読み取りにはそれぞれ異なる料金が適用されます。.

実際のClaudeコードタスクは、一連のリクエストで構成されます。以前のコンテキストが再度送信されたり、モデルがさらに調査を行ったり、ツールや追加のエージェントによってさらなる作業が発生したりする可能性があります。また、プロンプトのキャッシュには、書き込みレートと読み取りレートが明確に区別されています。したがって、この例における最も低いバーは、受け入れられた変更1件あたりの最低コストを示すものではありません。.

業務の質を損なうことなくコストを抑える5つの方法

  1. モデルを選択する前に、受け入れ条件を定義してください。. 想定される動作、エッジケース、および既存の制約条件を明記してください。明確で小規模なタスクほど、コスト効率よく委任しやすく、レビューも容易になります。.
  2. 関連する背景情報を提供してください。. モデルに必要なファイルや障害の詳細を記載してください。本件とは無関係な作業については、単に履歴が存在するという理由だけで長い履歴を引き継ぐのではなく、新しいスレッドを立ててください。.
  3. 「能力」と「努力」を区別すること。. Anthropicでは、まずモデルのデフォルトの処理レベルから始めることを推奨しています。文脈を正しく読み取ったにもかかわらず問題が解決できなかった場合は、より強力なモデルが役立つ可能性があります。読み取りや検証の段階をスキップしてしまった場合は、タスクの設定と処理レベルの選択を確認してください。.
  4. 回答全体の予算。. ソースコード、テスト、説明には、すべて表示スペースが必要です。2つ目の課題では、完全な関数があるだけでは、要求された成果物が予算内に収まっているという証拠にはならない理由が示されています。.
  5. 採択された作品を比較する。. 代表的なタスクについて、有用な出力、再試行回数、レビュー時間、および実際の課金データを記録してください。プロバイダーのエラーとモデルの品質に起因する失敗は区別して記録してください。.

これらの戦略は、以下のものと整合しています。 公式価格ガイド そして Anthropicのモデルおよび取り組みに関するガイダンス. プラン全体の週単位またはセッション単位の上限は、モデルを切り替えた後も引き続き適用される場合がありますが、モデルごとの上限については状況が異なります。繰り返し切り替える場合は、実際の上限を確認してください。.

もしあなたの仕事が、コーディング、研究、執筆、メディア制作など多岐にわたる場合は、そのために費用を支払っているワークフローも比較してみてください。. GlobalGPTのマルチモデルワークスペース これらの機能を1つのダッシュボードに統合し、開発タスク向けにCLIアクセスも提供します。こうした幅広いワークフロー上の価値は、従量課金制のAPIルートと併せて検討する上で有用です。なお、上記のAPIチャートは、GlobalGPTのサブスクリプション価格表ではありません。.

選択したモデルが定着しない理由

症状おそらく確認具体的な次のステップ
次のセッションでは、旧モデルが使用されますそのスイッチはセッション限定のものだった可能性がありますピッカーの「Enter」アクションを使用して保存し、新しいセッションを確認してください
設定は保存されるが、別のモデルが起動してしまう「ローンチ」、「シェル」、「プロジェクト」、「管理対象」、または「組織」の設定が優先される場合があります起動時の情報を確認し、その所有者とともに関連する設定を点検してください
再開された会話には別のモデルがあります保存されたセッションは、以前のモデルを復元できる場合があります/status を確認し、作業を再開する際は、慎重に目的のモデルを選択してください
モデルが見つからないか、拒否されましたプロバイダーの利用可能状況、組織のルール、または古いバージョンのClaudeコード対応しているモデルID、アカウントへのアクセス権限、およびバージョン要件を確認してください
同じ名字でも、場所によって解釈が異なるエイリアスとプロバイダーのマッピングが異なるリリースを固定する必要がある場合は、プロバイダーの正しい完全なIDを使用してください
スイッチングを行っても、使用制限はリセットされませんこの制限はプラン全体に適用される場合があります「ファミリースイッチ」だけで十分だと決めつけるのではなく、使用方法のメッセージをよく読み、期間をリセットしてください
他の設定を変更する前に、問題の範囲を特定してください。.

Claudeコードでユーザー設定を書き込めない場合、対話型の選択は現在のセッション中のみ有効となり、設定は永続化されません。管理対象または生成された設定ファイルについては、再度選択を試みるのではなく、所有者による変更が必要になる場合があります。単にオプションを表示させるためだけに、組織的な制限を解除することは避けてください。.

GlobalGPTでより広範なワークフローを構築する

モデル選択はワークフローの一部に過ぎません。ライブラリの調査、関数の草案作成、チームメイトへの変更点の説明、ドキュメントの作成、ビジュアルアセットの準備などが必要になる場合もあります。GlobalGPTは、複数の最先端モデルとAI機能を1つの手頃な価格のワークスペースに統合しているため、これらのタスクをすべて同じダッシュボード上で一元管理できます。.

端末での作業については、 GlobalGPT CLI このツールは、プラットフォームのツールを開発環境に連携させます。ドキュメントに記載されているセットアップ手順では、GlobalGPTアカウントのログイン情報と通常のアカウント残高を使用します。CLIは、より幅広いコーディングおよび作成ワークフローに対応可能ですが、Claude Code独自のモデルは、そのモデル制御機能を通じて意図的に選択されたままとなっています。.

たとえば、実装案を作成・検討し、簡潔な説明には別のモデルを用い、その後、リリースに付随するドキュメントや資産を作成します。ガイドに従って GlobalGPT CLI と Claude のコードを関連付ける そのツールの統合が必要な場合は、コーディングタスクに応じて、Claudeコード推論モデルを個別に設定してください。.

最初のモデルを選び、成功の基準となるチェック項目を書き出し、タスクの要件に応じて段階を上げていきます。作業を完了とする前に、成果物全体を精査してください。. GlobalGPTでワークフローを構築しましょう 日々の業務において、モデルの選択、調査、コーディング、そしてクリエイティブなツールを連携させたいとき。.

よくあるご質問

Claudeコードでモデルを変更するにはどうすればよいですか?

/model を実行してピッカーを開きます。s キーを押すと現在のセッションのみを切り替え、Enter キーを押すと選択したモデルをデフォルトとして保存します。単一の新しいセッションでモデルを選択するには、claude –model の後にモデル名を指定して起動してください。.

/model コマンドは、保存済みのデフォルト設定を変更しますか?

現在のインタラクティブ版では、Enterキーでモデルを選択するか、「/model sonnet」と入力すると、書き込み可能な状態であれば、その選択内容がユーザー設定に保存されます。ピッカーで「s」キーを押した場合の設定は、そのセッション中のみ有効です。次回起動時には、他の設定が優先される場合があります。.

デフォルトのClaudeコードモデルとは何ですか?

実行時のデフォルト値は、アカウント、プロバイダー、および設定によって異なります。このデフォルト値はモデルのオーバーライドをクリアするものであり、特定のモデル ID が固定されているわけではありません。すべてのアカウントが同じリリースから開始されると仮定するのではなく、/status コマンドでアクティブなモデルを確認し、ピッカーを調べてください。.

opusplanにはどのような機能がありますか?

プランモードではOpusを、実行モードではSonnetを使用します。各プロンプトに対して自動的に最も安価なモデルを選択するのではなく、モードの切り替えに従ってモデルを選択します。実際のコストは、各フェーズで実行される作業内容によって異なります。.

なぜピッカーにモデルが表示されないのですか?

利用可否は、プロバイダー、アカウント、組織の制限、およびClaudeコードのバージョンによって異なる場合があります。現在のモデルのドキュメントと、お使いの環境で許可されているモデルを確認してください。また、ファミリーエイリアスは、別のプロバイダーでは異なるリリースに解決される場合もあります。.

安価なモデルを選べば、その作業のコストも必ず安くなるのでしょうか?

いいえ。トークン価格はあくまで一つの要素に過ぎません。総使用量、不完全な回答、再試行、およびレビューの労力などが、許容可能な変更にかかるコストに影響を与えます。私たちの小規模なリファクタリングでは、3つの関数すべてが通過しましたが、2つのファイルからなる大規模なレスポンス3件はすべて、共有の出力制限により切り捨てられました。.

出典

記事を共有する

関連記事