Skip to main content
Comfy Router はまだ一般提供されていません。 以下で参照されるルート(POST /v1/models/{provider}/{model} と、そのカタログおよびスキーマ関連ルート)は、まだリクエストを処理していません。現時点では、認証済みの呼び出しでも 404 が返ります。このページは、それらのルートが提供する予定の契約について説明したものであり、既知の形状に対して統合を記述できるよう、その展開に先立って公開されています。以下の内容はすべて、その契約に関する記述であり、現在実際に試すことができる動作に関するものではありません。
Comfy Router は1回の同期呼び出しです。パートナーモデルのネイティブな入力を、1つの認証情報で1つのホストに送信し、接続は開いたままになり、200 がそのモデルのネイティブな出力を運びます。この形状こそが最初の統合を短くするものであり、また、このページに記載されたすべての制限の由来でもあります。Router を中心に設計する前に、このページを読んでください。後ではなく前です。以下に続く内容のほとんどには単純明快な代替手段があり、代替手段のないものは、Router が保持しない前提に基づいて構築する前に知っておく価値があります。

概要

各行は、その制限を説明するセクションへのリンクになっています。Deliberate(意図的) は、その制限がRouterの動作の一部であり、今後の実装を待つものではないことを意味します。Not yet(未対応) は、Routerがこの機能を獲得する見込みがあることを意味しますが、このページは時期についての約束をするものではありません。

キュー投入はありません

モデルの実行方法は1つだけです。POST /v1/models/{provider}/{model} は、生成が完了するまで接続を保持し、レスポンスで結果を返します。ジョブを受け付けて識別子を返し、後で結果を取得できるようにするエンドポイントはなく、完了時のコールバックやウェブフックもありません。キュー投入に対応する同等のエンドポイントは計画されており、APIリファレンスでは /v1/queue/models/{provider}/{model} として記載されています。ただし、これは現時点では契約の一部ではなく、このエンドポイントへの呼び出しは処理されません。 代わりにすべきこと。 ほとんどのモデルではこれは問題になりません。接続を開いたままにして結果を読み取ってください。高速な画像モデルは数秒で結果を返します。長時間のビデオ生成は数分かかることもありますが、Routerはその間接続を保持します。クライアントの読み取りタイムアウトは、Router自身の期限 よりも長い余裕のある値に設定し、この呼び出しを高速なリクエストではなく長時間実行として扱ってください。アーキテクチャ上、どうしても接続を開いたままにできない場合(実行時間の上限が短いサーバーレス関数や、ユーザーが閉じることを想定しているブラウザタブなど)は、接続を保持できる自分が管理するワーカーから呼び出しを実行するか、独自の送信・ポーリングのペアを備えたプロバイダー向けのパートナープロキシルートを使用してください。最後のセクション を参照してください。 ステータス: 未実装。 キュー投入のパスは予定されていますが、このページでは時期については何も約束していません。

レスポンスにコストやクレジットの情報がない

