Bu makale size, korkunç "OpenAI Hız Sınırı" istisnasına boyun eğmeden herhangi bir LLM modelini kullanarak değerlendirmeleri nasıl çalıştıracağınızı öğretecektir. Şununla başlayabiliriz:
Şu ana kadar Cloudflare açıklaması gördüğüm en iyisi: Hız sınırlama, ağ trafiğini sınırlamaya yönelik bir stratejidir. Bir kişinin belirli bir zaman dilimi içinde bir işlemi ne sıklıkta tekrarlayabileceğine (örneğin, bir hesaba giriş yapmaya çalışmak) bir sınır koyar.
Basitçe söylemek gerekirse, balı seven dört çocuk annesi olduğunuzu hayal edin. Geçen sefer bal beklenenden daha erken tükendi. Şimdi, on bine kadar sayacak bir zamanlayıcı ayarladınız ve her çocuğa biraz bal alma sırası verdiniz. Zamanlayıcı, daha fazla bal alabilmeleri için belirli bir bekleme süresini zorunlu kıldığından oran sınırını temsil eder.
Konsepti açıkladıktan sonra, OpenAI hız sınırlarını anlayalım ve Python kullanarak OpenAI'nin R/TPM'sini (dakika başına istek/jeton) yönetmek için bir hız sınırı mantığını nasıl uyguladığımı tartışalım.
OpenAI, bir kişinin AI modelleri için bir dakika içinde yapabileceği istek sayısına belirli kısıtlamalar getirmiştir. Bu sınırlamalar OpenAI tarafından sağlanan her yapay zeka modeli için farklıdır.
Ücretsiz sürüm için:
1. seviye için:
Diğer katmanların hız sınırları hakkında daha fazla bilgi için dokümanlara bakın.
Bu kısıtlamaların nedeni şunları içerir:
Bu sınırlamaların öngörülebilir gelecekte de tutarlı kalması beklenmektedir.
Süreç (aşağıdaki resme bakın), kullanıcıların kullanıcı arayüzünden LLM değerlendirmelerini çalıştırmalarına ve mantığı kendileri yazmaya gerek kalmadan LLM uygulamaları için hız sınırı parametrelerini yapılandırmalarına olanak sağlamayı içerir.
Bu, partiyi hazırlayan ve çağıran bir fonksiyon aracılığıyla gerçekleştirilir. Gruptaki her çağrı, run_with_retry
işlevini çağırır ve bu da, yeniden deneme mekanizmasıyla son işlevi ( invoke_app
) çağırır.
Yukarıdaki işlemleri inceledikten sonra kod mantığını istediğiniz dilde yazabileceğinize eminim. Ne olursa olsun, sana benimkini nasıl yaptığımı göstereceğim. Daha fazla arka plan ve bağlam için öncelikle Agenta'da arka uç yazılım mühendisi olarak çalışıyorum.
Agenta, size hızlı mühendislik ve yönetim, ⚖️ değerlendirme, insan açıklamaları ve 🚀 konuşlandırma için araçlar sağlayan, açık kaynaklı, uçtan uca bir LLM geliştirici platformudur. Üstelik seçtiğiniz çerçeve, kitaplık veya modele herhangi bir kısıtlama getirilmeden. Agenta , geliştiricilerin ve ürün ekiplerinin üretim düzeyinde LLM destekli uygulamaları daha kısa sürede oluşturma konusunda işbirliği yapmasına olanak tanır.
Kullanıcılara LLM değerlendirmelerinin hız sınırlayıcı yapılandırmasını kullanıcı arayüzünden yapılandırma yeteneği vermek istedik, böylece LLM sağlayıcı hız sınırlayıcı istisnalarını atlayabilirler.
Süreç diyagramına bakıldığında, uygulanacak ilk şey, partiyi (LLM çağrılarının) hazırlama ve çağırma mantığıdır. Hız sınırı konfigürasyonunun doğrulanması ve LLM çalışma hızı sınırını tanımlamak için bir veri doğrulama modelinin kullanılması önemlidir. Aşağıdaki model, toplu çağrının çalışması için gereken rate_limit_config
parametresini işler.
from pydantic import BaseModel, Field class LLMRunRateLimit(BaseModel): batch_size: int = Field(default=10) max_retries: int = Field(default=3) retry_delay: int = Field(default=3) delay_between_batches: int = Field(default=5)
batch_invoke
işlevi aşağıdaki parametreleri alır:
async def batch_invoke( uri: str, testset_data: List[Dict], parameters: Dict, rate_limit_config: Dict ) -> List[AppOutput]: """ Invokes the LLm app in batches, processing the testset data. Args: uri (str): The URI of the LLm app. testset_data (List[Dict]): The testset data to be processed. parameters (Dict): The parameters for the LLm app. rate_limit_config (Dict): The rate limit configuration. Returns: List[AppOutput]: The list of app outputs after running all batches. """ batch_size = rate_limit_config[ "batch_size" ] # Number of testset to make in each batch max_retries = rate_limit_config[ "max_retries" ] # Maximum number of times to retry the failed llm call retry_delay = rate_limit_config[ "retry_delay" ] # Delay before retrying the failed llm call (in seconds) delay_between_batches = rate_limit_config[ "delay_between_batches" ] # Delay between batches (in seconds) list_of_app_outputs: List[AppOutput] = [] # Outputs after running all batches openapi_parameters = await get_parameters_from_openapi(uri + "/openapi.json") async def run_batch(start_idx: int): print(f"Preparing {start_idx} batch...") end_idx = min(start_idx + batch_size, len(testset_data)) for index in range(start_idx, end_idx): try: batch_output: AppOutput = await run_with_retry( uri, testset_data[index], parameters, max_retries, retry_delay, openapi_parameters, ) list_of_app_outputs.append(batch_output) print(f"Adding outputs to batch {start_idx}") except Exception as exc: import traceback traceback.print_exc() print( f"Error processing batch[{start_idx}]:[{end_idx}] ==> {str(exc)}" ) # Schedule the next batch with a delay next_batch_start_idx = end_idx if next_batch_start_idx < len(testset_data): await asyncio.sleep(delay_between_batches) await run_batch(next_batch_start_idx) # Start the first batch await run_batch(0) return list_of_app_outputs
Grubu hazırlayıp çağırdıktan sonraki adım, run_with_retry
mantığının yürütülmesini içerir. Bu özel uygulama, hız sınırlama işlevini içerir ve belirlenen gecikmeye ulaşıldıktan sonra yeniden deneyerek llm uygulamasının çağrılmasını yönetir. Üstel olarak artan bekleme süresiyle bir işlemi yeniden deneyen bir teknik olan üstel geri çekilme, maksimum yeniden deneme sayısına ulaşılana kadar kullanılır.
async def run_with_retry( uri: str, input_data: Any, parameters: Dict, max_retry_count: int, retry_delay: int, openapi_parameters: List[Dict], ) -> AppOutput: """ Runs the specified app with retry mechanism. Args: uri (str): The URI of the app. input_data (Any): The input data for the app. parameters (Dict): The parameters for the app. max_retry_count (int): The maximum number of retries. retry_delay (int): The delay between retries in seconds. openapi_parameters (List[Dict]): The OpenAPI parameters for the app. Returns: AppOutput: The output of the app. """ retries = 0 last_exception = None while retries < max_retry_count: try: result = await invoke_app(uri, input_data, parameters, openapi_parameters) return result except (httpx.TimeoutException, httpx.ConnectTimeout, httpx.ConnectError) as e: last_exception = e print(f"Error in evaluation. Retrying in {retry_delay} seconds:", e) await asyncio.sleep(retry_delay) retries += 1 # If max retries reached, return the last exception return AppOutput(output=None, status=str(last_exception))
AppOutput'un Kullanımı: Maksimum yeniden deneme sayısını kullandıktan sonra bile bir istisnayı ele almak önemlidir. Bu şekilde, işlemeye çalıştığınız tüm verilerin çalıştırılmasına izin verirsiniz ve ardından neyin başarısız olduğunu ve neyin geçtiğini belirleyebilirsiniz.
Son adım, uygulamanın tek bir veri noktasıyla nasıl çağrılacağını belirlemek için LLM uygulamasının openapi_parameters
kullanarak uygulamayı çağırmaktır.
make_payload işlevi sizi ilgilendirmiyor. OpenAPI parametrelerine göre LLM uygulamasını çağırmak için yükü oluşturur.
async def invoke_app( uri: str, datapoint: Any, parameters: Dict, openapi_parameters: List[Dict] ) -> AppOutput: """ Invokes an app for one datapoint using the openapi_parameters to determine how to invoke the app. Args: uri (str): The URI of the app to invoke. datapoint (Any): The data to be sent to the app. parameters (Dict): The parameters required by the app taken from the db. openapi_parameters (List[Dict]): The OpenAPI parameters of the app. Returns: AppOutput: The output of the app. Raises: httpx.HTTPError: If the POST request fails. """ url = f"{uri}/generate" payload = await make_payload(datapoint, parameters, openapi_parameters) async with httpx.AsyncClient() as client: try: logger.debug(f"Invoking app {uri} with payload {payload}") response = await client.post( url, json=payload, timeout=httpx.Timeout(timeout=5, read=None, write=5) ) response.raise_for_status() llm_app_response = response.json() app_output = ( llm_app_response["message"] if isinstance(llm_app_response, dict) else llm_app_response ) return AppOutput(output=app_output, status="success") except: return AppOutput(output="Error", status="error")
Bu da süreci tamamlıyor.
Koddaki geri çekilme üstel stratejisi şu şekilde çalışır:
Toplu İşleme: Batch_invoke işlevi, test seti verilerini yapılandırılabilir boyutta daha küçük gruplara böler. Her parti sırayla işlenir.
Yeniden Deneme ile Bireysel Çağrılar: Her toplu iş içinde, her veri noktası run_with_retry
işlevi tarafından işlenir. Bu işlev, veri noktası için uygulamayı çağırmaya çalışır. Belirli ağ hataları (zaman aşımları, bağlantı sorunları) nedeniyle çağırma başarısız olursa, işlev bir gecikmeyle yeniden dener. Bu gecikme başlangıçta yapılandırılabilir bir değere ( retry_delay
) ayarlanır ve aynı toplu iş içindeki sonraki her yeniden deneme girişiminde ikiye katlanır.
Bu yaklaşım, bir arıza sonrasında uygulama sunucusunun tekrarlanan isteklerle aşırı yüklenmesini önlemeye yardımcı olur. Sunucuya kurtarması için zaman verir ve yeniden denemeden önce bekleyen istekler sırasının temizlenmesine olanak tanır.
Strateji ayrıca sonsuz döngüleri önlemek için veri noktası başına yapılandırılabilir maksimum yeniden deneme sayısını da içerir. Uygulama sunucusu tarafından belirlenen hız sınırlarının aşılmasını önlemek için gruplar arasında bir gecikme ( delay_between_batches
) da bulunur.
Umarım bu, bugünkü makalede öğrendiğiniz her şeyi özetlemektedir. Herhangi bir sorunuz varsa lütfen bana bildirin!