コンテンツにスキップ

コンボ: フェイルオーバーとロードバランシング

コンボ は、実際のプロバイダー/モデル ターゲットの順序付きリストの先頭にある 1 つの仮想モデルです。クライアントは combo/<id> をリクエストします。 opencodex はターゲットを選択し、リクエストをその具体的な provider/model に書き換えます。最初のターゲットで再試行可能な障害が発生した場合は、別のターゲットを試行できます。

これは、次のいずれかが必要な場合に便利です。

  • フェイルオーバー: 1 つのモデルを推奨しますが、バックアップを準備しておいてください。
  • 負荷分散: 成功したリクエストを重み付けされたバッチでモデルまたはプロバイダー全体に分散します。

コンボは、通常のプロバイダー ルーティングの前に配置されます。 provider/model セレクターを初めて使用する場合は、まず モデルルーティング をお読みください。

この例では、最初に Anthropic、2 番目に OpenAI を使用して combo/main を作成します。両方のプロバイダーがすでに存在し、有効になっている必要があります。

Terminal window
ocx combo set main --targets anthropic/claude-opus-4-8,openai/gpt-5.6-sol

デフォルトの戦略はフェイルオーバーであるため、通常のリクエストは anthropic/claude-opus-4-8 に送信されます。その試行に再試行可能な失敗があった場合、opencodex は openai/gpt-5.6-sol にホップできます。

通常モデル ID を指定する場所であればどこでも仮想モデルを使用します。

{
"model": "combo/main",
"input": "Explain why the sky looks blue."
}

保存された定義を確認します。

Terminal window
ocx combo show main

ocx combo set <id> のコンボ ID は文字または数字で始まる必要があります。文字、数字、._、または - を合計 64 文字まで含めることができます。その正規モデル ID は常に combo/<id> です。たとえば、ID maincombo/main になります。

combo/ 名前空間は、コンボの構成中に予約されます。 combo という名前のプロバイダーはそれを占有することはできず、コンボ ID は構成されたプロバイダー名を複製することはできません。

オプションのエイリアスにより、コンボに別のパブリック モデル名が与えられます。別名:

  • ID と同じ文字を使用します。
  • daily-fast のように裸の場合もあれば、team/daily-fast のように / を 1 つ含む場合もあります。
  • combo にしたり、combo/ で始めることはできません。
  • 別のコンボ エイリアスを複製することはできません。そして
  • 通常、gpt-o1-o3-o4-、または codex- で始まる bare native OpenAI family 名は使用できません。明示的な nativeAlias: true Desktop 互換モードだけが例外です。

エイリアスが設定されている場合でも、正規の combo/<id> 形式は解決されます。正規ルックアップはエイリアスの一致の前に実行されるため、エイリアスが別のコンボの正規 ID を引き継ぐことはできません。

フェイルオーバー: 順序付けされたプライマリとバックアップ

Section titled “フェイルオーバー: 順序付けされたプライマリとバックアップ”

failover は、構成順序で最初の適格なターゲットを選択します。ターゲットは、プロバイダーが存在し、有効になっていて、クールダウン中でなく、特別なリクエスト制約を処理できる場合に適格となります。重みと stickyLimit はこの戦略に影響しません。

この順序を考慮すると、次のようになります。

  1. anthropic/claude-opus-4-8
  2. openai/gpt-5.6-sol
  3. google/gemini-3-pro

各リクエストは Anthropic で始まります。再試行可能な Anthropic エラーが発生すると、そのリクエストは OpenAI に移動します。再試行可能な OpenAI が失敗すると、OpenAI が Google に移される可能性があります。端末エラーは、残りのターゲットを試行する代わりに、ただちに停止します。

ラウンドロビン: スムーズな加重バッチ

Section titled “ラウンドロビン: スムーズな加重バッチ”

round-robin はスムーズな加重ラウンドロビンを使用します。ターゲットの重みが大きいほど、すべてのシェアを 1 つの長いブロックとして送信することなく、時間の経過とともにそのターゲットに大きなシェアが与えられます。 stickyLimit は、次の重み付けされた選択の前に、選択されたターゲットに残る成功したリクエストの数を制御します。

成功した 2 つのリクエストのバッチを含む 2:1 コンボを作成します。

Terminal window
ocx combo set balanced \
--targets anthropic/claude-opus-4-8:2,openai/gpt-5.6-sol:1 \
--strategy round-robin \
--sticky 2