Router のレスポンスはモデルが生成したものを伝えるだけで、その契約にはコストに関する情報が一切ありません。レスポンスボディに請求額・クレジット残高・使用量の数字はなく、ルートもコストヘッダーを宣言しません。1つ注意点があります。Router はパートナープロキシルートと課金パスを共有しており、そのパスは許可リストに載っているプロバイダーの課金済みレスポンスに X-Comfy-Credits-Used を付与するため、その1つに対する Router 呼び出しにはこのヘッダーが現れることがあります。これは Router の契約の一部ではありません。許可リスト外のプロバイダーには常に存在せず、べき等リトライでは意図的に再送されません。これは、このヘッダーを合算するクライアントが、1回しか支払われていない呼び出しを二重に数えられないようにするためです。これに基づいて照合処理を構築しないでください。モデルカタログも同様で、呼び出し前に必要な課金ファクトだけを伝え、価格は決して含みません。したがって、Router のレスポンスだけから支出を照合することはできず、X をどこか別の場所から取得しない限り、ユーザーに「この呼び出しのコストは X」と表示することもできません。 代わりにすべきこと。 残高・使用量・請求書は platform.comfy.org の Comfy プラットフォームにあります。ここが、使った額と残っている額の真実の情報源であり、このページの内容に影響されません。呼び出し時に Router が教えてくれる価値のある2つのことを挙げます。クレジット不足で拒否された呼び出しは insufficient_credits として返るため、残高を事前確認する代わりに、クレジット切れを型付きエラーとして処理できます。また、各モデルのカタログエントリには billing.charges_on_policy_rejection があり、そのモデルがコンテンツポリシー上の理由で拒否した生成に対して課金するかどうかを示します。これはブール値ではなく、3つの値を持つ文字列です。yesnounknown です。unknown は「課金されるかもしれない」と読みます。つまり、まだ誰もそのモデルの挙動を確認していないということであり、未確認のモデルが no として公開されないようにするために正確に存在します。no は主張だからです。このフィールドは意図的に enum ではなく、認識できない値も unknown として扱ってください。また、この値に対して真偽値チェックを書かないでください。文字列 "no" はほとんどの言語で真と評価され、そのチェックは、このフィールドが存在する目的であるケースを逆にしてしまうからです。プロバイダーによってこの挙動は異なり、その違いは呼び出し時には見えません。呼び出し前にこれを読むことが、後から説明できない課金を避ける方法です。 ステータス: 未対応(呼び出しごとの数字について)。カタログには意図的に価格が含まれていないことに注意してください。価格は価格が管理される場所に属するものであり、そこから乖離しうるモデルリストに複製されるべきではありません。

失った呼び出しを再開する方法がない

Router は実行中の呼び出しの再開可能な記録を保持しません。ステータスルートもジョブ識別子も再接続先もありません。呼び出しの途中で接続が切れた場合(クライアントのクラッシュ、ネットワークの分断、プロセスを再起動するデプロイ)はレスポンスが失われ、その呼び出しについて後から問い合わせることもできません。生成が完了して課金されたかどうかは、それを受け取ったかどうかとは別の問いであり、接続が切れただけではどちらも確実には分かりません。 代わりにすべきこと。 すべての呼び出しに Idempotency-Key ヘッダーを送ってください。失われた呼び出しを再開可能にはしませんが、再試行を安全にします。Router は呼び出しの間キーを予約し、呼び出しが実際に回答を届けた場合、そのレスポンスをキーに対応付けて24時間記録します。同じキーで再試行すると、記録されたレスポンスが再生され、プロバイダーへの2回目のディスパッチ(と再課金)は行われません。Idempotent-Replayed: true が付くので、再生と新しい実行を区別できます。論理的な呼び出しごとに新しいキーを生成してください。試行ごとではなく。異なるリクエストボディで同じキーを提示すると、静かな上書きではなく 409 になります。 これが何をもたらすかを正確に理解してください。これは課金の性質であり、配信の性質ではありません。キーは最大でも1回しか課金されません。 キーがプロバイダーに最大でも1回しかディスパッチされないという約束でもありません。Router は、実際に回答を受け取った場合にキーを保持します。課金されなかった結果はキーを解放し、呼び出しを再度行えるようにします。5xx408/425/429、そして(ここが重要なケースです)何も届かなかった呼び出し。これらはすべてキーを解放し、そのキーでの再試行は本当に再実行され、プロバイダーに再ディスパッチされます。 つまり、接続が切れた場合は、べき等性が救えないケースです。 呼び出し途中の接続喪失は通常、レスポンスが一度もコミットされなかったことを意味し、それはまさに上記の解放経路です。同じキーでの再試行は、失った結果を渡すのではなく、新しい実行を開始します。元の生成がすでにディスパッチされていた場合、プロバイダーは2回目に実行するかもしれません。これは正しいデフォルトです。受け取っていない未課金の呼び出しは再実行可能であるべきです。ただし「再試行は新しい実行を生む」と計画してください。「再試行が失った実行を回収する」のではありません。 Router がキーに対して何かを保持している場合、再試行は再実行ではなく回答として扱われます。元のレスポンスが再生されるか、できない理由を説明する 409 が返ります。元の呼び出しがまだ実行中のときに送られた再試行は Retry-After 付きの 409 になるので、待ってから同じキーを再送してください。完了したが Router が忠実なコピーを保持できなかった呼び出しへの再試行も 409 です。これはレスポンスが大きすぎる場合だけではありません。再生上限を超えたレスポンス、回答後に失敗またはパニックしたハンドラー、あなたへの書き込みが失敗または不足した場合。これらはすべてキーを「消費済みだが再生不可」として記録し、同じ 409 を返します。サイズの問題を探しに行かないでください。これらのすべての場合の指針は同じです。新しいキーを使ってください。元の呼び出しは完了して課金されており、Router はそのレスポンスを捏造もせず、古いキーで再実行もさせません。
生成された契約にはまだありません。 ここで説明する Idempotency-Key リクエストヘッダー、409 レスポンス、Idempotent-ReplayedRetry-After レスポンスヘッダーは、リファレンスの生成元である OpenAPI 契約の POST /v1/models/{provider}/{model} には宣言されていません。そのため、生成された API リファレンスには登場せず、SDK もこれらをモデル化しません。正式にサポートされるまで、これらを自分で送受信してください。
ステータス: 未対応。 永続的で再開可能な実行は、キュー投入パスとともに登場する見込みです。そこならリクエスト記録の置き場所があります。べき等リトライは今日の答えであり、一時しのぎではありません。いずれにせよ組み込む価値があります。

