رفتن به محتوای اصلی
هوشوانا

محدودیت نرخ درخواست

محدودیت تعداد درخواست و توکن در دقیقه (RPM و TPM) در هوشوانا، هدرهای محدودیت، مدیریت خطای ۴۲۹ با backoff نمایی و راه‌های کم کردن برخورد با محدودیت.

آخرین به‌روزرسانی:

محدودیت نرخ تعیین می‌کند هر کلید در هر دقیقه چند درخواست و چند توکن می‌تواند مصرف کند. این محدودیت‌ها از سرویس شما در برابر حلقه‌های بی‌پایان و هزینه‌های ناگهانی محافظت می‌کنند و اجازه می‌دهند سهم سرویس‌های مختلف را از هم جدا کنید.

انواع محدودیت

محدودیتمعنیکجا تنظیم می‌شود
RPMحداکثر تعداد درخواست در دقیقهقوانین کلید
TPMحداکثر تعداد توکن (ورودی و خروجی) در دقیقهقوانین کلید
حداکثر RPM حسابسقف تعداد درخواست همه‌ی کلیدهای حساب با همقوانین حساب

محدودیت‌های کلید نمی‌توانند از محدودیت حساب بیشتر باشند. مثلاً اگر حداکثر RPM حساب ۶۰۰ باشد و دو کلید هر کدام RPM ۵۰۰ داشته باشند، مجموع درخواست‌های دو کلید در یک دقیقه از ۶۰۰ بیشتر نمی‌شود. نحوه‌ی تنظیم در قوانین کلید آمده است.

علاوه بر این، ارائه‌دهنده‌های مدل هم محدودیت‌های خودشان را دارند. هوشوانا با توزیع بار بین مسیرهای مختلف تلاش می‌کند این محدودیت‌ها به شما نرسند، ولی در زمان‌های شلوغی ممکن است برخی مدل‌ها کندتر پاسخ دهند.

هدرهای پاسخ

هر پاسخ شامل این هدرهاست تا بدانید چقدر تا محدودیت فاصله دارید:

هدرمعنی
x-ratelimit-limit-requestsسقف تعداد درخواست در بازه‌ی فعلی
x-ratelimit-remaining-requestsتعداد درخواست باقی‌مانده در این بازه
x-ratelimit-reset-requestsزمان باقی‌مانده تا بازنشانی شمارنده
Shell
curl -s -D - -o /dev/null https://hooshvana.ir/api/v1/models \
  -H "Authorization: Bearer $HOOSHVANA_API_KEY" | grep -i x-ratelimit

خطای ۴۲۹

وقتی از محدودیت عبور کنید، درخواست با وضعیت HTTP ۴۲۹ و کد rate_limited رد می‌شود. پاسخ هدر Retry-After دارد که می‌گوید حداقل چند ثانیه صبر کنید:

HTTP/1.1 429 Too Many Requests
Retry-After: 12
Content-Type: application/json

{"error": {"message": "تعداد درخواست‌های این کلید از سقف مجاز در دقیقه بیشتر شده است. چند ثانیه بعد دوباره تلاش کنید.", "type": "rate_limit_error", "code": "rate_limited"}}

درخواستی که با ۴۲۹ رد شود هزینه‌ای ندارد.

backoff نمایی با jitter

بدترین واکنش به ۴۲۹ تلاش دوباره‌ی فوری است، چون فقط بار را بیشتر می‌کند. روش درست:

  1. اگر هدر Retry-After وجود دارد، حداقل همان مدت صبر کنید.
  2. در غیر این صورت، فاصله را در هر تلاش دو برابر کنید (۱، ۲، ۴، ۸ ثانیه و ...).
  3. یک مقدار تصادفی (jitter) به فاصله اضافه کنید تا همه‌ی کارگرها همزمان دوباره تلاش نکنند.
  4. تعداد تلاش‌ها و حداکثر فاصله را محدود کنید.

Python

Python
import os
import random
import time

import openai
from openai import OpenAI