ターゲットを A (重み 2) および B (重み 1) と呼ぶと、最初の 6 つの重み付き選択は A, B, A, A, B, A になります。 stickyLimit は 2 であるため、各選択は 2 つのリクエストが成功した場合にアクティブのままになります。

|リクエストが成功しました | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | | — | — | — | — | — | — | — | — | — | — | — | — | — | — | |ターゲット |あ |あ | B | B |あ |あ |あ |あ | B | B |あ |あ |

長期的なシェアは依然として2:1です。再試行可能な障害が発生すると、現在のスティッキー バッチが終了し、そのターゲットが冷却され、同じリクエストに対して別の適格なターゲットが選択されます。

random: リクエストごとの加重抽選

Section titled “random: リクエストごとの加重抽選”

random は、リクエストごとに適格なターゲットを 1 つ、weight に比例する確率で抽選します。各リクエストは独立した抽選となるため、round-robin の決定論的なパターンや固定性なしに、複数のターゲットへトラフィックが分散されます。stickyLimit はこの戦略に影響しません。

least-used: 成功数が最も少ないターゲットを優先

Section titled “least-used: 成功数が最も少ないターゲットを優先”

least-used は、この opencodex プロセスに記録された成功リクエスト数が最も少ない適格なターゲットへ、各リクエストをルーティングします。再起動時にカウントはゼロから始まり、同数の場合は構成順序が維持されます。weightstickyLimit はこの戦略に影響しません。

reset-window: 最も早いクォータリセットに従う

Section titled “reset-window: 最も早いクォータリセットに従う”

reset-window は、キャッシュされたプロバイダーのクォータスナップショットで、次回のウィンドウリセット(5 時間、週次、月次、またはカスタム)が最も早い適格なターゲットへ、各リクエストをルーティングします。これにより、最初にクォータが補充されるプロバイダーを先に使用します。新しいクォータデータがないターゲットと、リセット時刻が同じターゲットでは、構成順序が維持されます。weightstickyLimit はこの戦略に影響しません。

この順位付けと送信前のプロバイダー除外には、現在の単一 API キー全体に適用される最新のモデル推論制限が必要です。OAuth/現在のアカウントの概要、呼び出し元の認証情報を転送するルート、複数キー、認証情報や送信先が変わったスナップショットは、この事前判断では表示専用です。Authorizationx-api-keyx-goog-api-key ヘッダーで認証情報を上書きする場合も同様で、検索専用および MCP 専用ウィンドウは対象外です。適用可能なリセット情報を持つ適格な対象がなければ、設定順序を使用します。アカウント選択と再試行には引き続き通常の制限が適用されます。

ターゲットが失敗すると何が起こるか

Section titled “ターゲットが失敗すると何が起こるか”

コンボ障害は、ホップ 障害と ターミナル 障害に分類されます。

結果 行動
HTTP 401、403、404、408、429、または任意の 5xx ターゲットを冷却し、次の適格なターゲットに移動します。
モデルのサポート終了、retired、deprecated、sunset、decommissioned、または利用不可を明示する HTTP 410 そのターゲットをクールダウンし、次へ進みます。無関係な 410 はターミナル エラーのままです。
機密認証、サブスクリプション、クォータ、レート制限、過負荷、またはアップストリーム サーバー エラー ステータスだけでは物足りない場合でもターゲットを冷やしてホップさせましょう。
クライアントのキャンセル (499)、origin_rejected、サイバー ポリシーの拒否、コンテキスト オーバーフロー、またはその他の無効なリクエスト 停止してエラーを返します。別のターゲットではリクエストは有効になりません。
user の明示的な拒否、reasoning.effort/reasoning_effort の非対応値、またはモデル固有の画像入力拒否(param: input)を示す構造化 HTTP 400 出力開始前に次の適格なターゲットへ進み、クールダウンを記録しません。任意パラメーターの互換性を参照してください。
その他の未分類のエラー 停止してエラーを返します。

