paint-brush
पायथन में ओपनएआई असिस्टेंट के साथ एक एजेंट कैसे बनाएं - भाग 1: संवादात्मकद्वारा@jeanmaried
4,035 रीडिंग
4,035 रीडिंग

पायथन में ओपनएआई असिस्टेंट के साथ एक एजेंट कैसे बनाएं - भाग 1: संवादात्मक

द्वारा Jean-Marie Dalmasso12m2024/02/09
Read on Terminal Reader

बहुत लंबा; पढ़ने के लिए

अब हम कुछ त्रुटि परिदृश्यों को संभालते हुए पूर्ण स्थिति की जांच करने के लिए थोड़ी देर का लूप चलाते हैं। असिस्टेंट एपीआई की वास्तविक बिलिंग थोड़ी अस्पष्ट है, इसलिए सुरक्षित रहने के लिए, मैंने 2 मिनट के बाद अपने रन रद्द करने का विकल्प चुना। हालाँकि, जब OpenAI 10 मिनट के बाद चलता है तो इसकी समय सीमा समाप्त हो जाती है। यदि एक दौड़ में 2 मिनट से अधिक समय लगता है, तो संभवतः आपको कोई समस्या है।
featured image - पायथन में ओपनएआई असिस्टेंट के साथ एक एजेंट कैसे बनाएं - भाग 1: संवादात्मक
Jean-Marie Dalmasso HackerNoon profile picture

यह पायथन एसडीके का उपयोग करके ओपनएआई के सहायक एपीआई के साथ एजेंटों के निर्माण पर एक बहु-भाग श्रृंखला में पहला भाग है।

एजेंट क्या हैं?

जिस तरह से मैं इसे देखना पसंद करता हूं, एक एजेंट वास्तव में एलएलएम (बड़े भाषा मॉडल) का लाभ उठाने वाले सॉफ्टवेयर का एक टुकड़ा है और मानव व्यवहार की नकल करने की कोशिश कर रहा है। इसका मतलब है कि यह न केवल बातचीत कर सकता है और भाषा को समझ सकता है, बल्कि यह ऐसे कार्य भी कर सकता है जिनका वास्तविक दुनिया पर प्रभाव पड़ता है। इन क्रियाओं को आम तौर पर उपकरण कहा जाता है।


इस ब्लॉग पोस्ट में, हम यह पता लगाएंगे कि ओपनएआई के असिस्टेंट एपीआई का उपयोग करके उनके पायथन एसडीके का उपयोग करके एक एजेंट कैसे बनाया जाए। भाग 1 सहायक का ढाँचा मात्र होगा। यानी सिर्फ बातचीत का हिस्सा.


मैंने फ़्रेमवर्क अज्ञेयवादी होने के उद्देश्य से एक सीएलआई ऐप बनाने का निर्णय लिया। हम जानबूझकर अपने कार्यान्वयन को एक एजेंट कहेंगे और दोनों के बीच आसानी से अंतर करने के लिए ओपनएआई एसडीके कार्यान्वयन को एक सहायक के रूप में संदर्भित करेंगे।


जब उन कार्यों की बात आती है जिन्हें एजेंट कॉल करने में सक्षम होता है तो मैं टूल और फ़ंक्शन शब्दों का परस्पर उपयोग करता हूं। भाग 2 में फ़ंक्शन कॉलिन को अधिक विस्तार से कवर किया जाएगा।

आवश्यक शर्तें

इस ट्यूटोरियल का अनुसरण करने के लिए, आपको निम्नलिखित की आवश्यकता होगी:


  • आपकी मशीन पर Python3 स्थापित है
  • एक OpenAI API कुंजी
  • पायथन प्रोग्रामिंग का बुनियादी ज्ञान

OpenAI सहायक अवधारणाएँ

असिस्टेंट : असिस्टेंट एपीआई में एक असिस्टेंट उपयोगकर्ता संदेशों का जवाब देने के लिए कॉन्फ़िगर की गई एक इकाई है। यह कार्यों के साथ बातचीत करने और उत्तर प्रदान करने के लिए निर्देशों, एक चुने हुए मॉडल और टूल का उपयोग करता है।