client = OpenAI(base_url="https://hooshvana.ir/api/v1", api_key=os.environ["HOOSHVANA_API_KEY"], max_retries=0)

def with_backoff(fn, max_attempts=6, base=1.0, cap=60.0):
    for attempt in range(max_attempts):
        try:
            return fn()
        except openai.RateLimitError as e:
            if attempt == max_attempts - 1:
                raise
            retry_after = e.response.headers.get("retry-after")
            if retry_after and retry_after.isdigit():
                delay = float(retry_after)
            else:
                delay = min(cap, base * 2 ** attempt)
            time.sleep(delay + random.uniform(0, 1))

result = with_backoff(lambda: client.chat.completions.create(
    model="openai/gpt-4o-mini",
    messages=[{"role": "user", "content": "سلام"}],
))
print(result.choices[0].message.content)

Node.js

JavaScript
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://hooshvana.ir/api/v1",
  apiKey: process.env.HOOSHVANA_API_KEY,
  maxRetries: 0,
});

const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const header = (h, name) => (typeof h?.get === "function" ? h.get(name) : h?.[name]);

async function withBackoff(fn, maxAttempts = 6, baseMs = 1000, capMs = 60000) {
  for (let attempt = 0; ; attempt++) {
    try {
      return await fn();
    } catch (err) {
      if (!(err instanceof OpenAI.RateLimitError) || attempt >= maxAttempts - 1) throw err;
      const retryAfter = Number(header(err.headers, "retry-after"));
      const delay = retryAfter > 0 ? retryAfter * 1000 : Math.min(capMs, baseMs * 2 ** attempt);
      await sleep(delay + Math.random() * 1000);
    }
  }
}

const result = await withBackoff(() =>
  client.chat.completions.create({
    model: "openai/gpt-4o-mini",
    messages: [{ role: "user", content: "سلام" }],
  }),
);
console.log(result.choices[0].message.content);

SDKهای رسمی OpenAI به‌طور پیش‌فرض خودشان چند بار با backoff تلاش دوباره می‌کنند (max_retries در Python و maxRetries در Node.js). اگر همین رفتار برایتان کافی است، می‌توانید فقط تعداد تلاش‌ها را بیشتر کنید و کد بالا را ننویسید.

پیشنهادها برای برخورد کمتر با محدودیت

  • دسته‌ای بفرستید: برای embedding، چند متن را در یک درخواست بفرستید. Embeddings را ببینید.
  • همزمانی را کنترل کنید: در پردازش‌های دسته‌ای از یک صف یا semaphore با تعداد کارگر محدود استفاده کنید، نه هزاران درخواست همزمان.
  • max_tokens واقع‌بینانه بگذارید: TPM بر اساس توکن‌ها حساب می‌شود و مقدار بزرگ بی‌دلیل ظرفیت را هدر می‌دهد.
  • نتایج تکراری را کش کنید: اگر پرسش‌های یکسان زیاد دارید، پاسخ را در سمت خودتان ذخیره کنید.
  • کلیدها را جدا کنید: برای سرویس آنلاین و اسکریپت‌های دسته‌ای کلید جدا با محدودیت جدا بسازید تا اسکریپت شبانه سهم کاربران زنده را نگیرد.
  • هدرها را پایش کنید: وقتی x-ratelimit-remaining-requests به صفر نزدیک می‌شود، سرعت ارسال را خودتان کم کنید.

تفاوت با سقف هزینه

محدودیت نرخ درباره‌ی سرعت مصرف است و پس از چند ثانیه برطرف می‌شود. سقف هزینه درباره‌ی مقدار مصرف در روز یا ماه است و تا دوره‌ی بعد ادامه دارد. اولی خطای ۴۲۹ (rate_limited) و دومی خطای ۴۰۲ (spend_cap_reached) می‌دهد. با خطای ۴۰۲ تلاش دوباره نکنید.

اگر سرویس شما به محدودیت حساب بیشتری نیاز دارد، از طریق تیکت پشتیبانی درخواست دهید.