速率限制open in new window

概述

什么是速率限制?

速率限制是API对用户或客户端在指定时间内访问服务器次数所施加的限制。

为什么我们有速率限制?

速率限制是API的一种常见做法,它们是出于一些不同的原因而设置的:

  • 它们有助于防止滥用或误用API。例如,恶意行为者可能会用请求淹没API,试图使其过载或导致服务中断。通过设置速率限制,OpenAI可以防止这种活动的发生。
  • 速率限制有助于确保每个人都能公平地访问API。如果一个人或组织提出了过多的请求,可能会使其他人的API陷入困境。通过节制单个用户的请求数量,OpenAI确保大多数人有机会使用API,而不会出现速度减慢的情况。
  • 速率限制可以帮助OpenAI管理其基础设施上的总负荷。如果对API的请求急剧增加,可能会对服务器造成负担并导致性能问题。通过设置速率限制,OpenAI可以帮助维持所有用户的流畅和一致的体验。

TIP

请完整地阅读本文件,以更好地了解OpenAI的速率限制系统是如何工作的。我们包括代码示例和处理常见问题的可能解决方案。建议在填写速率限制增加申请表open in new window之前,先按照此指导进行填写,关于如何填写的细节在最后一节。

我们的API的速率限制是什么?

我们根据使用的具体端点以及您拥有的账户类型,在组织级别而非用户级别上执行速率限制。速率限制有两种度量方式:RPM(每分钟请求数)和TPM(每分钟token数)。下表列出了我们 API 的默认速率限制,但是根据您的使用情况,这些限制可以增加。在填写速率限制增加请求表格后,可以提出增加请求。

TPM(每分钟token数)的单位根据模型的不同而不同:

实际上,这意味着你可以每分钟向 ada 模型发送的 token 数量,大约比向 davinci 模型多 200 倍。

需要注意的是,速率限制可能会因为先达到哪种限制而触发。例如,您可能会向Codex端点发送20个请求,但只有100个token,这将填满您的限制,即使在这些20个请求中没有发送40ktoken。

ChatGPT-4 的速率限制

在GPT-4的有限测试版推出期间,该模型将有更积极的速率限制,以跟上需求。gpt-4/gpt-4-0314的默认速率限制是40k TPM和200 RPM。gpt-4-32k/gpt-4-32k-0314的默认速率限制是80k TPM和400 RPM。由于能力限制,我们无法满足增加速率限制的要求。 在目前的状态下,该模型用于实验和原型设计,而不是大批量的生产用例。

速率限制是如何运作的?

如果你的速率限制是每分钟60个请求和每分钟150k token(davinci模型),无论先达到请求/分钟上限,或者先耗尽token,你都将受到限制。例如,如果你的最大请求/分钟是60,你应该能够每秒钟发送一个请求。如果你每800ms发送一个请求,为了避免你达到速率限制,你需要让你的程序睡眠200ms,然后再发送下一个请求,否则后续的请求会失败。在默认的3000个请求/分钟的情况下,客户可以有效地每20ms发送一个请求,或者每0.02秒。

如果我遇到速率限制错误会怎样?

速率限制错误看起来像这样:

Rate limit reached for default-text-davinci-002 in organization org-{id} on requests per min. Limit: 20.000000 / min. Current: 24.000000 / min.
1

如果你遇到速率限制,这意味着你在短时间内提出了太多的请求,API拒绝满足进一步的请求,直到指定的时间过去。

Rate limits vs max_tokens

我们提供的每个模型open in new window都有一个token数量限制,可以在提出请求时作为输入传入。你不能增加一个模型接受的token的最大数量。例如,如果你使用text-ada-001,你可以向这个模型发送的token最大数量是每个请求2,048个 token。

错误缓解

我可以采取哪些措施来缓解这种情况?

OpenAI Cookbook有一个python笔记本open in new window,详细解释了如何避免速率限制错误。

在提供程序化访问、批量处理功能和自动社交媒体发布时,你也应该谨慎行事--考虑只为可信的客户启用这些功能。

为了防止自动和大批量的滥用,在指定的时间范围内(每天、每周或每月)为个人用户设置一个使用限制。考虑对超过限额的用户实施一个硬性上限或人工审查程序。

指数退避的重试

避免速率限制错误的一个简单方法是用随机指数后退法自动重试请求。用指数退避法重试意味着在遇到速率限制错误时进行短暂的睡眠,然后重试不成功的请求。如果请求仍然不成功,则增加睡眠时间并重复该过程。这个过程一直持续到请求成功或达到最大重试次数为止。这种方法有很多好处:

  • 自动重试意味着你可以在没有崩溃或丢失数据的情况下从速率限制错误中恢复过来。
  • 指数退避意味着你的第一次重试可以快速进行,同时如果你的前几次重试失败,仍然可以从较长的延迟中受益。
  • 在延迟中添加随机抖动,有助于重试在同一时间发生。

下面是几个使用指数后退的Python解决方案的示例。

示例1: 使用Tenacity库

Tenacity是一个Apache 2.0许可的通用重试库,用Python编写,用于简化为任何东西添加重试行为的任务。为了给你的请求添加指数退避,你可以使用tenacity.retry装饰器。下面的例子使用tenacity.wait_random_exponential函数来为一个请求添加随机指数退避。

import openai
from tenacity import (
    retry,
    stop_after_attempt,
    wait_random_exponential,
)  # for exponential backoff
 
@retry(wait=wait_random_exponential(min=1, max=60), stop=stop_after_attempt(6))
def completion_with_backoff(**kwargs):
    return openai.Completion.create(**kwargs)
 
completion_with_backoff(model="text-davinci-003", prompt="Once upon a time,")
1
2
3
4
5
6
7
8
9
10
11
12