थ्रेड : असिस्टेंट एपीआई में एक थ्रेड एक वार्तालाप या संवाद का प्रतिनिधित्व करता है। यह प्रत्येक उपयोगकर्ता इंटरैक्शन के लिए बनाया गया है और इसमें कई संदेश शामिल हो सकते हैं, जो चल रही बातचीत के लिए एक कंटेनर के रूप में काम करेंगे।


संदेश : एक संदेश एक थ्रेड में संचार की एक इकाई है। इसमें टेक्स्ट (और भविष्य में संभावित फ़ाइलें) शामिल हैं और इसका उपयोग थ्रेड के भीतर उपयोगकर्ता प्रश्नों या सहायक प्रतिक्रियाओं को व्यक्त करने के लिए किया जाता है।


रन : रन असिस्टेंट द्वारा थ्रेड को प्रोसेस करने का एक उदाहरण है। इसमें थ्रेड को पढ़ना, टूल को कॉल करना है या नहीं, यह तय करना और थ्रेड के संदेशों की मॉडल की व्याख्या के आधार पर प्रतिक्रियाएं उत्पन्न करना शामिल है।

विकास परिवेश की स्थापना

पहला कदम venv उपयोग करके एक आभासी वातावरण बनाना और उसे सक्रिय करना है। यह सुनिश्चित करेगा कि हमारी निर्भरताएँ सिस्टम पायथन इंस्टालेशन से अलग हैं:

 python3 -m venv venv source venv/bin/activate


आइए अपनी एकमात्र निर्भरता स्थापित करें: openai पैकेज:

 pip install openai


एक main.py फ़ाइल बनाएँ। आइए हमारे सीएलआई ऐप के लिए कुछ बुनियादी रनटाइम तर्क को शामिल करें:

 while True: user_input = input("User: ") if user_input.lower() == 'exit': print("Exiting the assistant...") break print(f"Assistant: You said {user_input}")


इसे python3 main.py चलाकर आज़माएँ:

 python3 main.py User: hi Assistant: You said hi


जैसा कि आप देख सकते हैं, सीएलआई एक उपयोगकर्ता संदेश को इनपुट के रूप में स्वीकार करता है, और हमारे जीनियस असिस्टेंट के पास अभी तक दिमाग नहीं है इसलिए वह संदेश को तुरंत दोहरा देता है। अभी इतना स्मार्ट नहीं हूं.

एजेंट

अब, मज़ा 😁 (या सिरदर्द 🤕) शुरू होता है। मैं अभी अंतिम कक्षा के लिए आवश्यक सभी आयात प्रदान करूंगा, ताकि आप अपना दिमाग इस बात पर न लगाएं कि चीजें कहां से आ रही हैं क्योंकि मैंने संक्षिप्तता के लिए आयात को कोड नमूनों से बाहर रखा है। आइए एक नई फ़ाइल agent.py में Agent क्लास बनाकर शुरुआत करें:

 import time import openai from openai.types.beta.threads.run import Run class Agent: def __init__(self, name: str, personality: str): self.name = name self.personality = personality self.client = openai.OpenAI(api_key="sk-*****") self.assistant = self.client.beta.assistants.create( name=self.name, model="gpt-4-turbo-preview" )


क्लास कंस्ट्रक्टर में, हम अपनी ओपनएआई एपीआई कुंजी पास करके ओपनएआई क्लाइंट को क्लास प्रॉपर्टी के रूप में प्रारंभ करते हैं। इसके बाद, हम एक assistant क्लास प्रॉपर्टी बनाते हैं जो हमारे नव निर्मित असिस्टेंट से मैप होती है। हम बाद में उपयोग के लिए name और personality वर्ग गुणों के रूप में संग्रहीत करते हैं।


क्रिएट मेथड में हम name तर्क दे रहे हैं, वह केवल ओपनएआई डैशबोर्ड में असिस्टेंट की पहचान करने के लिए है, और एआई को वास्तव में इस बिंदु पर इसकी जानकारी नहीं है। आपको वास्तव में instructions को नाम देना होगा जिसे हम बाद में देखेंगे।


