Discord Bot Coding AI: bouw er een met een LLM API
Een Discord bot coding AI beantwoordt programmeervragen binnen je server, met behulp van een taalmodel achter een API. Deze tutorial bouwt er een in ongeveer 70 regels Python en behandelt de onderdelen die vaak fout gaan.
Bijgewerkt

Belangrijkste punten
- De bot heeft discord.py, het openai-pakket, een bot token en een LLM API-sleutel nodig.
- Schakel de Message Content intent in in het Discord developer portal, anders ziet de bot lege berichten.
- Houd een korte geschiedenis per kanaal bij en knip deze, omdat het model niets onthoudt tussen calls.
- Splits antwoorden bij 2.000 tekens en beperk parallelle calls zodat je onder de concurrency cap van 8 verzoeken blijft.
Wat de bot zal doen
Het doel is een Discord-bot coderings-AI die reageert wanneer iemand hem noemt. Een gebruiker typt "@helper waarom geeft mijn list comprehension None?", de bot stuurt de boodschap naar het model en het antwoord van het model komt terug als reply in hetzelfde kanaal. De bot onthoudt ook de laatste paar wisselwerkingen van elk kanaal, zodat vervolgvragen werken.
Het ontwerp bestaat uit drie onderdelen. discord.py verzorgt de verbinding met Discord. De OpenAI Python SDK communiceert met de LLM API, wat hier werkt omdat de API OpenAI-compatible is. Een kleine dictionary houdt de gespreksgeschiedenis bij. Je hebt geen database nodig om te beginnen.
Je hebt Python 3.9 of nieuwer nodig, een Discord account waarmee je een applicatie kunt maken, en een API-sleutel van de API-sleutel pagina. Nieuwe accounts kunnen met één klik $0,50 aan trial credit claimen, wat genoeg is om deze bot te bouwen en te testen.
Stap 1: maak de Discord applicatie
- Open het Discord-ontwikkelaarsportaal en maak een nieuwe applicatie aan.
- Maak in het Bot-gedeelte de botgebruiker aan en kopieer het token. Behandel het als een wachtwoord.
- Schakel op dezelfde pagina Message Content Intent in onder Privileged Gateway Intents. Zonder dit ontvangt de bot berichten met lege tekst en zul je een uur besteden aan het zoeken waarom hij nooit antwoordt.
- Genereer in OAuth2 een uitnodigingslink met de
botscope en de rechten om berichten te lezen en te versturen. Open de link en voeg de bot toe aan een testserver.
Installeer de bibliotheken en stel twee omgevingsvariabelen in.
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}'Stap 2: de bot code
Sla dit op als bot.py. Het antwoordt wanneer het wordt genoemd, houdt twaalf berichten van geschiedenis per kanaal bij, toont de typindicator terwijl het wacht en splitst lange antwoorden.
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"])
Voer het uit met python bot.py, noem de bot vervolgens in je testserver. Het eerste antwoord zou binnen enkele seconden moeten aankomen.
Waarom de code zo is geschreven
Geschiedenis wordt opzettelijk bijgesneden
Het model heeft geen geheugen, dus elk verzoek stuurt de recente wisselwerkingen. Zonder del log[:-MAX_TURNS] zou de lijst oneindig groeien. Uiteindelijk zou je het contextvenster van 100.000 tokens raken en zouden je kosten met elk bericht stijgen. Twaalf entries is genoeg voor een gesprek over één bug. Voor een server met lange threads, verhoog dit of vat oudere wisselwerkingen samen.
De 2.000-teken limiet van Discord
Discord wijst berichten langer dan 2.000 tekens af, en code-antwoorden raken dat snel. De helper split_reply knipt bij een newline in de buurt van de limiet. Het weet niets over code fences, dus een blok kan in het midden worden afgekapt. Als dat je stoort, voeg dan logica toe die een fence aan het einde van één deel sluit en aan het begin van het volgende weer opent.
Een semaphore voor concurrentie
Een volledige sleutel staat 8 gelijktijdige verzoeken toe, en een proefsleutel staat er 2 toe. Een drukke server kan meerdere vragen tegelijk genereren. De semaphore zet extra aanroepen binnen je proces in een wachtrij in plaats van ze te versturen en een 429 te ontvangen met de foutcode concurrency. Als je nog steeds de proefsleutel gebruikt, verander Semaphore(6) dan in Semaphore(2).
Fouten worden niet in rekening gebracht
Mislukte of geweigerde verzoeken worden niet gefactureerd, dus een retry na een fout verdubbelt de kosten niet. De code verwijdert de gebruikersbeurt van de geschiedenis bij een fout, zodat een retry geen hangende vraag achterlaat die het model al twee keer heeft gezien.
Antwoorden beter laten voelen
Zodra de basislus werkt, verbeteren een paar kleine wijzigingen het aanzienlijk.
- Stream het antwoord. Geef
stream=Truedoor en bewerk het bericht van de bot elke seconde of zo met de tekst tot nu toe. Bewerk niet op elke token, omdat Discord zijn eigen rate limits toepast op berichtbewerkingen. Een gestreamd verzoek houdt zijn concurrentieslot vast tot het eindigt, dus houd de semaphore rond de hele stream. - Gebruik slashcommands. Een commando zoals
/askvermijdt het parseren van mentions en heeft helemaal geen Message Content intent nodig, wat de bot ook makkelijker te verifiëren maakt later als het groeit voorbij een klein aantal servers. - Per gebruiker geschiedenis. Koppel de geschiedenis aan kanaal en gebruiker als meerdere mensen ongerelateerde vragen stellen in één kanaal.
- Stel de systeemprompt af. Noem de talen die je community gebruikt, vraag om korte antwoorden en vertel het model om een verduidelijkende vraag te stellen als het probleem vaag is. Prompt-aanpassingen zijn gratis en vaak beter dan model-aanpassingen.
- Verlaag de temperature. Voor code geven waarden tussen 0,2 en 0,4 stabielere resultaten dan de standaard.
Probleemoplossing voor de veelvoorkomende fouten
Wanneer een nieuwe bot stil blijft, is de oorzaak bijna altijd een van de onderstaande punten. Controleer ze in deze volgorde.
- De bot is online maar antwoordt nooit. De Message Content intent staat uit in het developer portal, of
intents.message_content = Trueontbreekt in de code. Beide moeten worden ingesteld. - Het antwoordt alleen in sommige kanalen. De bot heeft geen toestemming om berichten in de anderen te lezen of te versturen. Controleer de rechten-overwrites van het kanaal, niet alleen de serverbrede rol.
- Elk antwoord is een "bezet"-bericht. Je raakt waarschijnlijk een 429. Print de body van de exception één keer. Als de code
rate_limitedzegt, heb je de per-minuut limiet van 300 verzoeken op een volledige sleutel of 60 op een proefsleutel gepasseerd. Als hetconcurrencyzegt, verlaag dan de semaphore grootte. - Een authenticatiefout verschijnt bij het eerste verzoek. De LLM-sleutel ontbreekt in de omgevingsvariabelen van het proces dat de bot uitvoert. Een sleutel die in één terminaltabblad is geëxporteerd, is niet zichtbaar voor een service die elders is gestart.
- Het antwoord wordt afgekapt. De
max_tokens=900in het voorbeeld stopt lange antwoorden. Verhoog het, of verwijder het, aangezienmax_tokensoptioneel is en de voltooiing de rest van het venster kan gebruiken. - De bot antwoordt op zijn eigen berichten. Die lus treedt op als je de
message.author.botcheck verwijdert. Laat die staan.
Voor foutopsporing, log de X-Request-Id waarde voor elk verzoek. Met de OpenAI SDK kun je deze lezen uit de ruwe response door llm.chat.completions.with_raw_response.create(...) aan te roepen en dan .headers te lezen. Als je support contacteert over een specifieke fout, stelt die ID hen in staat het exacte verzoek te vinden.
Wat dit kost om te draaien
Prijzen zijn $0,15 per 1M invoertokens en $0,50 per 1M outputtokens, zonder abonnement. Neem een typische uitwisseling: de systeemprompt plus twaalf geschiedenis entries maken ongeveer 2.500 invoertokens, en het antwoord is ongeveer 400 tokens.
Input: 2.500 x $0,15 / 1.000.000 = $0,000375. Output: 400 x $0,50 / 1.000.000 = $0,0002. Eén antwoord kost ongeveer $0,000575. Een community die 500 vragen stelt per dag zou 500 x $0,000575 = $0,2875 uitgeven, iets minder dan dertig cent. Jouw cijfers verschillen met langere code fragmenten, dus log resp.usage gedurende een week en lees de echte gemiddelden. De prijzenpagina toont de opties om op te waarderen: elk geheel bedrag van $20 tot $500, met +5% vanaf $50, +10% vanaf $100 en +15% vanaf $200, betaald met kaart of crypto.
Om misbruik te beperken, voeg een per-gebruiker cooldown en een limiet voor de vraaglengte toe. Die twee controles beschermen je saldo beter dan alles wat je kunt toevoegen.
Hosting- en veiligheidsnotities
De bot is een langlopend proces. Een kleine virtuele machine of een container host is genoeg, aangezien het zware werk aan de API-kant gebeurt. Draai het onder een procesmanager zodat het herstart na een crash, en houd beide tokens in omgevingsvariabelen of een secrets store, nooit in de repository.
Denk na over wat je server toestaat. Het model is afgestemd om te antwoorden zonder inhoudelijke weigeringen voor legaal gebruik door volwassenen, dus het zal veiligheidstesten of grensverleggende fictie bespreken die een strengere assistent zou weigeren. Als je community jongere leden bevat, stel regels op in de systeemprompt, beperk de bot tot specifieke kanalen en onthoud dat de eigen voorwaarden van Discord ook op je bot van toepassing zijn. Inhoud die minderjarigen seksualiseert is op deze API zonder uitzondering verboden.
Volledige parameterdetails, zoals stop, seed en function calling, staan in de API-documentatie. Als je wilt dat de bot code uitvoert of repositories leest, is function calling de route, en jij beslist welke functies het model mag aanvragen. Voor programmeergerichte toepassingen van dit model, zie de pagina over het ongecensureerde AI-model voor coderen.
Meer handleidingen
Vragen en antwoorden
Heb ik de Message Content intent nodig?
Ja, als de bot normale berichten en mentions leest. Als je alleen slashcommands gebruikt, heb je het niet nodig.
Kan de bot antwoorden streamen?
Ja. Stel stream=True in en bewerk het Discord-bericht in een rustig interval, zoals één keer per seconde, zodat je binnen de eigen limieten van Discord blijft.
Wat gebeurt er als te veel mensen tegelijk vragen?
Na 8 gelijktijdige verzoeken op een volledige sleutel, retourneert de API HTTP 429 met de code concurrency. Een semaphore in je code zet de extra vragen in plaats daarvan in een wachtrij.
Onthoudt de bot gesprekken na een herstart?
Niet met het woordenboek dat hier wordt gebruikt. Sla geschiedenis op in SQLite of Redis als je wilt dat het herstarts overleeft.
Is de API-sleutel veilig in een Discord-bot?
Ja als het op je server blijft in een omgevingsvariabele. Plaats het nooit in een kanaal of commit het naar een openbare repository.
Je sleutel is nog maar één formulier verwijderd
Maak een account aan, kopieer de sleutel, pas de base URL aan. Dat is de hele setup.
API-sleutel aanvragen