TT Lab
はじめる
学ぶ 学習パス コース

LLMサービング

リクエスト数ではLLMのコストを制御できない

TT Labで続きを見る

一言でいうと

一般的なAPIは、リクエスト1つのコストがおおむね同じですが、LLMは、リクエスト1つが100トークンのこともあれば、100,000トークンのこともあります。そのため、ゲートウェイは、リクエストではなく、トークンを数える必要があります。

なぜ必要なのか

毎分60リクエストで、レートリミットをかけたとします。あるテナントが、毎回のリクエストに200,000トークンのコンテキストを入れると、リクエスト数は制限の範囲内ですが、コストとGPUの占有は、他のテナントの数百倍です。そして、そのリクエストがKVキャッシュを独占して、他のリクエストがプリエンプションされます。

リクエスト数の制限では、この状況をまったく防げません。必要なのは、トークン単位の会計です。

どう動くのか

ゲートウェイがすべきことは、5つあります。

第1に、認証とテナントの識別です。APIキーをテナントにマッピングします。

第2に、トークン会計です。リクエストの入力トークンと、レスポンスの出力トークンを、それぞれ数えて記録します。ストリーミングなら、出力トークンはストリームが終わって初めて確定するので、途中で切れた場合も、そこまでのトークンを計上する必要があります。

第3に、2つの層での制限です。RPM(毎分のリクエスト)とTPM(毎分のトークン)を、いっしょにかけます。RPMは乱用を防ぎ、TPMはコストとリソースを守ります。TPMには、トークンバケットがよく合います。普段は静かなテナントの瞬間的なバーストを許容しながら、長期の平均は守れます。

第4に、429とRetry-Afterです。拒否するときに、いつ再び来ればよいかを知らせます。これがないと、クライアントたちがそれぞれリトライして、波を作ります。

第5に、コストの算出です。モデルごとに入力・出力の単価が違うので、トークン数に単価を掛けて累積します。出力トークンのほうが入力より高いのが普通なので、2つを分けて数える必要があります。

ここに、バジェットが加わります。テナントごとに日次または月次の上限を置き、超えたら遮断するか、より安いモデルにダウングレードします。後者をフォールバックと呼び、サービスが完全に止まるよりよい場合が多くあります。

何を基準に制限するのか

RPM(毎分のリクエスト)だけをかけても、LLMサービスでは、ほとんど役に立ちません。リクエスト1つが、100トークンのこともあれば、10万トークンのこともあるからです。そのため、2つの軸をいっしょにかけます。

軸 何を防ぐか 単位
RPM リクエストの殺到、ボット 毎分のリクエスト数
TPM GPU時間の消耗 毎分のトークン数(入力+出力)
同時実行数 キューの爆発、メモリ 進行中のリクエスト数

3つのうち、同時実行数がGPUを最も正確に反映します。vLLMは、バッチで処理するので、同時リクエスト数が、そのままKVキャッシュの使用量であり、それがあふれると、OOMかプリエンプション(preemption)です。RPMとTPMはコストの会計に、同時実行数は安定性に使います。

トークンバケットで実装すれば、バーストを許容しながら、平均を守れます。

용량 = 60,000 토큰,  채우는 속도 = 1,000 토큰/초 (= 60k TPM)

요청이 오면 max_tokens 만큼 버킷에서 뺀다(예약)
완료되면 실제 사용량과의 차이를 돌려준다(정산)
버킷이 비면 429 + Retry-After: <채워질 때까지의 초>

このコードブロックの韓国語は、容量が60,000トークン、補充速度が毎秒1,000トークン(=60k TPM)で、リクエストが来たらmax_tokens分をバケットから引き(予約)、完了したら実際の使用量との差を返し(精算)、バケットが空なら429とRetry-Afterを返す、という意味です。

Retry-Afterを必ず送ります。ないと、クライアントがすぐにリトライして、状況がさらに悪くなります。

429をうまく返すことも設計

拒否するときに何を知らせるかが、クライアントのコードの品質を決めます。

HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Limit-Tokens: 60000
X-RateLimit-Remaining-Tokens: 0
X-RateLimit-Reset-Tokens: 12s

そして、どの上限に引っかかったかを、本文に書きます。RPMなのか、TPMなのか、バジェットなのかによって、クライアントがすることが違います。前の2つは待てばよいですが、バジェットの超過は、待ってもだめです。

キャッシュが最大の節約

制限より効果が大きいのが、キャッシュです。3つの層があります。

現場での姿

トークン数があらかじめわからないという点が、この設計を難しくします。入力トークンは、リクエストの時点で数えられますが、出力トークンは、生成が終わってから初めてわかります。そのため、実務では、max_tokensを上限として予約しておいて、完了後に実際の使用量で精算する方式を使います。予約をしないと、同時に入ってきたリクエストが、すべて予算の範囲内だと判断して通過したあと、いっしょに超過します。

コスト暴走の事故は、たいていリトライのループで起きます。クライアントがタイムアウトのたびにリトライするのに、サーバーは生成し続けていると、ユーザー1人に同じ答えを5回作らせることになります。ゲートウェイで冪等キーを受け取って、進行中の同一リクエストをまとめれば、この無駄がなくなります。

次のラボですること

前に作ったモックサーバーの前に、ゲートウェイを立てます。APIキー認証、RPM制限、トークン会計、TPMのトークンバケット、Retry-After、モデルごとのコスト算出、そしてテナントのバジェット超過の遮断まで付けます。