Gemini の無料枠を利用していると、しばしばレート制限に引っ掛かって 429 Resource Exhausted エラーが発生します。しばらく待ってから再試行すれば解決しますが、これを自動化する API が用意されています。
レート制限
記事執筆時点で主力となっている Gemini 2.0 Flash Experimental の無料枠のレート制限を示します。
2025 年 1 月 13 日時点
- 1 分あたりのリクエスト数: 10
- 1 日あたりのリクエスト数: 1,500
このうちよく引っ掛かるのが 1 分当たりのリクエスト数 (rpm: requests per minute) です。仕様上、1 日あたりのリクエスト数を超過していなければ、最大で 1 分程度待てば解消します。
自動再試行
Google の API には Retry
デコレーターによる再試行機能が用意されています。以下のような特徴があります。
-
指数バックオフ:再試行の間隔が徐々に長くなります。これにより、サーバーの負荷を軽減しつつ、復旧の機会を待つことができます。
-
ジッター:再試行間隔にランダムな変動を加えます。多数のクライアントが同時に再試行することを防ぎます。
-
再試行可能なエラー:すべてのエラーに対して再試行するわけではありません。一時的なエラー(レート制限やネットワークエラーなど)の場合のみ再試行します。
リクエストを処理する関数に Retry
デコレーターを付ければ、その関数が自動的に再試行されます。
from google.api_core import retry
@retry.Retry()
def generate_content(model, *args, **kwargs):
return model.generate_content(*args, **kwargs)
この例では、model.generate_content(...)
の代わりに generate_content(model, ...)
を呼ぶことで、失敗時に再試行が行われます。
【出典】 https://github.com/google-gemini/generative-ai-python/issues/46
関数名は generate_text
から generate_content
に書き換えました。また、リンクされている text_calculator は認証が求められますが、以下で閲覧できるノートブックと同一だと思われます。
動作確認
どのような間隔で再試行するのかを確認するため、意図的に 429 エラーを発生させるコードを試します。
import logging, sys, traceback
from google.api_core import retry, exceptions
# 再試行状況を表示するための設定。これを設定しなければ何も表示されない。
logger = logging.getLogger("google.api_core.retry")
logger.setLevel(logging.DEBUG)
logger.addHandler(logging.StreamHandler())
# `test` 関数に自動再試行を設定
@retry.Retry()
def test():
raise exceptions.ResourceExhausted("Rate limit exceeded.")
try:
# 間隔を置いて自動的に再試行される
test()
except Exception as e:
# 一定時間経過しても成功しなければ打ち切られる
print(f"Error occurred at: {traceback.extract_tb(sys.exc_info()[2])[-1]}")
print(e)
待機時間はランダム化されているため、実行結果は毎回異なります。デフォルトでは 1 秒前後から始めて間隔を徐々に伸ばし、一定時間内に正常終了しなければ打ち切ってエラーとなります。
Retrying due to 429 Rate limit exceeded., sleeping 0.9s ...
Retrying due to 429 Rate limit exceeded., sleeping 0.2s ...
Retrying due to 429 Rate limit exceeded., sleeping 1.7s ...
Retrying due to 429 Rate limit exceeded., sleeping 1.6s ...
Retrying due to 429 Rate limit exceeded., sleeping 3.0s ...
Retrying due to 429 Rate limit exceeded., sleeping 10.4s ...
Retrying due to 429 Rate limit exceeded., sleeping 35.7s ...
Retrying due to 429 Rate limit exceeded., sleeping 13.9s ...
Error occurred at: <FrameSummary file /test/.venv/lib/python3.12/site-packages/google/api_core/retry/retry_base.py, line 221 in _retry_error_helper>
Timeout of 120.0s exceeded, last exception: 429 Rate limit exceeded.
Retrying due to 429 Rate limit exceeded., sleeping 0.5s ...
Retrying due to 429 Rate limit exceeded., sleeping 0.9s ...
Retrying due to 429 Rate limit exceeded., sleeping 3.6s ...
Retrying due to 429 Rate limit exceeded., sleeping 6.8s ...
Retrying due to 429 Rate limit exceeded., sleeping 15.7s ...
Retrying due to 429 Rate limit exceeded., sleeping 17.9s ...
Retrying due to 429 Rate limit exceeded., sleeping 58.8s ...
Error occurred at: <FrameSummary file /test/.venv/lib/python3.12/site-packages/google/api_core/retry/retry_base.py, line 221 in _retry_error_helper>
Timeout of 120.0s exceeded, last exception: 429 Rate limit exceeded.
実行ごとに待機時間が異なります。これは「ジッター」と呼ばれるランダムな変動が加えられているためです。
タイムアウト
ログの最後で、タイムアウトが 120 秒と表示されています。
Timeout of 120.0s exceeded, (略)
これはデフォルト値で、その時間を超えないように打ち切るアルゴリズムとなっています。具体的には、ログには表示されませんが次の待機時間 sleep
が用意されており、それを経過時間に足して 120 秒を超えるなら打ち切られます。
timeout = kwargs.get("deadline", timeout)
deadline = time.monotonic() + timeout if timeout is not None else None
error_list: list[Exception] = []
for sleep in sleep_generator:
try:
result = target()
if inspect.isawaitable(result):
warnings.warn(_ASYNC_RETRY_WARNING)
return result
# pylint: disable=broad-except
# This function explicitly must deal with broad exceptions.
except Exception as exc:
# defer to shared logic for handling errors
_retry_error_helper(
(略)
)
# if exception not raised, sleep before next attempt
time.sleep(sleep)
再試行設定のカスタマイズ
@retry.Retry
デコレータには、以下のようなオプションがあります。イコールの右辺は初期値です。
-
initial=1.0
:最初の再試行までの待機時間(秒) -
maximum=60.0
:最大の待機時間(秒) -
multiplier=2.0
:待機時間を増やす倍率 -
timeout=120.0
:再試行を続ける最大時間(秒)
例として initial=10
に変更してみます。
@retry.Retry(initial=10)
Retrying due to 429 Rate limit exceeded., sleeping 6.0s ...
Retrying due to 429 Rate limit exceeded., sleeping 15.3s ...
Retrying due to 429 Rate limit exceeded., sleeping 15.3s ...
Retrying due to 429 Rate limit exceeded., sleeping 54.7s ...
Error occurred at: <FrameSummary file /test/.venv/lib/python3.12/site-packages/google/api_core/retry/retry_base.py, line 221 in _retry_error_helper>
Timeout of 120.0s exceeded, last exception: 429 Rate limit exceeded.
ジッターが加えられるため指定した秒数で始まるわけではありませんが、デフォルトよりも最初の待機時間が増えていることが確認できました。
まとめ
再試行処理は、無料枠で Gemini を利用する上で重要な機能です。Retry
デコレーターを使用することで、効率的な再試行処理が実装できます。適切な設定とエラーハンドリングにより、アプリケーションの安定性を向上させることができるでしょう。
参考
ResourceExhausted google.api_core.exceptions.ResourceExhausted 割り当てが使い切れました。しばらくしてからもう一度お試しください。このようなエラーに対処するには、自動再試行の設定を検討してください。
関連記事
無料枠の提供当初からリミット制限はありました。
Google AI Studio の API Key で使用できる LLM の種類です。