Discord बॉट कोडिंग AI: LLM API के साथ बनाएं
एक Discord बॉट कोडिंग AI आपके सर्वर के अंदर प्रोग्रामिंग प्रश्नों के उत्तर देता है, एक API के पीछे एक भाषा मॉडल का उपयोग करके। यह ट्यूटोरियल Python में लगभग 70 पंक्तियों में एक बनाता है और उन हिस्सों को कवर करता है जो आमतौर पर टूट जाते हैं।
अपडेट किया गया

मुख्य बिंदु
- बॉट को discord.py, openai पैकेज, एक बॉट टोकन और एक LLM API कुंजी की आवश्यकता है।
- Discord डेवलपर पोर्टल में Message Content intent को सक्षम करें या बॉट खाली संदेश देखेगा।
- प्रत्येक चैनल के लिए एक छोटा इतिहास रखें और इसे काटें, क्योंकि मॉडल कॉल के बीच कुछ भी याद नहीं रखता।
- 2,000 वर्णों पर उत्तरों को विभाजित करें और समानांतर कॉल को सीमित करें ताकि आप 8-अनुरोध सह-कार्यता सीमा के नीचे रहें।
बॉट क्या करेगा
लक्ष्य एक Discord बॉट कोडिंग AI बनाना है जो जब कोई इसे मेंशन करता है तो प्रतिक्रिया दे। उपयोगकर्ता "@helper मेरी list comprehension None क्यों लौटा रही है?" लिखता है, बॉट संदेश मॉडल को भेजता है, और मॉडल का जवाब उसी चैनल में रिप्लाई के रूप में आता है। बॉट प्रत्येक चैनल के पिछले कुछ संवादों को भी याद रखता है, ताकि फॉलो-अप प्रश्न काम करें।
डिज़ाइन में तीन हिस्से हैं। discord.py Discord से कनेक्शन संभालता है। OpenAI Python SDK LLM API से बात करता है, जो यहाँ काम करता है क्योंकि API OpenAI-संगत है। एक छोटा डिक्शनरी संवाद इतिहास रखता है। शुरुआत के लिए आपको डेटाबेस की आवश्यकता नहीं है।
आपको Python 3.9 या उससे नया, एक Discord खाता चाहिए जिससे आप एप्लिकेशन बना सकें, और API कुंजी पृष्ठ से एक API कुंजी चाहिए। नए खाते एक क्लिक में $0.50 का मुफ़्त ट्रायल क्रेडिट क्लेम कर सकते हैं, जो इस बॉट को बनाने और परीक्षण करने के लिए पर्याप्त है।
चरण 1: Discord एप्लिकेशन बनाएं
- Discord डेवलपर पोर्टल खोलें और एक नया एप्लिकेशन बनाएं।
- Bot सेक्शन में, बॉट यूजर बनाएं और उसका टोकन कॉपी करें। इसे पासवर्ड की तरह व्यवहार करें।
- उसी पृष्ठ पर, Privileged Gateway Intents के तहत Message Content Intent को चालू करें। इसके बिना, बॉट खाली टेक्स्ट वाले संदेश प्राप्त करता है, और आप एक घंटा यह सोचने में बिताएंगे कि वह कभी जवाब क्यों नहीं देता।
- OAuth2 में,
botscope और संदेश पढ़ने व भेजने की अनुमतियों के साथ एक invite लिंक जनरेट करें। लिंक खोलें और बॉट को एक टेस्ट सर्वर में जोड़ें।
लाइब्रेरीज़ इंस्टॉल करें और दो एनवायरनमेंट वेरिएबल सेट करें।
pip install discord.py openai
export DISCORD_TOKEN="your-discord-bot-token"
export LLM_API_KEY="your-llm-api-key"
# quick check that the LLM key works, using model uncensored
curl -s https://api.codingllmapi.com/v1/chat/completions \
-H "Authorization: Bearer $LLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"uncensored","messages":[{"role":"user","content":"ping"}],"max_tokens":5}'चरण 2: बॉट का कोड
इसे bot.py के रूप में सेव करें। यह मेंशन होने पर जवाब देता है, प्रत्येक चैनल के लिए बारह संदेशों का इतिहास रखता है, प्रतीक्षा करते समय टाइपिंग इंडिकेटर दिखाता है, और लंबे जवाबों को बांटता है।
import asyncio
import os
import discord
from openai import AsyncOpenAI, RateLimitError, APIError
llm = AsyncOpenAI(
base_url="https://api.codingllmapi.com/v1",
api_key=os.environ["LLM_API_KEY"],
)
SYSTEM = (
"You are a helpful programming assistant in a Discord server. "
"Answer briefly. Put code in fenced blocks. Say so when you are unsure."
)
MAX_TURNS = 12
history = {} # channel id -> list of messages
slots = asyncio.Semaphore(6) # stay under the 8 concurrent request cap
intents = discord.Intents.default()
intents.message_content = True
bot = discord.Client(intents=intents)
def split_reply(text, limit=1900):
parts = []
while len(text) > limit:
cut = text.rfind("\n", 0, limit)
if cut < limit // 2:
cut = limit
parts.append(text[:cut])
text = text[cut:].lstrip("\n")
parts.append(text)
return parts
@bot.event
async def on_message(message):
if message.author.bot or bot.user not in message.mentions:
return
question = message.clean_content.replace(f"@{bot.user.display_name}", "").strip()
if not question:
await message.reply("Ask me a coding question after the mention.")
return
log = history.setdefault(message.channel.id, [])
log.append({"role": "user", "content": question})
del log[:-MAX_TURNS]
async with message.channel.typing():
try:
async with slots:
resp = await llm.chat.completions.create(
model="uncensored",
messages=[{"role": "system", "content": SYSTEM}] + log,
temperature=0.4,
max_tokens=900,
)
except RateLimitError:
await message.reply("The model is busy. Try again in a few seconds.")
log.pop()
return
except APIError:
await message.reply("The model call failed. Try again shortly.")
log.pop()
return
answer = resp.choices[0].message.content or "(empty reply)"
log.append({"role": "assistant", "content": answer})
for part in split_reply(answer):
await message.reply(part)
bot.run(os.environ["DISCORD_TOKEN"])
इसे python bot.py से चलाएं, फिर अपने टेस्ट सर्वर में बॉट को मेंशन करें। पहला जवाब कुछ ही सेकंड में आना चाहिए।
कोड इस प्रकार क्यों लिखा गया है
इतिहास जानबूझकर ट्रिम किया गया है
मॉडल की कोई मेमोरी नहीं है, इसलिए प्रत्येक कॉल में हालिया टर्न्स भेजे जाते हैं। del log[:-MAX_TURNS] के बिना, लिस्ट अनंत तक बढ़ती रहेगी। अंततः यह 100,000-टोकन विंडो को छू लेगा और हर संदेश के साथ आपकी लागत बढ़ती जाएगी। एक बग पर बातचीत के लिए बारह एंट्री पर्याप्त हैं। लंबे थ्रेड्स वाले सर्वर के लिए, इसे बढ़ाएं या पुराने टर्न्स को सारांशित करें।
Discord की 2,000-अक्षर की सीमा
Discord 2,000 अक्षर से लंबे संदेशों को अस्वीकार करता है, और कोड के जवाब जल्दी उस सीमा को छू लेते हैं। split_reply हेल्पर सीमा के पास न्यूलाइन पर कट करता है। यह कोड फेंसेस के बारे में नहीं जानता, इसलिए एक ब्लॉक बीच में कट सकता है। यदि यह आपको परेशान करता है, तो तर्क जोड़ें जो एक भाग के अंत में एक फेंस को बंद करे और अगले भाग की शुरुआत में उसे फिर से खोले।
समानांतर अनुरोधों के लिए सेमाफोर
एक पूर्ण कुंजी 8 समानांतर अनुरोधों की अनुमति देती है, और एक ट्रायल कुंजी 2 की अनुमति देती है। एक व्यस्त सर्वर एक साथ कई प्रश्न उत्पन्न कर सकता है। सेमाफोर आपकी प्रक्रिया के अंदर अतिरिक्त अनुरोधों को कतारबद्ध करता है, उन्हें भेजकर concurrency त्रुटि कोड के साथ 429 प्राप्त करने के बजाय। यदि आप अभी भी ट्रायल कुंजी पर हैं, तो Semaphore(6) को Semaphore(2) में बदलें।
त्रुटियों का शुल्क नहीं लिया जाता
असफल या अस्वीकृत अनुरोधों के लिए शुल्क नहीं लगाया जाता है, इसलिए त्रुटि के बाद पुनः प्रयास करने से लागत दोगुनी नहीं होती है। कोड असफल होने पर उपयोगकर्ता की बारी को इतिहास से हटा देता है, इसलिए पुनः प्रयास करने से एक लटकता हुआ प्रश्न नहीं रहता है जिसका मॉडल पहले ही दो बार सामना कर चुका है।
उत्तरों को बेहतर बनाना
एक बार जब बुनियादी लूप काम कर लेता है, तो कुछ छोटे बदलाव इसे काफी बेहतर बना सकते हैं।
- उत्तर को स्ट्रीम करें।
stream=Trueपास करें और लगभग हर सेकंड में टेक्स्ट के साथ बॉट के संदेश को संपादित करें। हर टोकन पर संपादित न करें, क्योंकि Discord संदेश संपादनों पर अपने रेट लिमिट लागू करता है। एक स्ट्रीम किए गए अनुरोध में कॉन्करेंसी स्लॉट अंत तक बना रहता है, इसलिए पूरे स्ट्रीम के आसपास सेमाफोर रखें। - स्लैश कमांड का उपयोग करें।
/askजैसे कमांड में mention पार्सिंग से बचा जाता है और Message Content intent की पूरी तरह आवश्यकता नहीं होती है, जिससे बाद में बॉट की सत्यापन प्रक्रिया सरल रहती है यदि यह छोटे सर्वरों की संख्या से आगे बढ़ जाता है। - प्रत्येक उपयोगकर्ता के लिए इतिहास। यदि एक ही चैनल में कई लोग असंबंधित प्रश्न पूछते हैं, तो इतिहास को चैनल और उपयोगकर्ता के आधार पर कुंजीबद्ध करें।
- सिस्टम प्रॉम्प्ट को ट्यून करें। अपनी कम्युनिटी द्वारा उपयोग की जाने वाली भाषाओं के नाम दें, छोटे उत्तरों के लिए कहें, और मॉडल को स्पष्टीकरण प्रश्न पूछने के लिए कहें जब समस्या अस्पष्ट हो। प्रॉम्प्ट बदलाव मुफ़्त हैं और अक्सर मॉडल बदलावों से बेहतर परिणाम देते हैं।
- तापमान कम करें। कोड के लिए, 0.2 और 0.4 के बीच के मान डिफ़ॉल्ट की तुलना में अधिक स्थिर परिणाम देते हैं।
सामान्य विफलताओं का निवारण
जब एक नया बॉट चुप रहता है, तो कारण लगभग हमेशा नीचे दिए गए आइटमों में से एक होता है। इन्हें इस क्रम में जांचें।
- बॉट ऑनलाइन है लेकिन कभी जवाब नहीं देता। डेवलपर पोर्टल में Message Content intent बंद है, या कोड में
intents.message_content = Trueगायब है। दोनों को सेट करना आवश्यक है। - यह केवल कुछ चैनलों में जवाब देता है। बॉट के पास अन्य चैनलों में संदेश पढ़ने या भेजने की अनुमति नहीं है। चैनल की अनुमति ओवरराइड्स की जाँच करें, न केवल सर्वर-व्यापी भूमिका की।
- प्रत्येक उत्तर एक "व्यस्त" संदेश है। आप संभवतः 429 त्रुटि प्राप्त कर रहे हैं। अपवाद बॉडी को एक बार प्रिंट करें। यदि कोड
rate_limitedदिखाता है, तो आपने पूर्ण कुंजी पर प्रति मिनट 300 अनुरोधों की सीमा या ट्रायल कुंजी पर 60 अनुरोधों की सीमा पार कर ली है। यदि यहconcurrencyबताता है, तो सेमाफोर का आकार कम करें। - प्रथम कॉल पर प्रमाणीकरण त्रुटि आती है। बॉट चलाए जाने वाले प्रक्रिया के वातावरण में LLM कुंजी अनुपस्थित है। एक टर्मिनल टैब में निर्यात की गई कुंजी अन्यत्र शुरू की गई सेवा के लिए दिखाई नहीं देती।
- उत्तर कट जाता है। नमूने में
max_tokens=900लंबे उत्तरों को रोकता है। इसे बढ़ाएं या हटा दें, क्योंकिmax_tokensवैकल्पिक है और पूर्णता विंडो के शेष हिस्से का उपयोग कर सकती है। - बॉट अपने ही संदेशों का उत्तर देता है। यह लूप तब होता है जब आप
message.author.botजाँच छोड़ देते हैं। इसे बनाए रखें।
डिबगिंग के लिए, प्रत्येक कॉल के लिए X-Request-Id मान लॉग करें। OpenAI SDK के साथ, आप llm.chat.completions.with_raw_response.create(...) कॉल करके कच्चे प्रतिक्रिया से इसे पढ़ सकते हैं और फिर .headers पढ़ सकते हैं। यदि आप किसी विशिष्ट विफलता के बारे में सहायता से संपर्क करते हैं, तो वह ID उन्हें सटीक अनुरोध खोजने में सक्षम बनाता है।
इसे चलाने में लागत
मूल्य $0.15 प्रति 1M इनपुट टोकन और $0.50 प्रति 1M आउटपुट टोकन है, बिना किसी सदस्यता के। एक सामान्य विनिमय पर विचार करें: सिस्टम प्रॉम्प्ट और बारह इतिहास प्रविष्टियाँ मिलकर लगभग 2,500 इनपुट टोकन बनाती हैं, और उत्तर लगभग 400 टोकन का होता है।
इनपुट: 2,500 x $0.15 / 1,000,000 = $0.000375। आउटपुट: 400 x $0.50 / 1,000,000 = $0.0002। एक उत्तर की लागत लगभग $0.000575 आती है। एक समुदाय जो एक दिन में 500 प्रश्न पूछता है, वह 500 x $0.000575 = $0.2875 खर्च करेगा, जो तीस सेंट से थोड़ा कम है। आपके अंक लंबे कोड पेस्ट के साथ अलग होंगे, इसलिए एक सप्ताह के लिए resp.usage लॉग करें और वास्तविक औसत पढ़ें। मूल्य निर्धारण पृष्ठ टॉप-अप विकल्प दिखाता है: $20 से $500 तक कोई भी पूर्ण राशि, $50 से +5%, $100 से +10% और $200 से +15%, कार्ड या क्रिप्टो द्वारा भुगतान।
दुरुपयोग को सीमित करने के लिए, प्रति-उपयोगकर्ता कूलडाउन और प्रश्न की लंबाई पर एक सीमा जोड़ें। ये दो जांच आपके बैलेंस की रक्षा किसी अन्य चीज की तुलना में बेहतर करते हैं।
होस्टिंग और सुरक्षा नोट्स
बॉट एक लंबे समय तक चलने वाला प्रोसेस है। एक छोटी आभासी मशीन या कंटेनर होस्ट पर्याप्त है, क्योंकि भारी कार्य API साइड पर होता है। इसे एक प्रोसेस मैनेजर के तहत चलाएं ताकि क्रैश के बाद यह पुनः शुरू हो, और दोनों टोकन को एनवायरनमेंट वेरिएबल्स या सिक्रेट्स स्टोर में रखें, रीपॉजिटरी में कभी नहीं।
विचार करें कि आपका सर्वर क्या अनुमति देता है। मॉडल को कानूनी वयस्क उपयोग के लिए सामग्री अस्वीकृतियों के बिना जवाब देने के लिए ट्यून किया गया है, इसलिए यह सुरक्षा परीक्षण या सीमांत कथाओं पर चर्चा कर सकता है जिसे एक कठोर सहायक अस्वीकार कर सकता है। यदि आपके समुदाय में नाबालिग सदस्य शामिल हैं, तो सिस्टम प्रॉम्प्ट में नियम सेट करें, बॉट को विशिष्ट चैनलों तक सीमित करें, और याद रखें कि Discord के अपने नियम आपके बॉट पर भी लागू होते हैं। नाबालिगों को यौन रूप से दर्शाने वाली सामग्री इस API पर अपवाद के बिना प्रतिबंधित है।
stop, seed जैसे पूर्ण पैरामीटर विवरण और फ़ंक्शन कॉलिंग API दस्तावेज़ में उपलब्ध हैं। यदि आप चाहते हैं कि बॉट कोड चलाए या रिपॉजिटरी पढ़े, तो फ़ंक्शन कॉलिंग ही सही रास्ता है, और आप तय करते हैं कि मॉडल किन फ़ंक्शन्स का अनुरोध कर सकता है। इस मॉडल के प्रोग्रामिंग-केंद्रित उपयोग के लिए, कोडिंग के लिए बिना सेंसर AI मॉडल के बारे में पृष्ठ देखें।
अधिक गाइड
प्रश्न और उत्तर
क्या मुझे Message Content इंटेंट की आवश्यकता है?
हाँ, यदि बॉट सामान्य संदेश और मेंशन पढ़ता है। यदि आप केवल स्लैश कमांड्स का उपयोग करते हैं, तो आपको इसकी आवश्यकता नहीं है।
क्या बॉट उत्तर स्ट्रीम कर सकता है?
हाँ। stream=True सेट करें और Discord संदेश को एक शांत अंतराल पर संपादित करें, जैसे कि प्रति सेकंड एक बार, ताकि आप Discord के अपने लिमिट्स के भीतर रहें।
यदि बहुत सारे लोग एक साथ पूछते हैं तो क्या होता है?
पूर्ण कुंजी पर 8 समानांतर अनुरोधों के बाद, API HTTP 429 concurrency कोड के साथ लौटाता है। आपके कोड में एक सेमाफोर अतिरिक्त प्रश्नों को क्यू में लगाता है।
क्या बॉट पुनः प्रारंभ होने के बाद बातचीत याद रखेगा?
यहाँ उपयोग किए गए डिक्शनरी के साथ नहीं। यदि आप इसे रीस्टार्ट के बाद जीवित रहना चाहते हैं, तो इतिहास को SQLite या Redis में स्टोर करें।
क्या Discord बॉट में API कुंजी सुरक्षित है?
हाँ यदि यह आपके सर्वर पर एनवायरनमेंट वेरिएबल में रहता है। इसे कभी चैनल में पोस्ट न करें या पब्लिक रीपॉजिटरी में कमीट न करें।
आपकी कुंजी बस एक फ़ॉर्म दूर है
एक खाता बनाएँ, कुंजी कॉपी करें, बेस URL बदलें। सेटअप यही है।
API कुंजी पाएँ