cooldownMs が未設定の場合、ホップされたターゲットはアップストリームのフォールバックを使用します。アップストリームコード 1302 または 1305 を伴うリクエストレート 429 では 5 秒、それ以外では 60 秒です。設定されている場合、使用可能なアップストリームの Retry-After または Codex リセットシグナルが存在しないときは、これらのリクエストレート 429 を含め、cooldownMs が適用されます。数値の Retry-After 秒数と HTTP-date 値が受け入れられ、すべてのクールダウンは 10 分を上限とします。優先順位は強い順に、明示的な Retry-After → Codex リセットヘッダー(x-codex-primary-reset-atx-codex-secondary-reset-at、または x-codex-tertiary-reset-at)→ コンボの cooldownMs(設定時)→ アップストリームのレート制限コード 1302/1305 に対する 5 秒のリクエストレート フォールバック → 60 秒のデフォルトです。有効な即時指定 Retry-After: 0 は、設定されたクールダウンで置き換えられず、即時のアップストリーム指示として維持されます。

現在のリクエストは、同じ試行ターゲットを再試行しません。後続のリクエストでは、クールダウンが期限切れになるまでそのターゲットをスキップします。すでに過去の時刻である Retry-After の HTTP-date も、Retry-After: 0 と同様に即時のアップストリーム指示として維持されます。waitForCooldownMs を設定すると、後続のリクエストは、最も早く利用可能になるターゲットのクールダウンを、その選択試行ごとにこの上限まで待ってから、新たに 1 回選択できます。したがって、複数のフェイルオーバー ホップをまたぐリクエストは合計で hops × waitForCooldownMs まで待つ場合があります。デフォルトは 0 です。適格なターゲットがすべて冷却中の場合、HTTP 503 ですぐにフェイルクローズし、その combo_unavailable 503 には最も早く終了する残りのクールダウンと等しい Retry-After ヘッダーが含まれ、秒単位に切り上げられ、最小値は 1 秒です。待機にはジッターがないため、同期したウェイクアップが発生する可能性があります。中止されたリクエストはこの待機をキャンセルし、通常の client_cancelled 応答を返します。キャンセル後にバックアップ ターゲットをディスパッチすることはありません。コンボ ターゲットのクールダウンはプロセス ローカルなコンボごとの状態であり、ネイティブ アカウント ルーティングで使用されるアカウントレベルの Codex クォータ クールダウンとは別です。

ストリーミング リクエストでは、アップストリームの HTTP ステータスだけで最終判断しません。OpenCodex は、選択した子ターゲットの Responses SSE を出力開始前の上限付き範囲だけバッファします。テキスト、推論、ツール呼び出し、またはその他の出力イベントが始まる前に再試行可能な response.failed ターミナルを受け取った場合、その子を失敗として記録し、次の適格なターゲットを試せます。出力が始まるかバッファ上限に達した時点で現在のターゲットにコミットし、その後のストリーム失敗を別プロバイダーへ再送しません。これによりテキストやツール実行の重複を防ぎます。

defaultEffort は、コンボの既定値が null でなく、対象の対応リストが既知で空でない場合に、省略された reasoning.effort を補います。設定値に対応していればその値を使い、そうでなければ設定値以下で最も高い段階を選びます。それもなければ最も低い対応段階を使います。不明または空のリストでは既定値を省略します。

既定値の補完は既存の effort と他の reasoning フィールドを保持します。以下の capability 正規化は、別途、非対応の effort/thinking 制御を削除できます。設定可能な既定値は lowmediumhighxhighmaxultra です。省略または null で補完を無効にします。

異なる reasoning capability の組み合わせ

Section titled “異なる reasoning capability の組み合わせ”

reasoningEffortMode の既定値は "strict" です。明示的な空リストを含む全対象の effort リストの共通部分を公開します。"adaptive" は空リストを共通部分の計算から除外し、混在するコンボでも選択肢を維持します。不明なリストは、どちらのモードでもカタログの共通部分を制限しません。

送信時には、明示的な空リストの対象で effort と thinking の制御を両モードとも削除します。不明な対象で削除するのは adaptive のみです。reasoning.summary と effort 以外のフィールドは保持し、既知の空でない対象は従来どおり effort を解決します。strict の不明な対象と通常の native Chat の不明な宣言は保持します。既定値の補完は既存の effort を上書きしませんが、この正規化は非対応の制御を削除できます。

暗号化された v2 サブエージェント タスク

Section titled “暗号化された v2 サブエージェント タスク”

Codex v2 サブエージェントには重要な制限が 1 つあります (第92号)。ネイティブの親は、新しく生成されたワーカーのタスクを、ネイティブ ChatGPT バックエンド用に作成された暗号文としてのみ送信できます。外部プロバイダーはそのペイロードを読み取ることができません。

