

Aravind Putrevu
October 22, 2023
10 min read
Squeezing Water from Stone - Managing OpenAI Rate Limits with Request Prioritizationの日本語訳です。
CodeRabbitは数か月前の提供開始以来、熱烈な反響を受け、数百件の登録を獲得しました。1,300を超えるGitHub Organizationへインストールされ、通常は1日あたり2,000件を超えるプルリクエストをレビューしています。さらに利用は拡大し続け、健全な前週比成長を遂げています。
この急速な成長は心強い一方、CodeRabbitを支える新しいgpt-4モデルを中心に、OpenAIの厳しいレート制限という課題へ直面しました。この記事ではOpenAIのレート制限を詳しく説明し、ユーザー基盤の拡大を続けながら信頼性の高い体験を確保するため、FluxNinja Aperture負荷管理プラットフォームを活用した方法を紹介します。
OpenAIは、提供するAIモデルごとに、1分あたりのリクエスト数とトークン数へ細かなレート制限を課します。たとえば、当社のアカウントには以下のレート制限が割り当てられています。

レート制限には複数の理由があり、近い将来に変わる可能性は低いと考えています。
gpt-4のような高度なモデルは計算負荷が高く、各リクエストの処理に数秒、場合によっては数分かかります。たとえば、複雑な作業では30秒の応答時間が一般的です。OpenAIはインフラストラクチャ全体の負荷を管理し、ユーザーへ公平なアクセスを提供するため、こうした制限を設定しています。
AIへの需要は、モデルを実行するために必要なGPUを中心に、利用可能なハードウェアの供給を上回っています。業界が急増する需要へ対応するには、しばらく時間がかかります。
CodeRabbitはGitHubまたはGitLabのリポジトリと統合するAIコードレビューアプリケーションです。プルリクエストを分析し、コード品質について開発者へフィードバックします。フィードバックはプルリクエストのコメントとして提供され、開発者はその提案に基づき、後続のコミットでコードを改善できます。

CodeRabbitはgpt-3.5-turboとgpt-4系列のモデルを組み合わせて使用します。要約などの単純な作業には、より経済的なgpt-3.5-turboモデルを使い、詳細なコードレビューなどの複雑な作業は、低速で高価なgpt-4モデルが行います。
利用パターンとして、プルリクエスト内の各ファイルを同時に要約、レビューします。ピーク時間帯や大規模なプルリクエスト(50ファイル以上)を処理すると、OpenAIから429 Too Many Requestsエラーを受けるようになりました。再試行とバックオフの仕組みがあっても、多くのリクエストは複数回の試行後もタイムアウトしました。レート制限の引き上げをOpenAIへ繰り返し依頼しましたが、実現しませんでした。
こうした課題を軽減するため、APIクライアントへ応急的な解決策を組み合わせました。
こうした調整は一時的に効果を発揮しましたが、数日以内に負荷が増えると課題が再発しました。「適切な」同時リクエスト数、バックオフ時間、最大再試行回数などを決めるため、多くの推測を行っていました。
さらに複雑なことに、コード生成と技術的な助言についてCodeRabbitボットへ相談できるチャット機能を追加しました。リアルタイムの応答を目指しましたが、バックオフの仕組みによって、特に利用のピーク時には応答時間が予測できなくなり、ユーザー体験が低下しました。
すべてのレビュアーインスタンスでレート制限を一元管理し、ユーザーのプランとリクエストの性質に基づいてリクエストを優先できる、より良い解決策が必要でした。
アドバイザーの1人から、FluxNinja Aperture負荷管理プラットフォームを紹介されました。Apertureは、高度なレート制限、リクエストの優先順位付け、クォータ管理機能を提供するオープンソースの負荷管理プラットフォームです。Apertureはグローバルなトークンバケットとして機能し、クライアント側のレート制限と、ビジネス属性に基づくリクエストの優先順位付けを実現します。
レビュアーサービスはGoogle Cloud Run上で動作し、Aperture Agentは別のKubernetesクラスター(GKE)へデプロイされています。Aperture Agentとの統合には、ApertureのTypeScript SDKを使用します。OpenAIを呼び出す前に、Aperture AgentのStartFlowメソッドを使ってリクエストを制御します。Apertureへより多くのコンテキストを提供するため、各リクエストへ次のラベルも付けます。
model_variant:使用するモデルのバリエーション(gpt-4、gpt-3.5-turbo、gpt-3.5-turbo-16k)を指定します。1分あたりのリクエスト数とトークン数のレート制限ポリシーを、モデルのバリエーションごとに設定します。
api_key:OpenAI APIキーの暗号学的ハッシュであり、キーごとにレート制限を適用します。
estimated_tokens:1分あたりのトークンクォータ制限は、補完リクエストの推定トークン数に基づいて適用されるため、計測用として各リクエストでこの値をApertureへ提供する必要があります。OpenAIのガイダンスに従い、estimated_tokensを(character_count / 4) + max_tokensとして計算します。OpenAIのレートリミッターはモデル固有のトークナイザーでリクエストをトークン化せず、文字数に基づくヒューリスティックを使用する点に注意してください。
product_tier:CodeRabbitはproとfreeの両プランを提供します。proプランは包括的なコードレビューを提供し、freeプランはプルリクエストの要約だけを提供します。
product_reason:proプランでレビューを開始した理由もラベル付けします。たとえばユーザーがpaid_user、trial_user、open_source_userであることが理由になります。これらのラベルに基づいてOpenAIへのリクエストを優先します。
priority:このラベルで提供する優先度の数値に従ってリクエストを順位付けします。たとえばpaid_userからのリクエストを、trial_userやopen_source_userからのリクエストより優先します。レビューしたファイルごとに基本優先度を高め、レビューが進んでいるプルリクエストを、新しく提出されたものより速く完了できるようにします。また、チャットメッセージにはレビュー作業よりもはるかに高い優先度を割り当てます。