असिस्टेंट बनाते समय आप पहले से ही instructions सेट कर सकते हैं, लेकिन यह वास्तव में आपके असिस्टेंट को गतिशील परिवर्तनों के प्रति कम लचीला बना देगा।


आप client.beta.assistants.update पर कॉल करके असिस्टेंट को अपडेट कर सकते हैं, लेकिन गतिशील मूल्यों को पारित करने के लिए एक बेहतर जगह है जिसे हम रन पर पहुंचने पर देखेंगे।


ध्यान दें कि यदि आप रन बनाते समय यहां बार-बार instructions पारित करते हैं, तो सहायक के instructions रन के instructions से अधिलेखित हो जाएंगे। वे एक-दूसरे के पूरक नहीं हैं, इसलिए अपनी आवश्यकताओं के आधार पर एक चुनें: स्थिर निर्देशों के लिए सहायक स्तर या गतिशील निर्देशों के लिए रन स्तर।


मॉडल के लिए, मैंने gpt-4-turbo-preview मॉडल चुना ताकि हम इस श्रृंखला के भाग 2 में फ़ंक्शन कॉलिंग जोड़ सकें। यदि आप उपकरण लागू करते समय अपने आप को शुद्ध हताशा का माइग्रेन देते हुए पैसे का कुछ अंश बचाना चाहते हैं तो आप gpt-3.5-turbo उपयोग कर सकते हैं।


जीपीटी 3.5 कॉलिंग टूल्स में भयानक है; इससे निपटने की कोशिश में मैंने जो घंटे गँवाए हैं, वे मुझे यह कहने की अनुमति देते हैं। 😝 मैं इसे यहीं छोड़ दूँगा, और इस पर बाद में और अधिक जानकारी दूंगा।

एक थ्रेड बनाना, संदेश जोड़ना, और अंतिम संदेश पुनः प्राप्त करना

एक एजेंट बनाने के बाद, हमें एक वार्तालाप सूत्र शुरू करने की आवश्यकता होगी।

 class Agent: # ... (rest of code) def create_thread(self): self.thread = self.client.beta.threads.create()


और हम उस थ्रेड में संदेश जोड़ने का एक तरीका चाहेंगे:

 class Agent: # ... (rest of code) def add_message(self, message): self.client.beta.threads.messages.create( thread_id=self.thread.id, role="user", content=message )


ध्यान दें कि फिलहाल, केवल user भूमिका के साथ संदेश जोड़ना संभव है। मेरा मानना है कि ओपनएआई भविष्य के रिलीज में इसे बदलने की योजना बना रहा है क्योंकि यह काफी सीमित है।


अब, हम थ्रेड में अंतिम संदेश प्राप्त कर सकते हैं:

 class Agent: # ... (rest of code) def get_last_message(self): return self.client.beta.threads.messages.list( thread_id=self.thread.id ).data[0].content[0].text.value


इसके बाद, हमारे पास अब तक क्या है इसका परीक्षण करने के लिए हम एक प्रवेश बिंदु run_agent विधि बनाते हैं। वर्तमान में, run_agent विधि केवल थ्रेड में अंतिम संदेश लौटाती है। यह वास्तव में रन नहीं करता है। यह अभी भी बुद्धिहीन है.

 class Agent: # ... (rest of code) def run_agent(self): message = self.get_last_message() return message


वापस main.py में, हम एजेंट और अपना पहला थ्रेड बनाते हैं। हम थ्रेड में एक संदेश जोड़ते हैं। फिर वही संदेश उपयोगकर्ता को वापस लौटाएं, लेकिन इस बार, उस लाइव थ्रेड से आ रहा है।

 from agent import Agent agent = Agent(name="Bilbo Baggins", personality="You are the accomplished and renowned adventurer from The Hobbit. You act like you are a bit of a homebody, but you are always up for an adventure. You worry a bit too much about breakfast.") agent.create_thread() while True: user_input = input("User: ") if user_input.lower() == 'exit': print("Exiting the agent...") break agent.add_message(user_input) answer = agent.run_agent() print(f"Assistant: {answer}")


आइए इसे चलाएँ:

 python3 main.py User: hi Assistant: hi