このようなリクエストの場合、コンボは、再試行可能な失敗後も含め、対象となるターゲットを正規のネイティブ ChatGPT ルートにフィルタリングします。コンボに復号化可能なターゲットがない場合、opencodex はディスパッチ前に停止し、HTTP 400 を返します。

{
"error": {
"type": "invalid_request_error",
"code": "unreadable_encrypted_agent_task"
}
}

これにより、読み取り可能な命令を受け取らないプロバイダーにタスクが送信されることがなくなります。読み取り可能なプレーンテキストのタスクは、通常のコンボ戦略を使用します。

回復オプションは 4 つあります。

  1. 子用のネイティブ ChatGPT モデルを選択します。
  2. 正規のネイティブ ChatGPT ターゲットをコンボに追加します。
  3. さまざまなプロバイダー間の委任には v1 サーフェスを使用します。
  4. 呼び出し元を制御している場合は、タスクをプレーンテキスト v2 agent_message コンテンツとして再送信します。

v1/base/v2 モードと完全な暗号化タスクのワークフローについては、サブエージェントサーフェス を参照してください。

ローカル ダッシュボードを開き、Models → コンボを選択します。ワークスペースはコンボを作成、編集、名前変更、削除し、そのターゲット ピッカーは無効なモデルとネストされたコンボを除外します。

各ターゲットには 利用可能クォータを使い切りましたクォータ不明 のライブバッジも表示されます。 エディターがクォータを理由に保存と作成をブロックするのは、使用可能なすべてのターゲットについて、設定された認証情報の推論上限に達したことを示す、サーバーによる確認が現在も有効な場合だけです。表示専用のアカウント・モデル・検索・MCP クォータや、ルーティングの根拠情報の欠落・期限切れによって、このブロックが発生することはありません。ブロックは該当するリセット時刻またはデータの有効期限に解除され、ページがアクティブになるか表示状態になると再確認されます。「更新」はコンボデータとクォータの両方を再読み込みします。ダッシュボードのエディターではまだ cooldownMswaitForCooldownMs を設定できません。後続の UI 作業が完了するまでは、構成ファイルまたは管理 API を使用してください。

主なコマンドは次のとおりです。

Terminal window
ocx combo list
ocx combo show <id>
ocx combo set <id> --targets provider/model[:weight],...
ocx combo remove <id> --yes

set は、--strategy--sticky--effort--alias--native-alias--display-name、および --rename-from も受け入れます。--native-alias には現在 サポートされている bare native alias と空でない display name が必要です。--effort--alias--display-name- を指定すると、その値をクリアできます。create および updateset の エイリアス、deleteremove のエイリアスです。すべてのコンボ サブコマンドは ocx route combo ... からも利用できます。

ヘッドレス クライアントは、/api/combos 上の GETPUT、および DELETE を使用します。 GET は正規化されたコンボ定義をリストし、PUT は 1 つを作成または置換し (名前を変更できます)、DELETE は id クエリ パラメーターを受け取ります。認証と要求/応答の詳細は 管理 API リファレンス にあります。PUT 本文で cooldownMs または waitForCooldownMs のいずれかを省略すると、そのコンボに保存済みの値が維持されます。変更するには明示的な値を指定してください。明示的な cooldownMs60000 でも)はリクエストレート フォールバックを上書きするため、そのまま永続化されます。保存済みの cooldownMs を削除できるのは構成ファイルを編集した場合だけです。waitForCooldownMs は、PUT0 を明示的に指定するとデフォルトに戻ります。これはスパース シリアライザーがそのデフォルト値を省略するためです。省略すると両方の値が維持され、ダッシュボードではまだどちらも設定できません。

永続化された設定全体については、「構成」を参照してください。

コンボは、コンボ ID をキーとして、最上位の combos オブジェクトに保存されます。