呼び出しはサーバーの期限で打ち切られる

Router の1回の呼び出しは、接続を 10分間 保持することがあります。これがデフォルト値です。これは固定定数ではなく、サーバー側の設定値であるため、契約に刻まれた保証ではなく、設計上の想定値として扱ってください。これを過ぎると、Router は待機を停止し、プロバイダーへの進行中のリクエストをキャンセルして、X-Comfy-Error-Type: deadline_exceeded を伴う 504 を返します。deadline_exceeded の呼び出しは課金されません: 制限は当社側のものであり、そのコストも当社側が負担します。 キャンセルが行わないことが2つあり、どちらも再試行する前に知っておく価値があります。キャンセルは、プロバイダーがすでに受け付けた生成を取り消すことはありません。Router がジョブを送信してポーリングする方式で駆動するパートナーの場合、期限の満了は Router 自身の待機を終了させるだけで、プロバイダーの作業は終了しません。そのため、そのジョブは完了まで実行され、再試行によって 2回目の生成 が発生する可能性があります(その場合も、タイムアウトした呼び出しに対しては課金されません)。また、送信済みの回答を取り消すこともできません。ハンドラーが競争に勝ち、期限が切れるちょうどその瞬間に応答をコミットした場合、504 ではなくその応答が保持されます。 これを、もう一方の 504 と混同しないでください。provider_timeout はパートナーが時間内に応答しなかったことを意味し、こちら 課金されます。一方、deadline_exceeded は Router 自身の制限が満了したことを意味します。原因が2つ、課金結果も2つあるからこそ、同じステータスコード上に2つのバケットが存在します。X-Comfy-Error-Type で分岐し、ステータスコードのみで判断してはいけません。 代わりにすべきこと。 クライアントの読み取りタイムアウトは、期限より に余裕を持って設定してください。期限より下に設定してはいけません。先に諦めるクライアントは、リクエスト識別子を伴う型付きの 504 を不透明なローカル中断に変えてしまい、サポートが追跡できる唯一の証跡を失うことになります。単一の生成が期限内にどうしても完了できない場合、Router は現時点ではその用途に適していません。その場合は、ジョブを送信してポーリングするパートナープロキシルート経由で実行するか、作業を、それぞれが期限内に完了する複数の呼び出しに分割してください。 ステータス: 意図的な設計。 制限は存在しなければなりません。制限がなければ、スタックしたアップストリームが接続と並行処理スロットを無期限に保持することになります。具体的な数値は調整される可能性がありますが、期限の存在自体がなくなることはありません。

呼び出し実行中は進捗がありません