अभी भी बहुत स्मार्ट नहीं है. हॉबिट की तुलना में तोते के अधिक करीब। अगले भाग में असली मज़ा शुरू होता है।

एक रन बनाना और मतदान करना

जब आप एक रन बनाते हैं, तो आपको रन की स्थिति की जांच करने के लिए समय-समय पर Run ऑब्जेक्ट को पुनः प्राप्त करने की आवश्यकता होती है। इसे मतदान कहते हैं, और यह बेकार है। आपके एजेंट को आगे क्या करना चाहिए यह निर्धारित करने के लिए आपको मतदान करने की आवश्यकता है। OpenAI ने इसे सरल बनाने के लिए स्ट्रीमिंग के लिए समर्थन जोड़ने की योजना बनाई है। इस बीच, मैं आपको दिखाऊंगा कि इस अगले भाग में मतदान कैसे स्थापित किया जाए।


निम्नलिखित विधि नामों पर _ नोट करें जो कि पायथन में यह इंगित करने के लिए मानक है कि विधि आंतरिक उपयोग के लिए है और इसे सीधे बाहरी कोड द्वारा एक्सेस नहीं किया जाना चाहिए।


सबसे पहले, आइए Run बनाने के लिए एक सहायक विधि _create_run बनाएं, और इस विधि को कॉल करने के लिए run_agent अपडेट करें:

 class Agent: # ... (rest of code) def get_breakfast_count_from_db(self): return 1 def _create_run(self): count = self.get_breakfast_count_from_db() return self.client.beta.threads.runs.create( thread_id=self.thread.id, assistant_id=self.assistant.id, instructions=f""" Your name is: {self.name} Your personality is: {self.personality} Metadata related to this conversation: {{ "breakfast_count": {count} }} """, ) def run_agent(self): run = self._create_run() # add this line message = self.get_last_message() return message


ध्यान दें कि रन बनाने के लिए हम thread.id और assistant.id कैसे पास करते हैं।


याद रखें कि मैंने शुरुआत में कैसे कहा था कि गतिशील निर्देश और डेटा भेजने के लिए एक बेहतर जगह है? रन बनाते समय वह instructions पैरामीटर होगा। हमारे मामले में, हम नाश्ते की count एक डेटाबेस से प्राप्त कर सकते हैं। यह आपको हर बार जब आप कोई उत्तर देना चाहते हैं तो विभिन्न प्रासंगिक गतिशील डेटा को आसानी से पारित करने की अनुमति देगा।


अब, आपका एजेंट अपने चारों ओर बदल रही दुनिया से अवगत है और उसके अनुसार कार्य कर सकता है। मुझे अपने निर्देशों में एक मेटाडेटा JSON ऑब्जेक्ट रखना पसंद है जो प्रासंगिक गतिशील संदर्भ रखता है। यह मुझे कम क्रियाशीलता के साथ और ऐसे प्रारूप में डेटा भेजने की अनुमति देता है जिसे एलएलएम वास्तव में अच्छी तरह से समझता है।


इसे अभी तक न चलाएं; यह काम नहीं करेगा क्योंकि हम अंतिम संदेश प्राप्त होने पर रन पूरा होने की प्रतीक्षा नहीं कर रहे हैं, इसलिए यह अभी भी अंतिम उपयोगकर्ता संदेश होगा।


आइए अपना मतदान तंत्र बनाकर इसका समाधान करें। सबसे पहले, हमें एक रन को बार-बार और आसानी से पुनः प्राप्त करने के लिए एक तरीके की आवश्यकता होगी, तो आइए एक _retrieve_run विधि जोड़ें:

 class Agent: # ... (rest of code) def _retrieve_run(self, run: Run): return self.client.beta.threads.runs.retrieve( run_id=run.id, thread_id=self.thread.id)


ध्यान दें कि किसी विशिष्ट रन को खोजने के लिए हमें run.id और thread.id दोनों को कैसे पास करना होगा।


