यह आलेख आपको सिखाएगा कि खतरनाक "ओपनएआई रेट लिमिट" अपवाद के आगे झुके बिना किसी भी एलएलएम मॉडल का उपयोग करके मूल्यांकन कैसे चलाया जाए। हम इससे शुरुआत करेंगे:
अब तक, क्लाउडफ़ेयर स्पष्टीकरण सबसे अच्छा है जो मैंने देखा है: दर-सीमित करना नेटवर्क ट्रैफ़िक को सीमित करने की एक रणनीति है। यह इस पर एक सीमा लगाता है कि कोई व्यक्ति एक निश्चित समय-सीमा के भीतर कितनी बार किसी कार्रवाई को दोहरा सकता है - उदाहरण के लिए, किसी खाते में लॉग इन करने का प्रयास करना।
सीधे शब्दों में कहें तो, ऐसे चार बच्चों की माँ होने की कल्पना करें जिन्हें शहद बहुत पसंद है। पिछली बार, शहद उम्मीद से जल्दी ख़त्म हो गया। अब, आपने दस हजार तक गिनती करने के लिए एक टाइमर सेट कर दिया है और प्रत्येक बच्चे को कुछ शहद लेने की बारी दी है। टाइमर दर-सीमा का प्रतिनिधित्व करता है, क्योंकि यह अधिक शहद प्राप्त करने से पहले एक विशिष्ट प्रतीक्षा समय लागू करता है।
अवधारणा को समझाने के बाद, आइए ओपनएआई दर-सीमा को समझें और चर्चा करें कि मैंने पायथन का उपयोग करके ओपनएआई के आर/टीपीएम (प्रति मिनट अनुरोध/टोकन) को प्रबंधित करने के लिए दर-सीमा तर्क कैसे लागू किया।
ओपनएआई ने एक मिनट के भीतर अपने एआई मॉडल के लिए किए जा सकने वाले अनुरोधों की संख्या पर कुछ प्रतिबंध लगाए हैं। OpenAI द्वारा प्रदान किए गए प्रत्येक AI मॉडल के लिए ये सीमाएँ अलग-अलग हैं।
मुफ़्त संस्करण के लिए:
टियर 1 के लिए:
अन्य स्तरों की दर-सीमाओं के बारे में अधिक जानकारी के लिए दस्तावेज़ देखें..
इन प्रतिबंधों के कारणों में शामिल हैं:
निकट भविष्य में इन सीमाओं के सुसंगत बने रहने की उम्मीद है।
प्रक्रिया (नीचे छवि देखें) में उपयोगकर्ताओं को यूआई से एलएलएम मूल्यांकन चलाने और तर्क लिखने की आवश्यकता के बिना अपने एलएलएम ऐप्स के लिए दर-सीमा पैरामीटर कॉन्फ़िगर करने में सक्षम बनाना शामिल है।
यह एक फ़ंक्शन के माध्यम से हासिल किया जाता है जो बैच को तैयार करता है और आमंत्रित करता है। बैच में प्रत्येक कॉल run_with_retry
फ़ंक्शन को आमंत्रित करती है, जो बदले में पुनः प्रयास तंत्र के साथ अंतिम फ़ंक्शन ( invoke_app
) को आमंत्रित करती है।
मुझे विश्वास है कि उपरोक्त प्रक्रिया को देखने के बाद आप अपनी पसंद की किसी भी भाषा में कोड-लॉजिक लिख सकते हैं। बहरहाल, मैं तुम्हें दिखाऊंगा कि मैंने अपना काम कैसे किया। अधिक पृष्ठभूमि और संदर्भ के लिए, मैं मुख्य रूप से एजेंटा में बैकएंड सॉफ्टवेयर इंजीनियर के रूप में काम करता हूं।
एजेंटा एक ओपन-सोर्स एंड-टू-एंड एलएलएम डेवलपर प्लेटफ़ॉर्म है जो आपको त्वरित इंजीनियरिंग और प्रबंधन, ⚖️ मूल्यांकन, मानव एनोटेशन और 🚀 परिनियोजन के लिए उपकरण प्रदान करता है। यह सब आपकी पसंद की रूपरेखा, लाइब्रेरी या मॉडल पर कोई प्रतिबंध लगाए बिना। एजेंटा डेवलपर्स और उत्पाद टीमों को कम समय में उत्पादन-ग्रेड एलएलएम-संचालित अनुप्रयोगों के निर्माण में सहयोग करने की अनुमति देता है।
हम उपयोगकर्ताओं को यूआई से अपने एलएलएम मूल्यांकन दर-सीमित कॉन्फ़िगरेशन को कॉन्फ़िगर करने की क्षमता देना चाहते थे ताकि वे अपने एलएलएम प्रदाता दर-सीमित अपवाद को बायपास कर सकें।
प्रक्रिया आरेख को देखते हुए, लागू करने वाली पहली चीज़ बैच (एलएलएम कॉल के) को तैयार करने और लागू करने का तर्क है। एलएलएम रन रेट सीमा को परिभाषित करने के लिए दर सीमा कॉन्फ़िगरेशन को सत्यापित करना और डेटा सत्यापन मॉडल का उपयोग करना महत्वपूर्ण है। नीचे दिया गया मॉडल बैच के कार्य करने के लिए आवश्यक rate_limit_config
पैरामीटर को संभालता है।
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
फ़ंक्शन निम्नलिखित पैरामीटर लेता है:
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
बैच को तैयार करने और लागू करने के बाद, अगले चरण में run_with_retry
तर्क को निष्पादित करना शामिल है। इस कस्टम कार्यान्वयन में दर-सीमित कार्यक्षमता शामिल है और एलएलएम ऐप के आह्वान का प्रबंधन करता है, सेट विलंब तक पहुंचने के बाद पुनः प्रयास करता है। एक्सपोनेंशियल बैकऑफ़, एक ऐसी तकनीक जो तेजी से बढ़ते प्रतीक्षा-समय के साथ एक ऑपरेशन का पुन: प्रयास करती है, अधिकतम पुनर्प्रयास गिनती तक पहुंचने तक नियोजित होती है।
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 का उपयोग: अधिकतम पुनर्प्रयास का उपयोग करने के बाद भी अपवाद को संभालना महत्वपूर्ण है। इस तरह, आप उस सभी डेटा को चलाने की अनुमति देते हैं जिसे आप संसाधित करने का प्रयास कर रहे हैं, और फिर आप यह निर्धारित कर सकते हैं कि क्या विफल हुआ और क्या पारित हुआ।
अंतिम चरण ऐप को इनवॉइस करना है, एलएलएम ऐप के openapi_parameters
का उपयोग करके यह निर्धारित करना है कि इसे एकल डेटापॉइंट के साथ कैसे इनवॉइस किया जाए।
मेक_पेलोड फ़ंक्शन से आपको चिंतित नहीं होना चाहिए। यह अपने ओपनएपीआई मापदंडों के आधार पर एलएलएम ऐप को लागू करने के लिए पेलोड का निर्माण करता है।
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")
और इससे प्रक्रिया पूरी हो जाती है।
कोड में बैकऑफ़ घातीय रणनीति निम्नानुसार काम करती है:
बैच प्रोसेसिंग: बैच_इनवोक फ़ंक्शन टेस्टसेट डेटा को कॉन्फ़िगर करने योग्य आकार के साथ छोटे बैचों में विभाजित करता है। प्रत्येक बैच को क्रमिक रूप से संसाधित किया जाता है।
पुनः प्रयास के साथ व्यक्तिगत आह्वान: प्रत्येक बैच के भीतर, प्रत्येक डेटा बिंदु को run_with_retry
फ़ंक्शन द्वारा संसाधित किया जाता है। यह फ़ंक्शन डेटा बिंदु के लिए ऐप को इनवॉइस करने का प्रयास करता है। यदि विशिष्ट नेटवर्क त्रुटियों (टाइमआउट, कनेक्शन समस्याएं) के कारण आमंत्रण विफल हो जाता है, तो फ़ंक्शन देरी से पुनः प्रयास करता है। यह विलंब प्रारंभ में एक कॉन्फ़िगर करने योग्य मान ( retry_delay
) पर सेट किया गया है और उसी बैच के भीतर प्रत्येक बाद के पुनः प्रयास प्रयास के लिए दोगुना कर दिया गया है।
यह दृष्टिकोण विफलता के बाद बार-बार अनुरोधों के साथ ऐप सर्वर पर ओवरलोडिंग से बचने में मदद करता है। यह सर्वर को पुनर्प्राप्त करने का समय देता है और पुन: प्रयास करने से पहले लंबित अनुरोधों की कतार को साफ़ करने की अनुमति देता है।
रणनीति में अनंत लूप को रोकने के लिए प्रति डेटा बिंदु पर कॉन्फ़िगर करने योग्य अधिकतम संख्या में पुनः प्रयास भी शामिल हैं। ऐप सर्वर द्वारा निर्धारित दर सीमा से अधिक होने से बचने के लिए बैचों के बीच देरी ( delay_between_batches
) भी शामिल है।
मुझे आशा है कि यह आज के लेख में आपने जो कुछ भी सीखा है उसका सारांश प्रस्तुत करता है। यदि आपके कोई सवाल हैं तो कृपया मुझे बताएं!