POST /v1/models/{provider}/{model} は、最後に一度だけ応答を返します。ストリーミング応答も、サーバー送信イベントも、進捗率も、部分的なフレームやプレビューフレームもありません。これは、自社のAPIが送信とポーリング方式であるパートナーについても当てはまります。Routerはそのポーリングを、あなたの1回の呼び出しの中で内部的に実行し、そこで見られる中間状態はあなたには転送されません。外から見ると、3秒の画像と6分のビデオは同じ形状です。つまり、1つのリクエスト、1つのレスポンス、その間に何もない、ということです。 代わりにできること。 現在のRouterでは、何もできません。取得できないパーセンテージの代わりに、不確定な進捗状態を表示してください。特定のプロバイダーで進捗が必須要件である場合は、そのプロバイダーのパートナープロキシルートが独自のポーリングやストリーミングを公開しているかどうかを確認し、それらを直接使用してください。実際にいくつかのプロバイダーは対応しており、それらは変更されておらず、完全にサポートされています。 ステータス: 未対応。 これはキュー中パスに結びついています。進捗を報告するための場所が必要ですが、それを提供するのはキュー中の送信であり、単一の同期呼び出しではありません。

3つの予測バケットは語彙に含まれていない

Routerのerror_type語彙は15個のバケットからなる閉じた集合です。その15個とは、APIリファレンスが列挙し、クイックスタートが指し示すものです。さらに3つが、そのリファレンスの本文で追加が見込まれるものとして名指しされています:file_download_errorcancelledqueue_timeout です。それらは名指しされているだけで、それ以上のものではありません。それらは現在の集合のメンバーではありません。Routerのレスポンスがそのいずれかを運ぶことはなく、コントラクトから生成されたクライアントはこれらを認識せず、Routerが内部的にそのいずれかを受け取った場合、レスポンスとして送信する代わりにinternal_errorに置き換えます。したがって、今日これらに対して書く分岐は決して実行されない分岐であり、リファレンスに登場することは、Routerが呼び出しをキャンセルしたりキューに入れたりする証拠ではありません。Routerはどちらも行いません。 これらが完全に省かれるのではなく文書で予測されているのは、error_typeが意図的に単なる文字列でありenumではないためです。認識できないバケットを厳格に拒否するクライアントは、何かがすでにうまくいかなくなったまさにそのときに、最も深刻な失敗をします。追加分を前もって名指しすることで、読者はこの集合が設計上オープンエンドであることを知ることができます。 代わりにすべきこと。 Routerが実際に公開する15個のバケットを処理してください。その完全なリストはAPIリファレンスにあります。そして、認識できない値をinternal_errorとして扱うフォールバック分岐を1つ書いてください。そのフォールバックが仕組み全体です。これにより、この3つと、クライアント作成後に追加される任意のバケットが、あなたを壊さずに届きます。制御フローには大まかなバケットで分岐し、具体的な理由が必要な場合は422ボディ内のフィールドごとのtypeを読んでください。 ステータス:未実装。 この3つのそれぞれは、Routerがまだ持っていない動作に対応しており、それぞれがそれを出力し始めるのと同じ変更で語彙に加わります。それより前には決して加わりません。

Routerはすべてのパートナー操作をカバーしていない

Routerはパートナーのモデルを実行します。Routerは、パートナーが公開するすべての操作をカバーするわけではありません。ファイルのアップロード、アカウントとアセットの読み取り、プロバイダー固有の管理呼び出し、ストリーミングチャットエンドポイント、一部のパートナーが公開する送信とポーリングのペアなどは対象外です。また、Routerはそれらを再形成することもありません。モデルのネイティブな入力を転送し、ネイティブな出力をそのまま返すため、サポートされていない操作を移植するための統一エンベロープはありません。 代わりにすべきこと。 /proxy/… のパートナープロキシルートは、同じホスト上で同じ認証情報を使い、引き続き完全にサポートされています。Routerがカバーしないものには、このルートが答えです。これらは非推奨でも、廃止予定でもありません。同じ統合内でRouterと併用することは、回避策ではなく想定された使い方です。多くのモデルにわたって1つのルート形状と1つの認証情報を使いたい場合はRouterを選んでください。特定のパートナー操作、プロバイダー独自のストリーミング応答、またはRouterが意図的に隠している送信・ポーリング制御が必要な場合は、/proxy/… を選んでください。 ステータス: 意図的な設計です。 Routerは対象範囲を意図的に絞っています。1つのルート形状がその機能です。プロキシの対象範囲は現状のままです。

次のステップ