Provider のルーティング ライフサイクル
ZeroClaw がターンを担当するエージェントを選択した後に、プロバイダーのルーティングが開始されます。これには、プロバイダープロファイルとモデルの選択、再試行とフォールバック、ストリームの復旧、およびリクエストを処理したバックエンドを示す帰属情報が含まれます。チャネルからエージェントへのディスパッチは別のライフサイクルです。チャネルランタイムのライフサイクル を参照してください。
変更が model_routes、セッションまたはターン内でのモデル選択、プロバイダーのフォールバック、リトライの分類、レート制限のクールダウン、ストリームの完了、ストリーム失敗後のリプレイ、または要求されたプロバイダーと実際に応答を提供したプロバイダーの帰属に関係する場合は、このページを参照してください。
所有権マップ
| 懸念 | 現在の所有者 | 契約 |
|---|---|---|
| プロバイダーのプロファイルとフォールバックグラフ | zeroclaw-config プロバイダーのスキーマと検証 | ドット区切りの <family>.<alias> は、1つのプロファイルのエンドポイント、認証情報、オプションのプライマリモデル、機能、および順序付けられたフォールバック宣言を識別します。 |
| プロバイダーの構築 | zeroclaw-providers ファクトリ関数 | 各プロファイルをそれぞれの設定で具体化し、設定されたフォールバックエントリを順序どおりにフラット化して、信頼性を軸にルーティングを構成します。 |
| ヒントベースの選択 | RouterModelProvider | hint:<name> を、設定されたプロバイダーターゲットとルーティングモデルに解決します。プライマリターゲットは、アクティブ/デフォルトモデルに固定されます。非プライマリターゲットは、そのプロファイルでモデルが設定されている場合に固定されます。設定されていない場合は、その信頼性エントリは固定されないままルーティングモデルを受け取ります。 |
| 再試行とフェイルオーバー | ReliableModelProvider | 失敗を分類し、上限付きバックオフで再試行し、レート制限のクールダウン期間に従い、マテリアライズ済みエントリを順に処理します。 |
| プロバイダー ストリームの終了 | 具体的なプロバイダーと zeroclaw-providers/src/stream_guard.rs | 各プロバイダープロトコルの完了セマンティクスを、StreamEvent::Final または打ち切りエラーに変換します。 |
| ストリームの再生と部分出力の確定 | zeroclaw-runtime/src/agent/turn/provider_call.rs と stream_consume.rs | 不変のイベント出力がコミットされる前に限り、失敗したストリームを非ストリーミングとして再試行します。キャンセルされた応答や、部分的に表示された応答は決して再生しません。 |
| 呼び出しごとのアトリビューション | ProviderDispatch | 各試行で選択されたプロバイダー呼び出しの周囲にアトリビューションスコープを開きます。 |
| 復旧成功レコード | ReliableModelProvider | 成功したリカバリ後に、タスクローカルな要求値と提供値の記録を 1 件公開します。これは試行ごとの正式な集計ではありません。 |
| ユーザー向けの復旧通知 | ランタイムとチャネルのコンシューマー | 各自の出力サーフェスに、回復成功のレコードを表示します。コンシューマー間で通知ルールは一様ではありません。 |
構築と選択
ランタイムは、選択されたエージェント、セッションのオーバーライド、またはターン中の 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 のファーストパーティのルートおよびフォールバック契約に取って代わるものではありません。
運用担当者向けのスキーマと例は、プロバイダー設定およびルーティングにあります。フィールド構文はアーキテクチャドキュメントに重複して記載せず、そちらに記載してください。
非ストリーミングの試行順序
本番用エイリアスの場合、ファクトリは構成されたグラフを深さ優先でフラット化します。実際の順序は次のとおりです:
- プロファイルの有効なプライマリモデル、または有効なプライマリモデルが存在しない場合は、ピン留めされていないエントリを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 フォールバックでは、不変の出力を複製することなくドラフトを置き換えられます。一方、イベントシンクはリプレイを行わない境界を定義します。
最終テキストもツール呼び出しもないまま完了したストリームは、意味的に空のレスポンスであり、成功した回答ではありません。ランタイムがその結果を再実行可能とマークし、provider_retries が 0 以外の場合、Reliable は空のストリームを生成したまったく同じプロバイダー/モデルに対して、非ストリーミングのリカバリ呼び出しを 1 回許可します。この許可は 1 回で使い切られます。リカバリに失敗した場合は、残りの構成済み候補へ進み、それぞれの通常のリトライ回数が適用されます。リトライが 0 回の場合、失敗したストリームエントリはスキップされたままになります。すでに表示された推論はそのまま一度だけ表示されますが、最終回答としては扱われません。この例外は、キャンセル後、表示中の出力が中断された後、またはプロバイダーが実行したツール処理の後の再実行を許可するものではありません。
この分担により、トランスポートの復旧はランタイムに、プロバイダー固有のフレーミングはアダプターに、再試行/フォールバックのポリシーは信頼性ラッパーに保持されます。プロバイダー実装では、別のターンレベルのリプレイポリシーを作り出すべきではありません。
帰属表示と既知の不足事項
ProviderDispatch は各プロバイダー呼び出しの周囲でアトリビューションを開始します。ReliableModelProvider は、非ストリーミング呼び出しが成功するか、フォールバックストリームがエラーなしで完了した後にのみ、要求されたフォールバックと実際に提供されたフォールバックを記録します。ランタイムとチャネルのコードは、そのタスクローカルな記録を使用して、リカバリが発生したことをユーザーに伝えられます。
このレコードは、ファミリー/モデルの復旧ヒントにすぎません。本番エントリではプロバイダーのファミリーを display_name として使用するため、レコードからドット区切りのプロファイルエイリアスが失われる可能性があります。そのため、同じファミリー・同じモデルでエイリアス間のフォールバックが発生した場合、要求されたルートと区別できないことがあります。レコードが異なる場合、ランタイムレスポンスにはモデル/プロバイダーのフォールバック通知が追加されます。チャネル配信では、ファミリーをまたぐ変更の場合にのみフッターが追加されます。ファミリー内の通知については issue #7883 で追跡しています。
その記録は成功通知であり、すべての試行を網羅する正式な台帳ではありません。Issue #9470 では、却下された試行や、ストリーム復旧後の古いフォールバック通知における、使用量とコストの誤った帰属を追跡しています。この Issue が解決されるまで、最後のフォールバック通知や要求されたプロバイダーの識別情報から、試行ごとのコストの正確性を推測しないでください。
コンテンツ拒否とセーフガードのフォールバックも、トランスポートの信頼性とは別個に提案されている契約です。Tracker #9293 が、プロバイダー、構成、チャネル、ゲートウェイ、Web サーフェスにまたがるその作業を調整します。PR #8966 で提案されている関連するサービング ID の作業だけでは、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 - オペレーターガイド: プロバイダー設定、ルーティング、ストリーミング