हमारे एजेंट वर्ग में _poll_run विधि जोड़ें:

 class Agent: # ... (rest of code) def _cancel_run(self, run: Run): self.client.beta.threads.runs.cancel( run_id=run.id, thread_id=self.thread.id) def _poll_run(self, run: Run): status = run.status start_time = time.time() while status != "completed": if status == 'failed': raise Exception(f"Run failed with error: {run.last_error}") if status == 'expired': raise Exception("Run expired.") time.sleep(1) run = self._retrieve_run(run) status = run.status elapsed_time = time.time() - start_time if elapsed_time > 120: # 2 minutes self._cancel_run(run) raise Exception("Run took longer than 2 minutes.")


🥵 ओह, यह बहुत है... चलो इसे खोलो।


_poll_run एक Run ऑब्जेक्ट को तर्क के रूप में प्राप्त करता है और वर्तमान रन status निकालता है। सभी उपलब्ध स्थितियाँ OpenAI डॉक्स में पाई जा सकती हैं। हम बस उनमें से कुछ का उपयोग करेंगे जो हमारे वर्तमान उद्देश्य के अनुरूप हों।


अब हम कुछ त्रुटि परिदृश्यों को संभालते हुए पूर्ण स्थिति की जांच करने के लिए थोड़ी देर का लूप चलाते हैं। असिस्टेंट एपीआई की वास्तविक बिलिंग थोड़ी अस्पष्ट है, इसलिए सुरक्षित रहने के लिए, मैंने 2 मिनट के बाद अपने रन रद्द करने का विकल्प चुना।


हालाँकि, जब OpenAI 10 मिनट के बाद चलता है तो इसकी समय सीमा expired है। यदि एक दौड़ में 2 मिनट से अधिक समय लगता है, तो संभवतः आपको कोई समस्या है।


चूँकि मैं भी हर कुछ मिलीसेकंड में मतदान नहीं करना चाहता, इसलिए मैं अपने अनुरोध को केवल हर 1 सेकंड में मतदान करके दबा देता हूँ जब तक कि मैं 2 मिनट के निशान तक नहीं पहुँच जाता और अपनी दौड़ रद्द नहीं कर देता। आप इसे अपनी इच्छानुसार समायोजित कर सकते हैं।


देरी के बाद प्रत्येक पुनरावृत्ति, हम रन स्थिति फिर से लाते हैं।


अब, आइए उन सभी को हमारी run_agent विधि में प्लग करें। आप देखेंगे कि हम पहले _create_run के साथ रन बनाते हैं, फिर हम _poll_run के साथ पोल करते हैं जब तक कि हमें कोई उत्तर नहीं मिलता है या कोई त्रुटि सामने नहीं आती है, और अंत में जब पोलिंग समाप्त हो जाती है, तो हम थ्रेड से अंतिम संदेश प्राप्त करते हैं जो अब एजेंट से होगा।


फिर हम संदेश को अपने रनटाइम लूप पर लौटाते हैं, ताकि इसे उपयोगकर्ता को वापस भेजा जा सके।

 class Agent: # ... (rest of code) def run_agent(self): run = self._create_run() self._poll_run(run) # add this line message = self.get_last_message() return message


वोइला, अब जब आप अपना एजेंट दोबारा चलाएंगे, तो आपको हमारे मित्रवत एजेंट से उत्तर मिलेगा:

 python3 main.py User: hi Assistant: Hello there! What adventure can we embark on today? Or perhaps, before we set out, we should think about breakfast. Have you had yours yet? I've had mine, of course – can't start the day without a proper breakfast, you know. User: how many breakfasts have you had? Assistant: Ah, well, I've had just 1 breakfast today. But the day is still young, and there's always room for a second, isn't there? What about you? How can I assist you on this fine day?


भाग 2 में, हम अपने एजेंट के लिए टूल को कॉल करने की क्षमता जोड़ेंगे।


आप पूरा कोड मेरे GitHub पर पा सकते हैं।


आपके पढ़ने के लिए धन्यवाद. टिप्पणियों में कोई भी विचार और प्रतिक्रिया सुनकर खुशी हुई। इस तरह की अधिक सामग्री के लिए लिंक्डइन पर मुझे फ़ॉलो करें: https://www.linkedin.com/in/jean-marie-dalmasso-1b5473141/