Aperture TypeScript SDKとの統合
Apertureはクォータ管理の基本的な「ブループリント」を提供し、主に2つのコンポーネントで構成されます。
レートリミッター: OpenAIはトークンバケットアルゴリズムでレート制限を適用し、Apertureのレートリミッターと直接互換性があります。たとえばgpt-4の1分あたりのトークン数ポリシーでは、40000 tokensのバースト容量と、40000 tokens per minuteの補充速度を割り当てています。トークンを取り出した瞬間にバケットの補充が始まり、OpenAIのレート制限の仕組みと一致します。これにより、送信するリクエストとトークンのレートを、OpenAIが適用する制限と同期できます。
スケジューラー: Apertureは重み付き公平キューイングスケジューラーを備え、トークン数、優先度、ワークロードラベルなどの複数要素に基づいてリクエストを優先します。
Apertureでこの2つのコンポーネントを微調整することにより、レート制限を超えず、最適なユーザー体験を維持しながら、可能な限り高速に処理できます。
gpt-4のクライアント側クォータ管理ポリシー
ピーク時間帯には、通常、数十件のプルリクエスト、数百のファイル、チャットメッセージを同時に処理します。以下の画像は、gpt-4の1分あたりのトークン数ポリシーにおける、受信トークンレートと許可されたトークンレートを示します。受信トークンレートには急増がありますが、許可されたトークンレートは滑らかで、666 tokens per second前後を維持しています。これはおよそ40,000 tokens per minuteに相当します。Apertureは変動する受信トークンレートを平滑化し、OpenAIのレート制限へ合わせています。

以下の画像は、同じピーク負荷期間にAperture Cloudコンソールで確認したリクエスト優先順位付けの指標です。

指標の左上のパネルでは、目立つピークから、一部のリクエストがApertureで数分間キューへ入ったことがわかります。トライアルと無料プランのユーザーは、有料ユーザーやチャットリクエストより長いキュー時間を経験する傾向があることを確認できます。
キューの待ち時間は、各ワークロードで同時に発生するリクエスト量に応じて変動します。たとえば、ピーク時間帯の待ち時間は、オフピーク時間帯より大幅に長くなります。Apertureは、優先順位付けの効果をさらに把握するため、スケジューラーのプリエンプション指標を提供します。下部のパネルに示すように、純粋な先入れ先出し(FIFO)順序と比較し、リクエストがキューでプリエンプトまたは遅延させられたトークン数を比べることで、各ワークロードへの優先順位付けの相対的な影響を測定します。
OpenAIのクォータを効果的に管理するだけでなく、ApertureはOpenAI APIのパフォーマンスとエラーに関する知見も提供します。以下のグラフは、使用するさまざまなOpenAIモデルの全体的な応答時間を示します。gpt-4系列のモデルは、gpt-3.5-turbo系列より大幅に遅いことがわかります。これはOpenAIのインフラストラクチャが需要への対応に苦慮する理由を示唆する有用な知見です。これらのAPIは単純なデータベースクエリや分析クエリではなく、実行に高い計算コストがかかります。

ApertureはCodeRabbitに大きな変化をもたらしました。OpenAIのレート制限を心配することなく、ユーザー登録と利用量の拡大を続けられるようになりました。Apertureがなければ、事業は壁にぶつかり、ウェイティングリスト方式を採用せざるを得ず、成長の勢いを損なっていたでしょう。さらに、ApertureはOpenAI APIのパフォーマンスとエラーに関する貴重な知見を提供し、ユーザー体験全体の監視と改善に役立っています。
生成AIの領域では、APIの動作が根本的に異なります。パフォーマンスの面で、これらのAPIは従来のAPIより1桁遅くなります。リクエストのスケジューリングと優先順位付けはAIインフラストラクチャスタックの重要な要素になると考えており、Apertureを擁するFluxNinjaはこの分野をリードするうえで有利な位置にいます。CodeRabbitが引き続き構築を進め、同じく計算コストの高いベクトルデータベースなどのコンポーネントを追加する中、Apertureが今後もユーザーへ信頼できる体験を提供する支えになると確信しています。