Provider のルーティング ライフサイクル
ZeroClaw がターンを担当するエージェントを選択した後に、プロバイダーのルーティングが開始されます。これには、プロバイダープロファイルとモデルの選択、再試行とフォールバック、ストリームの復旧、およびリクエストを処理したバックエンドを示す帰属情報が含まれます。チャネルからエージェントへのディスパッチは別のライフサイクルです。チャネルランタイムのライフサイクル を参照してください。
変更が model_routes、セッションまたはターン内でのモデル選択、プロバイダーのフォールバック、リトライの分類、レート制限のクールダウン、ストリームの完了、ストリーム失敗後のリプレイ、または要求されたプロバイダーと実際に応答を提供したプロバイダーの帰属に関係する場合は、このページを参照してください。
所有権マップ
| 懸念 | 現在の所有者 | 契約 |
|---|---|---|
| プロバイダーのプロファイルとフォールバックグラフ | zeroclaw-config プロバイダーのスキーマと検証 | ドット区切りの <family>.<alias> は、1つのプロファイルのエンドポイント、認証情報、オプションのプライマリモデル、機能、および順序付けられたフォールバック宣言を識別します。 |
| プロバイダーの構築 | zeroclaw-providers ファクトリ関数 | 各プロファイルをそれぞれの設定で具体化し、設定されたフォールバックエントリを順序どおりにフラット化して、信頼性を軸にルーティングを構成します。 |
| ヒントベースの選択 | RouterModelProvider | hint:<name> を、設定されたプロバイダーターゲットとルーティングモデルに解決します。プライマリターゲットは、アクティブ/デフォルトモデルに固定されます。非プライマリターゲットは、そのプロファイルでモデルが設定されている場合に固定されます。設定されていない場合は、その信頼性エントリは固定されないままルーティングモデルを受け取ります。 |
| エフォートベースの選択 | Resolved runtime profile に加え、agent/channel のターンエントリポイント | 決定論的にオプトイン済みのターンを分類し、既存の2つのルートヒントのいずれかを選択し、明示的なモデル選択を維持して、そのターンで対象となるプロバイダーへの試行を制限する。 |
| 再試行とフェイルオーバー | ReliableModelProvider | 失敗を分類し、上限付きバックオフで再試行し、レート制限のクールダウン期間に従い、マテリアライズ済みエントリを順に処理します。 |
| プロバイダー ストリームの終了 | 具体的なプロバイダーと zeroclaw-providers/src/stream_guard.rs | 各プロバイダープロトコルの完了セマンティクスを、StreamEvent::Final または打ち切りエラーに変換します。 |
| ストリームの再生と部分出力の確定 | zeroclaw-runtime/src/agent/turn/provider_call.rs と stream_consume.rs | 不変のイベント出力がコミットされる前に限り、失敗したストリームを非ストリーミングとして再試行します。キャンセルされた応答や、部分的に表示された応答は決して再生しません。 |
| 呼び出しごとのアトリビューション | ProviderDispatch | 各試行で選択されたプロバイダー呼び出しの周囲にアトリビューションスコープを開きます。 |
| 復旧成功レコード | ReliableModelProvider | 回復に成功した後、タスクローカルな要求と提供の対応記録を1件公開する。イベント計測付きのターン経路では、usage_by_provider 台帳が、提供元の識別情報と accepted フラグを付けて、課金対象の試行を TurnEvent::Usage 経由で記録する。 |
| ユーザー向けの復旧通知 | ランタイムとチャネルのコンシューマー | 各自の出力サーフェスに、回復成功のレコードを表示します。コンシューマー間で通知ルールは一様ではありません。 |
構築と選択
ランタイムは、選択されたエージェント、セッションのオーバーライド、またはターン中の model_switch から、アクティブなプロバイダー参照とモデルを取得して開始します。次に、プロバイダーの構築で2つのラッパーを組み合わせます。
- ファクトリは、アクティブなプロバイダープロファイル用に
ReliableModelProviderを構築します。実効プライマリモデルは、明示的な構築時オーバーライドまたはプロファイルで設定されたmodelから決まります。いずれかが存在する場合、それとプロファイルのfallback_modelsは固定エントリになります。存在しない場合、プロファイルは固定されていないエントリを1つ提供し、そのfallback_modelsはエントリ化されません。再帰的に参照されるfallbackプロファイルも引き続き走査されます。参照される各プロファイルは、それぞれ独自の認証情報、エンドポイント、ヘッダー、モデル、機能オーバーライドを保持します。 model_routesを設定すると、ファクトリはプライマリルートと一意の各ルートターゲット用に個別の信頼性の高いプロバイダーを構築し、それらを RouterModelProvider でラップします。- 認識された
hint:<name>は、呼び出しがそのターゲットの信頼性ポリシーの適用対象になる前に、設定済みのターゲットを選択します。通常のモデル値ではデフォルトルートが使用されます。未知のヒントは警告をログに記録し、デフォルトの信頼性ドメインにとどまり、要求されたモデルとしてリテラルのhint:<name>を保持します。ピン留めされたデフォルトエントリは引き続きそのピンを提供します。ピン留めされていないデフォルトエントリはリテラル値を転送し、通常のフォールバックまたはエラー処理が続行される前に、プロバイダーがその値を拒否する場合があります。
現在、構築には 2 つの制約があります:
- ルートのピン留めは条件付きです。プライマリターゲットは、プロバイダーの構築時に渡されたアクティブなデフォルトモデルにピン留めされます。認識されたヒントがアクティブなプライマリプロファイルを指している場合も同様です。そのヒントの
model_routes[].modelの値によってプライマリのピン留めが上書きされることはありません。設定済みのプロファイルモデルを持つ非プライマリターゲットはそのモデルにピン留めされるため、ルートモデルによってプロファイルモデルが上書きされることもありません。設定済みのモデルを持たない非プライマリターゲットも有効で、ピン留めされないままになります。ルートモデルはそのプロバイダーに渡され、そのプロファイルのfallback_modelsは具体化されませんが、参照されているフォールバックプロファイルは引き続き走査されます。ピン留めが存在する場合は各ルートモデルをターゲットのピン留め先に合わせ、ターゲットプロファイルでmodelが省略されている場合のピン留めされない動作も考慮してください。 - ルートターゲットは
model_providerによって重複排除されます。ルートでapi_keyが指定されている場合、共有ターゲットの構築時には、最初に一致したルートの認証情報が優先されます。複数のヒントが1つのターゲットを共有する場合は、プロバイダープロファイルの認証情報を優先してください。
この順序が重要です。ルーティングは信頼性ドメインを選択しますが、信頼性を迂回するものではありません。OpenRouter のような外部ルーティングサービスは、単一の ZeroClaw プロファイルの背後でサーバー側の選択を行うこともできますが、これは任意であり、ZeroClaw のファーストパーティのルートおよびフォールバック契約に取って代わるものではありません。
解決済みのランタイムプロファイルに effort_routing が設定されている場合、ターンのエントリポイントはプロバイダーの実行前に決定論的な複雑度推定器を実行します。単純および標準的なターンでは、設定済みのローカルヒントが選択されます。複雑なターンは、明示的な auto エスカレーションポリシーの下でのみクラウドヒントを選択します。分類のためのモデル呼び出しは行われず、決定テレメトリにはプロンプトのテキストは含まれません。明示的なオペレーターによる CLI、セッション、チャネルの選択は、該当するスコープにおいてこの自動ステップを無効にします。チャネルの /model auto はこれを復元します。モデルが発行する model_switch は、ルートが自動かオペレーター所有かを変更することなく、アクティブなプロバイダー/モデルを変更します。そのため、オペレーターによるオーバーライドで既に無効化されていない限り、モデルが発行したスイッチの後も自動の effort routing は有効なままです。
プロバイダー境界は、モデルの選択だけでなく、この決定そのものも強制します。構造化されたエージェントおよびチャネルのパスは、タスクローカルの許可リストを設定します。この許可リストは、非ストリーミング、ストリーミング、ストリーム回復のパスを含むすべての Reliable 候補ループでチェックされます。CLI およびデーモンの直接のエントリポイントは、許可されたルートターゲットのみからターンルーターを構築します。したがって、ローカルの決定が可用性フォールバックを通じて設定済みのクラウドプロバイダーへ越えてしまうことはありません。クラウドの決定では、設定済みのローカルおよびクラウドのプロバイダー参照の両方を使用できます。
運用担当者向けのスキーマと例は、プロバイダー設定およびルーティングにあります。フィールド構文はアーキテクチャドキュメントに重複して記載せず、そちらに記載してください。
非ストリーミングの試行順序
本番用エイリアスの場合、ファクトリは構成されたグラフを深さ優先でフラット化します。実際の順序は次のとおりです:
- プロファイルの有効なプライマリモデル、または有効なプライマリモデルが存在しない場合は、ピン留めされていないエントリを1件。
- 有効なプライマリモデルが存在する場合にのみ、そのプロファイルの
fallback_modelsを順番に使用します。 - 各
fallbackプロファイルを順に、そのプロファイル自身のプライマリまたはピン留めされていないエントリ、対象となるフォールバックモデル、ネストされたフォールバックプロファイルを含めて。
各マテリアライズ済みエントリについて、ReliableModelProvider はリクエストを最大 provider_retries + 1 回試行します。再試行可能なエラーでは通常そのエントリにとどまり、上限付きバックオフを適用します。再試行可能なレート制限が発生すると、そのプロバイダープロファイルをメモリ内のクールダウン状態に設定し、別のエントリが存在する場合は次へ進みます。ほとんどの再試行不可能なエラーでは直ちに次へ進みます。コンテキストウィンドウエラーにはメソッド固有の処理があり、ランタイムの復旧のために早期に返る場合があります。成功したレスポンスで走査を終了し、すべてのエントリが失敗した場合、ラッパーは各試行の失敗を含む集約エラーを返します。
レート制限後は、マテリアライズの順序と実効実行順序が異なる場合があります。プロファイルのプライマリモデルと fallback_models エントリは1つのクールダウンキーを共有するため、プライマリで 429 が発生すると、クールダウンが有効な間、同じプロファイルに残っているモデルがスキップされることがあります。
グローバルな reliability.api_keys プールは、現時点では機能するフェイルオーバー機構ではありません。ラッパーは再試行可能なレート制限の発生後に代替キーを選択してログに記録しますが、ModelProvider trait は構築されたプロバイダーにそのキーを適用できないため、再試行でも元の認証情報が使用されます。Issue #9190 で修正が追跡されています。認証情報レベルのフェイルオーバーが必要な場合は、個別のフォールバックプロファイルまたは外部ルーティングサービスを使用してください。
空の補完は、直ちに空のアシスタントターンになるのではなく、同じ上限付きの再試行処理を受けます。
無効なフォールバック宣言には、異なる2つの境界があります。解決不能な参照、循環、深さ超過のエッジ、空のモデル ID、重複するプライマリーモデルは、プロバイダー設定で説明されているとおり報告され、除去されます。解決はできても、必要な認証情報を提供できない、または構築できないフォールバックプロファイルは、ルートを暗黙に変更するのではなく、プロバイダーの初期化に失敗します。
ストリーミングとリプレイの境界
ストリーミングの再試行契約は、非ストリーミング呼び出しより意図的に狭く設定されています:
ReliableModelProviderは、要求されたストリーム機能をサポートし、クールダウン中でない最初の順序付きエントリを選択します。- そのストリームを一度だけ開きます。ストリームの開始後にエントリを切り替えることはありません。
- 具体的なプロバイダーパーサーは、プロトコルの完了セマンティクスを
Finalまたはエラーに変換します。ほとんどのガード付きSSEパーサーでは、設定された完了シグナルが必要です。Anthropic は現在、空でないmessage_delta.stop_reasonの後に EOF に到達した場合、message_stopが観測されていなくても完了として扱います。PR #9447 はmessage_stopを必須にすることを提案していますが、その変更はまだ反映されていません。 - ランタイムはストリームイベントを消費してサニタイズします。ストリームが不変のイベント出力を確認できるようになる前に失敗した場合、ランタイムは非ストリーミングパス経由で呼び出し全体を再試行し、完全な信頼性処理フローに再度入ります。
- テキスト、推論、または実行前のツールイベントがすでに不変のイベントシンクに到達している場合、中断は
StreamInterruptedAfterOutputになります。ランタイムはリクエストを再実行しません。コンシューマーにすでに転送されたテキストのみが、永続化された部分的なアシスタントテキストになります。 - キャンセルがプロバイダーによる自動再試行になることはありません。転送されたテキストの前にキャンセルすると、ターンは中止されます。転送されたテキストの後にキャンセルすると、その部分的なアシスタントテキストは保持されます。推論のみの出力やツール実行前の出力は、それだけではキャンセル時に保存される部分的なアシスタントテキストにはなりません。
ドラフト更新シンクは可変です。pre-commit フォールバックでは、不変の出力を複製することなくドラフトを置き換えられます。一方、イベントシンクはリプレイを行わない境界を定義します。
最終テキストもツール呼び出しもないまま完了したストリームは、意味的に空の応答であり、成功した回答ではありません。ランタイムがその結果を再実行安全(replay-safe)としてマークし、かつprovider_retriesが0以外の場合、Reliableは、空のストリームを生成したまさにそのprovider/modelに対して、ノンストリーミングの回復呼び出しを1回許可します。この許可は1回で消費されます。回復が失敗した場合は、残りの設定済み候補に、それぞれの通常のリトライ予算を使って進みます。リトライ回数が0の場合、失敗したストリームのエントリはスキップされたままになりますが、それが唯一の候補である場合は例外として、同じエントリに対してノンストリーミングの回復試行を1回許可します(これは再実行ではなく回復です)。この単一候補の許可も1回で消費されます。両方の許可が同じエントリに適用される場合は、1回の単一の試行にまとめられます。既に表示された推論は1回だけ表示されたまま残りますが、最終回答としては扱われません。この例外は、キャンセル後、中断された可視出力の後、またはプロバイダーが実行したツール処理の後の再実行を許可するものではありません。
この分担により、トランスポートの復旧はランタイムに、プロバイダー固有のフレーミングはアダプターに、再試行/フォールバックのポリシーは信頼性ラッパーに保持されます。プロバイダー実装では、別のターンレベルのリプレイポリシーを作り出すべきではありません。
帰属表示と既知の不足事項
ProviderDispatch は各プロバイダー呼び出しの周囲でアトリビューションを開始します。ReliableModelProvider は、非ストリーミング呼び出しが成功するか、フォールバックストリームがエラーなしで完了した後にのみ、要求されたフォールバックと実際に提供されたフォールバックを記録します。ランタイムとチャネルのコードは、そのタスクローカルな記録を使用して、リカバリが発生したことをユーザーに伝えられます。
このレコードは、ファミリー/モデルの復旧ヒントにすぎません。本番環境のエントリーでは、プロバイダーファミリーを display_name として使用するため、レコードからドット区切りのプロファイルエイリアスが失われる可能性があります。そのため、エイリアス間の同一ファミリー・同一モデルへのフォールバックは、要求されたルートと区別できない場合があります。レコードが異なる場合、ランタイムのレスポンスにはモデル/プロバイダーのフォールバック通知が追記されます。チャネル配信では、ファミリーをまたぐフォールバックのフッターは保持され、同一ファミリーだが異なるモデルへの通常のフォールバックには channels.model_fallback_notice が使用されます。グローバルモードは、デフォルトでは off、ルーティング識別子を含まない redacted、要求されたプロバイダー/モデルと実際に応答したプロバイダー/モデルの識別子を含む detailed です。設定と閲覧者のプライバシーに関するトレードオフについては、モデルフォールバック通知 を参照してください。
The channel orchestrator resolves this policy from the current live Config at outbound delivery rather than snapshotting it into a long-lived channel handle. 既存の設定公開・リロード経路は、実行中のデーモンに変更を適用します。通知はassistantの応答が履歴に入った後でアウトバウンドコンテンツに付加されるため、プロンプト履歴にはならず、サービング試行の記録も変更しません。Safeguard通知は、従来どおり個別の動作を維持します。
イベント計測対象のターン経路では、試行ごとの会計処理は usage_by_provider 台帳で行われ、そのレコードでは行われません。これらの経路で課金対象となるすべての試行は、受理されたものか拒否されたものかを問わず、提供元のprovider_ref/modelとacceptedフラグを含むTurnEvent::Usageを発行します。ゲートウェイの完了フレームは、台帳の合計としてcost_usdを導出します。イベントシンクを持たないスタンドアロンの単発クエリ(スキル振り返りを含む)は、この台帳に登録されずにコスト追跡される場合があります。これはissue #9470を解決します(ストリーム復旧後に、拒否された試行や古いフォールバック通知をまたいで使用量とコストが誤って割り当てられる問題)。試行ごとのコストの正確性を、最終的なフォールバック通知や要求されたプロバイダーの識別情報だけから推測しないでください。台帳を参照してください。
コンテンツ拒否およびセーフガードのフォールバックは、トランスポートの信頼性とは別に提案されているコントラクトです。Tracker #9293 は、provider、configuration、channel、gateway、web の各サーフェスにまたがるこの作業を調整しています。PR #8966 におけるサービング識別情報および試行ごとの台帳の作業は、Reliable のコスト帰属のギャップを解消します。コンテンツ拒否のフォールバックは引き続き別途追跡されています。
変更チェックリスト
プロバイダー ルーティングの変更について、レビュアーの承認前に以下に回答してください:
- この変更は、エージェントのディスパッチ、ヒントの選択、信頼性フォールバック、または外部ルーターに影響しますか。それぞれの決定について、担当者を1人だけ指定してください。
- ヒントがいずれかのプロバイダープロファイルを対象とする場合、そのモデルの扱いはターゲットの構築方法と一致していますか?プライマリターゲットをアクティブ/デフォルトのピンと比較します。非プライマリターゲットに構成済みのモデルがある場合は、ルートモデルをそのピンと比較します。プロファイルで
modelが省略されている場合は、ルートモデルがそのまま渡され、プロファイルのfallback_modelsが実体化されないことを確認します。 - すべてのフォールバックプロファイルは、それぞれ独自のエンドポイント、認証情報、モデル、ヘッダー、機能のオーバーライドを保持しますか?
- 何が再試行可能で、何が直ちに進み、再試行回数を使い果たした後にどのエラーが返されますか?
- ユーザーまたは不変コンシューマーがすでに観測した出力があっても、リクエストをリプレイできますか?
- 各プロバイダーのパーサーは、完了としてどの正確なシグナルを受け付けますか?そのシグナルの前にEOFが発生した場合、切り詰められたものとして失敗しますか?
- 要求されたプロバイダー/モデルの識別情報と、実際に提供されたプロバイダー/モデルの識別情報は、別々に保持されますか?
- 使用量、コスト、ログ、ユーザー通知は同じサービング試行に基づくものですか、それとも制限が明示的に追跡されていますか?
- ストリーミングテストと非ストリーミングテストは、動作が一致する想定の同じ失敗境界をカバーしていますか?
ソースポインタ
- Provider トレイトとストリームイベント:
crates/zeroclaw-api/src/model_provider.rs - ルート選択:
crates/zeroclaw-providers/src/router.rs - プロファイルごとのモデル固定:
crates/zeroclaw-providers/src/model_pin.rs - 再試行、クールダウン、フォールバック、およびフォールバック通知:
crates/zeroclaw-providers/src/reliable.rs - プロバイダーの構築とフォールバックグラフの実体化:
crates/zeroclaw-providers/src/lib.rs,crates/zeroclaw-providers/src/factory.rs - プロバイダーのストリーム完了ガード:
crates/zeroclaw-providers/src/stream_guard.rs - ランタイムストリームのリプレイと部分出力の処理:
crates/zeroclaw-runtime/src/agent/turn/provider_call.rs,crates/zeroclaw-runtime/src/agent/turn/stream_consume.rs - オペレーターガイド: プロバイダー設定、ルーティング、ストリーミング