कोड से मॉडल को कॉल करना

पिछले अध्याय ने संदेशों की एक सूची बनाई। यह अध्याय उस सूची को Python से वास्तविक मॉडल में भेजता है और एक उत्तर वापस पाता है। यह राउंड ट्रिप इन मॉडलों के साथ बनाने का सबसे छोटा पूर्ण लूप है, और लगभग हर फीचर जो आप लिखेंगे वह इसके ऊपर बैठा है।
आप एक प्रॉम्प्ट टाइप करते हैं, आपका कोड इसे कहीं भेजता है, और टेक्स्ट वापस आता है। ऐसा लगता है कि मॉडल आपके प्रोग्राम में रहता है। यह नहीं करता, और यह देखना कि यह वास्तव में कहाँ चलता है, लागत, गति, और विचित्रताओं को समझाता है जो आप मिलेंगे।
तो चित्र करें कि शारीरिक रूप से क्या हो रहा है। मॉडल प्रदाता के सर्वर पर एक विशाल पैरामीटर सेट है, हार्डवेयर पर जो आप कभी नहीं देखेंगे। जब आप इसे कॉल करते हैं, आपका कोड इंटरनेट पर एक साधारण वेब अनुरोध भेजता है जो आपके संदेश ले जाता है।
प्रदाता अपनी मशीन पर भविष्यवाणी लूप चलाता है और उत्पन्न टोकन आपको वापस भेजता है। एक मॉडल कॉल किसी और के कंप्यूटर पर कुछ समय किराए पर लेना है। यह फ्रेमिंग बहुत कुछ समझदारी करता है: लेटेंसी मॉडल उनके अंत में एक समय में टोकन उत्पन्न कर रहा है, लागत उन्हें उस कंप्यूट के लिए चार्ज कर रही है, और पूरी चीज एक नेटवर्क कॉल है, सब कुछ के साथ जो सूचित करता है।
उदाहरण आधिकारिक OpenAI लाइब्रेरी का उपयोग करते हैं। अन्य प्रदाता विवरण में भिन्न होते हैं, लेकिन आकार लगभग हर जगह समान है: आप संदेशों की एक सूची भेजते हैं, आप एक संदेश वापस पाते हैं। वह समानता लॉक-इन के विरुद्ध आपका बीमा है, क्योंकि एक ही कोड एक ओपन मॉडल की ओर इशारा कर सकता है जिसे आप कहीं और होस्ट या किराए पर लेते हैं, अक्सर केवल बेस URL में परिवर्तन के साथ (खुले और बंद मॉडल उस पसंद को कवर करते हैं)।
अनुरोध
pip install openai के साथ लाइब्रेरी स्थापित करें, एक क्लाइंट बनाएँ, और इसे कॉल करें। क्लाइंट एक पर्यावरण चर से आपकी API कुंजी पढ़ता है, इसलिए कुंजी कभी भी आपके कोड में दिखाई नहीं देती है।
from openai import OpenAI
# पर्यावरण से OPENAI_API_KEY पढ़ता है
client = OpenAI()
# वह एक पंक्ति है जिसे आप मॉडल स्वैप करने के लिए बदलते हैं
MODEL = "gpt-4o-mini"
response = client.chat.completions.create(
model=MODEL,
messages=[
{"role": "system", "content": "You are a concise assistant. Answer in one sentence."},
{"role": "user", "content": "Why is the sky blue?"},
],
)दो चीजें आवश्यक हैं: model, वह मॉडल का नाम जिसे आप चलाना चाहते हैं, और messages, पिछले अध्याय से भूमिका-टैग किए गए संदेशों की सूची। बाकी सब कुछ के पास एक डिफॉल्ट है।
मॉडल नाम एक एकल स्थिरांक में रहता है पर ध्यान दें। एक क्षेत्र में जहाँ एक बेहतर, सस्ता मॉडल हर कुछ महीनों में उतरता है, यह जानबूझकर है। मॉडल नाम को एक जगह रखें ताकि मॉडल स्वैप करना एक पंक्ति परिवर्तन हो। यह अभ्यास में परिवर्तन नियम है: अस्थिर विशिष्ट को जहाँ आप पा सकते हैं, अपने कोड में बिखरे हुए नहीं।
model और messages। मॉडल नाम एक एकल स्थिरांक में होना चाहिए, क्योंकि हर कुछ महीनों में एक सस्ता या बेहतर मॉडल दिखाई देता है और आप इसे नौ फाइलों में पेस्ट किए जाने के लिए शिकार नहीं करना चाहते। मुझे धीमे तरीके से सीखने में बहुत समय लगा, एक मॉडल का नाम बदलने के बाद और मुझे इसे नौ फाइलों में पाया। प्रतिक्रिया पढ़ना
उत्तर कुछ संरचना में लपेटा हुआ वापस आता है। टेक्स्ट जो आप चाहते हैं वह अंदर एक पाथ है, लेकिन बाकी संरचना जानने के लायक है, क्योंकि यह बताता है कि क्या हुआ।
choice = response.choices[0]
# उत्तर टेक्स्ट
print(choice.message.content)
# "stop" -> मॉडल अपने आप समाप्त हो गया
print(choice.finish_reason)
# Usage(prompt_tokens=24, completion_tokens=18, total_tokens=42)
print(response.usage)वहाँ तीन चीजें मायने रखती हैं। message.content टेक्स्ट है, choices[0] के अंदर बैठा है क्योंकि API एक से अधिक विकल्प लौटा सकता है, हालांकि आप लगभग हमेशा एक पूछते हैं और पहले को पढ़ते हैं।
finish_reason बताता है कि मॉडल क्यों रुका। "stop" का अर्थ है यह अपना विचार समाप्त कर गया, जबकि "length" का अर्थ है यह आपकी टोकन कैप में भाग गया और आधे-अधूरे उत्तर में कट गया। उस फ़ील्ड को चेक करना यह है कि आप कोड में एक काटे गए उत्तर को कैसे पकड़ते हैं आँख से नहीं।
और usage टोकन की रिपोर्ट करता है जो कॉल ने खर्च किया, प्रॉम्प्ट में विभाजित जो आप भेजते हैं और समाप्ति जिसे यह लिखता है। वह उपयोग ऑब्जेक्ट आपका बिल है, आइटमाइज़्ड। हर कॉल आपको बिल्कुल बताता है कि टोकन में इसकी लागत क्या है, जो संख्या है जिसे देखना है जब आप बनाते हैं।
response.choices[0].message.content पर है, लेकिन दो पड़ोसी भी मायने रखते हैं। finish_reason बताता है कि यह क्यों रुका: "stop" का अर्थ है किया गया, "length" का अर्थ है यह आपकी टोकन कैप को मार गया और कट गया। और response.usage टोकन में आपका बिल है, प्रॉम्प्ट और समाप्ति को विभाजित किया गया, तो आपको कभी अनुमान लगाने की आवश्यकता नहीं है कि एक कॉल की कीमत क्या है। जानने के लायक पैरामीटर
model और messages से परे, दो वैकल्पिक सेटिंग्स लगातार आती हैं।
temperature कैसे LLMs काम करते हैं से यादृच्छिकता डायल है, ठोस बनाया गया। निम्न मूल्य (0 के पास) मॉडल को इसकी शीर्ष चुनावों के पास रखते हैं: केंद्रीभूत और दोहराए जाने योग्य, जो आप निष्कर्षण और वर्गीकरण के लिए चाहते हैं। उच्च मूल्य (लगभग 0.7 से 1) इसे कम संभावना टोकन के लिए पहुँचने देते हैं: अधिक विविध और रचनात्मक, और भटकने के लिए अधिक प्रवण। आप अनुकूल कर रहे हैं कि मॉडल कितनी बोल्डली नमूने, कुछ नहीं।
max_tokens कैप करता है कि उत्तर कितने टोकन तक चल सकता है। यह आपको एक भाग्यहीन उत्तर और भाग्यहीन बिल से बचाता है। max_tokens को बहुत कम सेट करें और मॉडल कट जाता है, जो बिल्कुल पिछले सेक्शन से "length" समाप्ति कारण है, तो वास्तविक हेडरूम छोड़ दें।
response = client.chat.completions.create(
model=MODEL,
messages=messages,
# केंद्रीभूत और सुसंगत
temperature=0.2,
# उत्तर की लंबाई को कैप करें
max_tokens=300,
)temperature अनुकूल करता है कि मॉडल कितनी बोल्डली नमूने: केंद्रीभूत, दोहराए जाने योग्य उत्तर के लिए कम, विविध, रचनात्मक लोगों के लिए उच्च। max_tokens उत्तर की लंबाई को कैप करता है आपके बिल को बचाने के लिए, लेकिन बहुत कम सेट करें यह "length" कटन को ट्रिगर करता है, तो हेडरूम छोड़ दें। निष्कर्षण और वर्गीकरण के लिए, हर बार कम तापमान के लिए पहुँचें। स्ट्रीमिंग
डिफॉल्ट रूप से आप पूरे उत्तर को समाप्त होने तक प्रतीक्षा करते हैं, फिर यह एक बार में आता है। चूँकि मॉडल एक समय में टोकन उत्पन्न करता है, एक लंबा उत्तर मतलब एक लंबी प्रतीक्षा कुछ नहीं देख रहे हैं।
स्ट्रीमिंग प्रत्येक टोकन को आपको उसी क्षण भेजता है जब यह उत्पन्न होता है, तो टेक्स्ट तुरंत दिखाई देता है और लाइव भर जाता है, जिस तरह चैट ऐप्स एक उत्तर को टाइप करते हुए दिखाते हैं।
stream = client.chat.completions.create(
model=MODEL,
messages=messages,
stream=True,
)
for chunk in stream:
piece = chunk.choices[0].delta.content
if piece:
print(piece, end="", flush=True)कुल पीढ़ी समय दोनों तरीकों से समान है; मॉडल तेजी से नहीं है। स्ट्रीमिंग केवल बदलता है कब आप टोकन देखते हैं, इसे जैसे ही यह पैदा होता है सतह के रूप में इसे अंत तक सभी को वापस रखने के बजाय।
आप इसे चंक्स पर पुनरावृत्ति करके और टेक्स्ट के प्रत्येक delta को प्रिंट करके हैंडल करते हैं। ट्रेड-ऑफ थोड़ी अधिक कोड एक बहुत बेहतर प्रतीक्षा के लिए है। स्ट्रीमिंग बदलता है कब आप टोकन देखते हैं, कितनी तेजी से नहीं आते हैं।
हर कॉल स्वतंत्र है
यह अध्याय में सबसे महत्वपूर्ण व्यवहार है, और यह संदर्भ विंडो पाठ से सीधे अनुसरण करता है। API स्टेटलेस है: प्रत्येक अनुरोध पूरी तरह से अपने आप पर खड़ा है। प्रदाता का सर्वर आपकी पिछली कॉल को याद नहीं करता है। यह बिल्कुल उन संदेशों पर भविष्यवाणी चलाता है जो आप भेजते हैं, परिणाम लौटाता है, और अगली बार के लिए विनिमय के बारे में कुछ नहीं रखता है।
तो बातचीत कहीं भी संग्रहीत नहीं है मॉडल द्वारा या API द्वारा। यह आपके कोड में रहता है। यदि आप चाहते हैं कि टर्न दो को जानना चाहिए कि टर्न एक में क्या हुआ, आप संदेशों की चलती सूची को अपने आप रखते हैं और हर बार पूरी चीज को फिर से भेजते हैं। एक आगे-पीछे चैट एक भ्रम है जिसे आप हर कॉल पर एक बढ़ते इतिहास को पुनः भेज कर बनाते हैं।
यह भी यही है कि क्यों एक लंबी बातचीत समय के साथ प्रति संदेश अधिक खर्च करता है: प्रत्येक कॉल इनपुट टोकन के रूप में सभी पूर्व मोड़ को फिर से भेजता है, तो प्रॉम्प्ट बढ़ता रहता है यहाँ तक कि जब उपयोगकर्ता का नया प्रश्न छोटा है।
history = [
{"role": "system", "content": "You are a friendly travel assistant. Keep answers short."},
]
def chat(user_text):
history.append({"role": "user", "content": user_text})
# पूरा इतिहास हर बार ऊपर जाता है; सर्वर कुछ नहीं याद करता है
response = client.chat.completions.create(model=MODEL, messages=history)
reply = response.choices[0].message.content
# अगली बार के लिए उत्तर रखें
history.append({"role": "assistant", "content": reply})
return reply
chat("I have a weekend in दिल्ली. What should I see?")
# केवल काम करता है क्योंकि पहली बातचीत इतिहास में है और टर्न एक भेजा जाता है
chat("Which of those is best for kids?")दूसरा सवाल केवल समझदारी में आता है क्योंकि पहली बातचीत और इसका उत्तर अभी भी history में है और साथ भेजा जाता है। आप स्मृति हैं। यह एक विचार, कि आप हर बार पूर्ण संदर्भ को असेंबल और पुनः भेजते हैं, बातचीत को आधार करता है, और बाद में यह उपकरण उपयोग, पुनर्प्राप्ति, और एजेंट को भी आधार करता है। वे सभी यह तय करने के भिन्नताएँ हैं कि प्रत्येक स्वतंत्र कॉल से पहले उन संदेशों की सूची में क्या जाता है।
जब चीजें गलत हो जाती हैं
एक मॉडल कॉल किसी और के सर्वर पर एक नेटवर्क कॉल है, तो यह सभी तरीकों से विफल हो जाता है नेटवर्क कॉल विफल होते हैं। शुरुआत से डिजाइन करें।
- त्रुटियाँ और दर सीमाएँ। प्रदाता सीमा करता है कि आप कितने अनुरोध भेज सकते हैं एक विंडो में। कैप को हिट करें और कॉल दर-सीमा त्रुटि के साथ विफल। मानक प्रतिक्रिया प्रतीक्षा है और पुनः प्रयास, प्रत्येक विफलता के बाद प्रतीक्षा को लंबा करना (बैकऑफ) तो आप व्यस्त सेवा को हथौड़ा नहीं करते हैं।
- समय सीमाएँ। एक कॉल लंबित हो सकता है। एक समय सीमा निर्धारित करें तो एक धीमी अनुरोध आपके ऐप को फ्रीज नहीं करता।
- कुंजियाँ सर्वर पर रहती हैं। आपकी API कुंजी एक पासवर्ड है जो आपके पैसे खर्च करता है। कभी API कुंजी को ब्राउज़र कोड में न डालें। कोई भी dev उपकरण खोल सकता है और पढ़ सकता है। ब्राउज़र आपके बैकएंड से बात करता है, और आपका बैकएंड, कुंजी रखते हुए, मॉडल से बात करता है।
- मान लें कि कोई भी उत्तर गलत हो सकता है। यहाँ तक कि एक सफल कॉल भ्रम या खराब आउटपुट लौटा सकता है, तो अगले अध्याय परिणाम को कुछ के बारे में हैं जिस पर आपका कोड विश्वास कर सकता है।
def ask_model(messages):
try:
response = client.chat.completions.create(
model=MODEL,
messages=messages,
# 20 सेकंड के बाद हार मान जाएँ
timeout=20,
)
return response.choices[0].message.content
except Exception as err:
print("Model call failed:", err)
return "Sorry, something went wrong. Please try again."