{
"combos": {
"balanced": {
"targets": [
{ "provider": "anthropic", "model": "claude-opus-4-8", "weight": 2 },
{ "provider": "openai", "model": "gpt-5.6-sol", "weight": 1 }
],
"strategy": "round-robin",
"stickyLimit": 2,
"defaultEffort": "high",
"alias": "team/balanced"
}
}
}
フィールド 必須 デフォルト ルール
targets はい 構成された { provider, model, weight? } ターゲットの空でない順序付けされた配列。重複するプロバイダーとモデルのペアは拒否されます。
targets[].weight いいえ 1 1 ~ 10,000 の整数。round-robinrandom で使用され、failoverleast-usedreset-window では無視されます。
strategy いいえ "failover" "failover""round-robin""random""least-used""reset-window"
stickyLimit いいえ 1 round-robin の 1 回の選択あたり、成功したリクエスト数を指定する 1 ~ 100 の整数。round-robin にのみ適用されます。
cooldownMs いいえ 未設定 → アップストリーム フォールバック(リクエストレート 429 コード 1302/1305 では 5 秒、それ以外では 60 秒) 1 ~ 600000 の整数。設定時は、使用可能なアップストリーム Retry-After または Codex リセットシグナルがない場合に、リクエストレート 429 を含むターゲットごとのクールダウンとして適用されます。未設定時はアップストリーム フォールバックを使用します。
waitForCooldownMs いいえ 0 0 ~ 600000 の整数。最も早く利用可能になる冷却中のターゲットを待ってから combo_unavailable を返すまでの最大待機時間。中止すると待機はキャンセルされます。
defaultEffort いいえ null lowmediumhighxhighmax、または ultra;呼び出し元が努力を省略し、ターゲットがサポートをアドバタイズした場合にのみ適用されます。
reasoningEffortMode いいえ "strict" strict または adaptive。混在する capability の共通部分と対象別の制御正規化を選択します。
alias いいえ なし オプションのトリミングされたパブリック モデル ID。上記のエイリアス ルールを使用します。空の値はエイリアスなしで保存されます。
nativeAlias いいえ false 現在サポートされている bare native alias に routing/catalog の優先権を明示的に与えます。
displayName いいえ なし catalog 表示専用ラベル。nativeAlias が true の場合は必須です。

combo/<id> が 404 を返すのはなぜですか?

Section titled “combo/<id> が 404 を返すのはなぜですか?”

コンボIDは不明です。応答はタイプ invalid_request_error の HTTP 404 です。 ocx combo list を実行し、スペルと大文字小文字を確認して、モデル要求を受信する同じ実行中の opencodex インスタンスに管理コマンドが書き込まれたことを確認します。

combo_unavailable が発生するのはなぜですか?

Section titled “combo_unavailable が発生するのはなぜですか?”

現在、すべてのターゲットは不適格です。たとえば、プロバイダーが無効になっている、冷却中である、このリクエストに対してすでに試行されている、暗号化された v2 タスクによってターゲットが除外されているなどです。ターゲットプロバイダーの状態と最近のアップストリームエラーを確認してください。クールダウンでは、まずレスポンスで確認できる Retry-After の値に従ってください。Codex のリセットヘッダーも cooldownMs より優先され、どちらのアップストリームシグナルも使用できない場合は、設定した cooldownMs、未設定ならアップストリーム フォールバック(リクエストレートコード 1302/1305 では 5 秒、それ以外では 60 秒)が適用されますが、いずれのクールダウンも 10 分を超えません。

私のエイリアスが拒否されたのはなぜですか?

Section titled “私のエイリアスが拒否されたのはなぜですか?”

まず、エイリアスの文法と予約名を確認してください。重複したエイリアスまたは無効な形状は、HTTP 400 として拒否されます。最初のセグメントが構成済みの Codex アカウント名前空間であるスラッシュ付きエイリアスは、HTTP 409 として拒否されます。別のエイリアス名前空間を選択してください。 CLI とダッシュボードには、サーバーの正確な検証メッセージが表示されます。

最初のエラーの後にフェイルオーバーが停止したのはなぜですか?

Section titled “最初のエラーの後にフェイルオーバーが停止したのはなぜですか?”

このエラーはターゲット固有のものではなく、最終的なものでした。無効な入力を修正し、大きすぎるコンテキストを削減し、ポリシーの拒否を処理し、拒否されたリクエストの送信元を修正します。コンボはそのような場合には機能しません。

通常の 400 エラーは終了扱いですが、user の明示的な拒否、reasoning.effort/reasoning_effort の非対応値、またはモデル固有の画像入力拒否(param: input)を示す構造化エラーでは、出力開始前に次の適格なターゲットへ進めます。この不一致ではクールダウンを記録しません。安全ポリシーによる拒否、キャンセル、出力開始後の再実行は禁止のままです。

Canonical compatibility details.