Open source Discord-bot met een ongecensureerd LLM
Een open source Discord-bot die via een LLM praat, bestaat uit ongeveer tachtig regels Python. Deze gids geeft je de code, de limieten die je moet respecteren en de kosten per antwoord, met behulp van een OpenAI-compatible API met een model dat geen wettelijke verzoeken van volwassenen weigert.

Belangrijkste punten
- discord.py plus de OpenAI SDK is genoeg; wijs de SDK naar https://api.openrouternsfw.com/v1 en gebruik het model uncensored.
- Schakel het Message Content-intent in in het Discord developer portal, anders ziet de bot lege berichten.
- Gebruik een semaphore onder de 8 om binnen de limiet voor gelijktijdige verzoeken te blijven, en bewaar inhoud voor volwassenen in kanalen die als leeftijdsgelimiteerd zijn gemarkeerd.
- Een antwoord met 1.500 input- en 300 output-tokens kost $0,000375, dus ongeveer $3,75 per 10.000 antwoorden.
Geen kaart nodig. Na registratie claim je met één klik $0,50 gratis proeftegoed (eenmaal per persoon).
API-sleutel aanvragenWat je bouwt
De onderstaande bot antwoordt wanneer iemand hem noemt. Het houdt een korte geschiedenis per kanaal bij, stuurt deze naar het chat-completions-endpoint en plaatst het antwoord. Het is gewone Python, MIT-vriendelijk en heeft geen database. Je kunt het allemaal in één keer lezen, wat het punt is van een open source project: iemand anders kan het forken en het begrijpen.
Het model erachter is een enkel open-weight tekstmodel, gerund door een onafhankelijke provider en afgestemd om te antwoorden zonder inhoudsweigeringen voor wettelijk volwassen gebruik. Dat past bij Discord-gemeenschappen die rond fictie, roleplay of volwassen gesprek zijn gebouwd. Er gelden vanaf het begin twee regels. Ten eerste is seksuele inhoud met minderjarigen niet toegestaan via de API en mag dat niet onderdeel zijn van het ontwerp van je bot. Ten tweede heeft Discord zijn eigen regels en instellingen voor leeftijdsgelimiteerde kanalen, en ben jij verantwoordelijk voor het naleven daarvan. Houd inhoud voor volwassenen beperkt tot kanalen die als zodanig zijn gemarkeerd en tot servers waar leden volwassenen zijn.
Stel Discord en je sleutels in
- Open het Discord developer portal en maak een applicatie aan, voeg dan een bot toe.
- Schakel onder de bot-instellingen de Message Content Intent in. Zonder dit ontvangt de bot berichten met lege tekst.
- Kopieer de bot-token. Behandel het als een wachtwoord.
- Gebruik de OAuth2 URL generator om de bot uit te nodigen met de rechten om berichten te lezen en te sturen in de kanalen die je kiest.
- Haal een API-sleutel op via de sleutelpagina. Nieuwe gebruikers kunnen met één klik $0,50 aan gratis proeftegoed claimen, zonder betalingsgegevens nodig te hebben, geldig voor 7 dagen.
Sla beide geheimen op als omgevingsvariabelen, nooit in de repository. Voor een open source project is dit belangrijker dan normaal, omdat de code publiek is.
pip install discord.py openai python-dotenv
printf 'DISCORD_TOKEN=your-discord-token
API_KEY=your-api-key
' > .env
echo ".env" >> .gitignore
De botcode
Sla dit op als bot.py. De opmerkingen verklaren de beslissingen die niet voor de hand liggen.
import asyncio
import os
from collections import defaultdict, deque
import discord
from dotenv import load_dotenv
from openai import AsyncOpenAI
load_dotenv()
ai = AsyncOpenAI(
base_url="https://api.openrouternsfw.com/v1",
api_key=os.environ["API_KEY"],
max_retries=4, # the SDK retries 429 and honors Retry-After
)
SYSTEM = (
"You are Vex, a sharp-tongued storyteller in a Discord server for adults. "
"Stay in character, keep replies under 150 words, and never write "
"anything sexual involving minors."
)
intents = discord.Intents.default()
intents.message_content = True
bot = discord.Client(intents=intents)
slots = asyncio.Semaphore(6) # stay under 8 concurrent
history = defaultdict(lambda: deque(maxlen=12)) # last 12 turns per channel
async def ask(channel_id, user_text):
turns = history[channel_id]
turns.append({"role": "user", "content": user_text})
messages = [{"role": "system", "content": SYSTEM}] + list(turns)
async with slots:
resp = await ai.chat.completions.create(
model="uncensored",
messages=messages,
temperature=0.9,
max_tokens=400,
)
reply = resp.choices[0].message.content or ""
turns.append({"role": "assistant", "content": reply})
return reply
@bot.event
async def on_ready():
print(f"Logged in as {bot.user}")
@bot.event
async def on_message(message):
if message.author.bot or bot.user not in message.mentions:
return
text = message.clean_content.replace(f"@{bot.user.display_name}", "").strip()
if not text:
return
async with message.channel.typing():
try:
reply = await ask(message.channel.id, f"{message.author.display_name}: {text}")
except Exception as exc:
print("API error:", exc)
await message.reply("The model is busy. Try again in a few seconds.")
return
for i in range(0, len(reply), 1900): # Discord caps messages at 2000 chars
await message.reply(reply[i:i + 1900])
bot.run(os.environ["DISCORD_TOKEN"])
Voer het uit met python bot.py, noem de bot dan in een kanaal dat het kan lezen. Het eerste antwoord zou binnen enkele seconden moeten aankomen.
Als er niets gebeurt, controleer drie dingen in volgorde. De bot moet online zijn in de ledenlijst, dus het token is geldig. Het moet de rechten hebben om berichten in dat kanaal te lezen en te versturen. En de vermelding moet een echte Discord-vermelding zijn, gekozen uit de autocomplete-lijst, omdat platte tekst met de botnaam niet verschijnt in message.mentions. De terminal toont API-fouten, dus een verkeerde sleutel verschijnt daar als een authenticatiefout.
Waarom de code zo is gevormd
Geschiedenis is klein met opzet
Het contextvenster is 100.000 tokens groot, dus je kunt veel versturen. Maar elk invoertoken wordt gefactureerd bij elke aanroep, en Discord-chat bestaat meestal uit korte regels. Twaalf beurten houden antwoorden coherent zonder elk bericht om te zetten in een grote rekening. Verhoog maxlen voor verhaalkanalen waar continuïteit belangrijk is.
De semaphore beschermt je sleutel
Een volledige sleutel staat 8 gelijktijdige verzoeken en 300 verzoeken per minuut toe. Een proefsleutel staat slechts 2 en 60 toe. Als tien mensen de bot tegelijk vermelden en jij stuurt tien verzoeken, krijgen de extra's HTTP 429 met de foutcode concurrency. De semaphore zet ze in wachtrij in je eigen proces. Stel het in op 2 terwijl je op de proefsleutel bent. Als je ooit streaming inschakelt, onthoud dan dat een gestreamd verzoek zijn slot vasthoudt tot de stream klaar is.
Retries komen van de SDK
De OpenAI Python SDK probeert opnieuw bij 429 en respecteert de Retry-After header, die de service stuurt als Retry-After: 5 bij tijdelijke overbelasting. Stel max_retries in op 4 om korte pieken te dekken. Mislukte of geweigerde verzoeken worden niet in rekening gebracht, dus opnieuw proberen kost je geen tokens als het mislukt.
Een gedeeld persona
De systeemprompt staat eerst op elke aanroep. Persona's per kanaal zijn een kleine uitbreiding: houd een woordenboek bij van kanaal-ID naar prompt en zoek het op in ask.
Maak er een goed open source project van
De code werkt, maar een openbare repository heeft een paar extra's nodig voordat vreemden hem kunnen gebruiken.
- Een licentie. MIT of Apache 2.0 zijn de gebruikelijke keuzes voor kleine bots. Voeg het bestand toe aan de root van de repository.
- Een .env.example. Lijst
DISCORD_TOKENenAPI_KEYop met nepwaarden zodat mensen weten wat ze moeten instellen. - Een configureerbare base URL. Lees
BASE_URLenMODELuit de omgeving, met default waarden zoals hierboven. Iedereen die het forkt kan dan elke OpenAI-compatible server gebruiken. - Een Dockerfile. Een kort bestand gebaseerd op een Python slim-image, waarin
bot.pywordt gekopieerd, de drie pakketten worden geïnstalleerd en het script wordt uitgevoerd, stelt mensen in staat het overal te hosten. - Een README met de intent waarschuwing. Het ontbrekende Message Content-intent is de belangrijkste support vraag voor elke Discord-bot.
Houd je eigen token en sleutel buiten de Git-geschiedenis. Als er een lekt, trek het in dan in via het Discord-portaal of op de API-sleutelpagina en maak een nieuwe aan.
Hosting en wat het kost
De bot is een enkel langlopend proces met licht CPU-gebruik. Een kleine VPS, een overbodige machine of een containerplatform is genoeg. Er is geen webserver om bloot te stellen, omdat de bot uitgaat naar Discord.
De API-kosten zijn eenvoudig te berekenen. Een typisch antwoord hier gebruikt 1.500 inputtokens (systeemprompt plus twaalf korte beurten) en 300 outputtokens.
- Input: 1.500 x $0,15 / 1M = $0,000225
- Output: 300 x $0,50 / 1M = $0,00015
- Per antwoord: $0,000375
Dat maakt 1.000 antwoorden $0,375 en 10.000 antwoorden $3,75. De $0,50 proef dekt ongeveer 1.333 antwoorden. Een $20 top-up dekt meer dan 53.000. Top-ups lopen van $20 tot $500, met +5% vanaf $50, +10% vanaf $100 en +15% vanaf $200. Credit verloopt nooit en er is geen abonnement, dus een rustige server kost bijna niets. Zie de prijspagina voor de details. Betaling is alleen crypto, met USDT op TRC20 of USDC op Base.
Waar je nu naartoe kunt
Drie upgrades zijn de moeite waard. Voeg streaming toe door een enkel bericht te bewerken terwijl chunks aankomen, maar houd rekening met de edit rate limits van Discord. Voeg een slash-command toe dat de kanaalgeschiedenis reset. Voeg function calling toe zodat de bot dobbelstenen kan rollen of een karakterblad kan opzoeken; de API ondersteunt tools, tool_choice en role: "tool" resultaten in het OpenAI-formaat.
De API docs lijsten elke ondersteunde parameter op, en het Hermes API artikel behandelt hoe ongecensureerde modellen zich gedragen binnen een project. Prompts die naar de API worden gestuurd worden niet gebruikt voor training, wat de moeite waard is om te zeggen in de regels van je server als je leden het vragen.
Meer handleidingen
Vragen en antwoorden
Heeft de bot het Message Content-intent nodig?
Ja. Schakel dit in in het Discord developer portal en in de code met intents.message_content ingesteld op true. Anders ziet de bot lege berichten.
Hoeveel antwoorden kan de bot tegelijk afhandelen?
Een volledige sleutel staat 8 gelijktijdige verzoeken en 300 per minuut toe; een proefsleutel staat 2 en 60 toe. Een semaphore in de bot houdt je onder de limiet.
Mag ik de code van de bot publiceren?
Ja, zolang de Discord-token en API-sleutel buiten de repository blijven. Lees ze uit omgevingsvariabelen en lever een .env.example mee.
Is het toegestaan om volwassen thema's te gebruiken?
Alleen voor wettelijk volwassen gebruik, in lijn met de regels van Discord en de instellingen voor leeftijdsgelimiteerde kanalen. Seksuele inhoud met minderjarigen is nooit toegestaan.
Wat kost het om te draaien?
Een antwoord met 1.500 input en 300 output tokens kost $0,000375, dus ongeveer $3,75 per 10.000 antwoorden, plus de kosten van het hosten van het proces.
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