请注意,Tenacity库是一个第三方工具,OpenAI对其可靠性和安全性不做任何保证。

示例2: 使用backoff库 s

另一个提供退避和重试的函数装饰器的python库是backoffopen in new window

import backoff 
import openai 
@backoff.on_exception(backoff.expo, openai.error.RateLimitError)
def completions_with_backoff(**kwargs):
    return openai.Completion.create(**kwargs)
 
completions_with_backoff(model="text-davinci-003", prompt="Once upon a time,")
1
2
3
4
5
6
7

与Tenacity一样,backoff库是一个第三方工具,OpenAI对其可靠性和安全性不做保证。

示例3: 手动实现退避

如果你不想使用第三方库,你可以按照这个例子实现你自己的退避逻辑:

# imports
import random
import time
 
import openai
 
# define a retry decorator
def retry_with_exponential_backoff(
    func,
    initial_delay: float = 1,
    exponential_base: float = 2,
    jitter: bool = True,
    max_retries: int = 10,
    errors: tuple = (openai.error.RateLimitError,),
):
    """Retry a function with exponential backoff."""
 
    def wrapper(*args, **kwargs):
        # Initialize variables
        num_retries = 0
        delay = initial_delay
 
        # Loop until a successful response or max_retries is hit or an exception is raised
        while True:
            try:
                return func(*args, **kwargs)
 
            # Retry on specific errors
            except errors as e:
                # Increment retries
                num_retries += 1
 
                # Check if max retries has been reached
                if num_retries > max_retries:
                    raise Exception(
                        f"Maximum number of retries ({max_retries}) exceeded."
                    )
 
                # Increment the delay
                delay *= exponential_base * (1 + jitter * random.random())
 
                # Sleep for the delay
                time.sleep(delay)
 
            # Raise exceptions for any errors not specified
            except Exception as e:
                raise e
 
    return wrapper
    
@retry_with_exponential_backoff
def completions_with_backoff(**kwargs):
    return openai.Completion.create(**kwargs)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

同样,OpenAI对这一解决方案的安全性或效率没有任何保证,但它可以成为你自己的解决方案的一个良好的起点。

批量请求

OpenAI API对每分钟的请求和每分钟的token有单独的限制。

如果你遇到了每分钟请求的限制,但每分钟有可用的token容量,你可以通过在每个请求中批处理多个任务来增加你的吞吐量。这将允许你每分钟处理更多的token,特别是对于我们的小型模型。

发送一批提示的工作方式与正常的API调用完全相同,只是你在提示参数中传递一个字符串列表,而不是一个单一的字符串。

不使用分批的示例
import openai
 
num_stories = 10
prompt = "Once upon a time,"
 
# serial example, with one story completion per request
for _ in range(num_stories):
    response = openai.Completion.create(
        model="curie",
        prompt=prompt,
        max_tokens=20,
    )
    # print story
    print(prompt + response.choices[0].text)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
使用分批的示例
import openai  # for making OpenAI API requests
 
 
num_stories = 10
prompts = ["Once upon a time,"] * num_stories
 
# batched example, with 10 story completions per request
response = openai.Completion.create(
    model="curie",
    prompt=prompts,
    max_tokens=20,
)
 
# match completions to prompts by index
stories = [""] * len(prompts)
for choice in response.choices:
    stories[choice.index] = prompts[choice.index] + choice.text
 
# print stories
for story in stories:
    print(story)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

TIP

警告:响应对象可能不会按照提示的顺序返回完成情况,所以一定要记得使用索引字段将响应与提示匹配起来。

提高速率限额

我应该在什么时候考虑申请提高速率限额?

我们的默认速率限制帮助我们最大限度地提高稳定性,并防止滥用我们的API。我们提高限额是为了实现高流量的应用,所以申请提高费率限额的最佳时机是当你觉得你有必要的流量数据来支持提高费率限额的有力理由。没有支持数据的大额速率限制增加申请不可能被批准。如果你正在为产品发布做准备,请通过10天内分阶段发布获得相关数据。

请记住,速率限制的增加有时需要7-10天,因此,如果有数据支持你将达到你的速率限制,鉴于你目前的增长数字,尝试提前计划并提前提交是有意义的。

我的提高费率限额的请求是否会被拒绝?

提高速率限制的请求最常被拒绝,因为它缺乏证明提高费率的必要数据。我们在下面提供了一些数字例子,说明如何最好地支持提高速率限制的请求,并尽力批准所有符合我们安全政策和显示支持数据的请求。我们致力于使开发者能够利用我们的API进行扩展并获得成功。

我已经为我的文本/代码API实施了指数退避,但我还是遇到了这个错误。我怎样才能提高我的速率限制?

我们理解有限的速率限制可能造成的挫折,我们很愿意为每个人提高默认值。然而,由于共享容量的限制,我们只能批准通过我们的速率限制增加申请表格open in new window证明有需要的付费客户增加速率限制。为了帮助我们正确评估你的需求,我们要求你在表格的 "分享需求证据 "部分提供你目前使用量的统计数据或基于历史用户活动的预测。如果没有这些信息,我们建议采取分阶段释放的方法。首先以你目前的速率限制向一部分用户发布服务,收集10个工作日的使用数据,然后根据这些数据提交一份正式的速率限制增加申请,供我们审查和批准。

我们将审查你的请求,如果获得批准,我们将在7-10个工作日内通知你批准情况。

以下是一些例子,说明你可以如何填写这份表格:

例子地址open in new window

请注意,这些例子只是一般的使用情况,实际使用率会因具体的实施和使用情况而有所不同。

Last Updated:
Contributors: lanheixingkong