Bot Discord open source avec un LLM sans censure
Un bot Discord open source qui parle via un LLM tient en environ quatre-vingts lignes de Python. Ce guide vous donne le code, les limites à respecter et le coût par réponse, en utilisant une API compatible OpenAI avec un modèle qui ne refuse pas les requêtes légales d'adultes.

Points clés
- discord.py et le SDK OpenAI suffisent ; pointez le SDK vers https://api.openrouternsfw.com/v1 et utilisez le modèle uncensored.
- Activez l'intention Message Content dans le portail développeur Discord ou le bot verra des messages vides.
- Utilisez un sémaphore inférieur à 8 pour respecter la limite de concurrence et gardez le contenu pour adultes dans les salons marqués comme restreints aux adultes.
- Une réponse avec 1 500 tokens d'entrée et 300 tokens de sortie coûte $0,000375, soit environ $3,75 pour 10 000 réponses.
Aucune carte nécessaire. Après la connexion, réclamez $0,50 de crédit d'essai gratuit en un clic (une fois par personne).
Obtenir une clé APICe que vous construisez
Le bot ci-dessous répond lorsque quelqu'un le mentionne. Il conserve un court historique par canal, l'envoie à l'endpoint de complétion de chat et publie la réponse. Il est en Python pur, compatible MIT, et ne nécessite pas de base de données. Vous pouvez tout lire en une seule fois, ce qui est l'intérêt d'un projet open source : quelqu'un d'autre peut le forker et le comprendre.
Le modèle derrière cela est un unique modèle textuel à poids ouverts, hébergé par un fournisseur indépendant et ajusté pour répondre sans refus de contenu pour une utilisation légale par les adultes. Cela convient aux communautés Discord axées sur la fiction, le jeu de rôle ou les conversations pour adultes. Deux règles s'appliquent dès le départ. Premièrement, le contenu sexuel impliquant des mineurs n'est pas autorisé par l'API et ne doit pas faire partie de la conception de votre bot. Deuxièmement, Discord a ses propres règles et ses paramètres de salons restreints aux adultes, et vous êtes responsable de leur respect. Limitez le contenu pour adultes aux salons marqués comme tels et aux serveurs où les membres sont des adultes.
Configurez Discord et vos clés
- Ouvrez le portail développeur Discord et créez une application, puis ajoutez-y un bot.
- Dans les paramètres du bot, activez l'Intention du contenu des messages. Sans cela, le bot reçoit des messages avec un texte vide.
- Copiez le jeton du bot. Traitez-le comme un mot de passe.
- Utilisez le générateur d'URL OAuth2 pour inviter le bot avec la permission de lire et d'envoyer des messages dans les salons de votre choix.
- Obtenez une clé API depuis la page des clés. Les nouveaux utilisateurs peuvent réclamer $0,50 de crédit d'essai en un clic, sans besoin de détails de paiement, valable 7 jours.
Stockez ces deux secrets en tant que variables d'environnement, jamais dans le dépôt. Pour un projet open source, cela est plus important que d'habitude, car le code est public.
pip install discord.py openai python-dotenv
printf 'DISCORD_TOKEN=your-discord-token
API_KEY=your-api-key
' > .env
echo ".env" >> .gitignore
Le code du bot
Enregistrez ceci sous bot.py. Les commentaires expliquent les décisions qui ne sont pas évidentes.
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"])
Exécutez-le avec python bot.py, puis mentionnez le bot dans un canal qu'il peut lire. La première réponse devrait arriver en quelques secondes.
Si rien ne se passe, vérifiez trois choses dans l'ordre. Le bot doit être en ligne dans la liste des membres, donc le jeton est valide. Il doit avoir la permission de lire et d'envoyer des messages dans ce canal. Et la mention doit être une vraie mention Discord, extraite de la liste d'autocomplétion, car le texte brut avec le nom du bot n'apparaît pas dans message.mentions. Le terminal affiche les erreurs API, donc une clé incorrecte s'y affiche comme une erreur d'authentification.
Pourquoi le code est agencé ainsi
L'historique est volontairement limité
La fenêtre de contexte est de 100 000 tokens, vous pouvez donc envoyer beaucoup. Mais chaque token d'entrée est facturé à chaque appel, et les chats Discord sont principalement des lignes courtes. Douze tours maintiennent les réponses cohérentes sans transformer chaque message en une facture importante. Augmentez maxlen pour les canaux de récit où la continuité compte.
Le sémaphore protège votre clé
Une clé complète permet 8 requêtes simultanées et 300 requêtes par minute. Une clé d'essai en permet seulement 2 et 60. Si dix personnes mentionnent le bot en même temps et que vous lancez dix requêtes, les supplémentaires reçoivent un HTTP 429 avec le code d'erreur concurrency. Le sémaphore les met en file d'attente dans votre propre processus. Réglez-le à 2 lorsque vous êtes sur la clé d'essai. Si vous activez le streaming, rappelez-vous qu'une requête en streaming occupe son emplacement jusqu'à la fin du flux.
Les nouvelles tentatives proviennent du SDK
Le SDK Python OpenAI réessaie sur 429 et respecte l'en-tête Retry-After, que le service envoie sous forme de Retry-After: 5 en cas de surcharge temporaire. Définir max_retries à 4 couvre les pics courts. Les requêtes échouées ou refusées ne sont pas facturées, donc les nouvelles tentatives ne vous coûtent pas de tokens lorsqu'elles échouent.
Une seule personnalité partagée
Le prompt système est placé en premier à chaque appel. Les personnalités par canal sont une petite extension : gardez un dictionnaire de l'ID du canal vers le prompt et recherchez-le dans ask.
Faites-en un bon projet open source
Le code fonctionne, mais un dépôt public nécessite quelques ajouts avant que des inconnus puissent l'utiliser.
- Une licence. MIT ou Apache 2.0 sont les choix habituels pour les petits bots. Ajoutez le fichier à la racine du dépôt.
- Un .env.example. Listez
DISCORD_TOKENetAPI_KEYavec des valeurs fictives pour que les gens sachent quoi définir. - Une URL de base configurable. Lisez
BASE_URLetMODELdepuis l'environnement, en utilisant les valeurs ci-dessus par défaut. Quiconque le forkera pourra alors utiliser n'importe quel serveur compatible OpenAI. - Un Dockerfile. Un fichier court basé sur une image Python slim, copiant
bot.py, installant les trois packages et exécutant le script, permet à quiconque de l'héberger n'importe où. - Un README avec l'avertissement sur les intentions. L'intention du contenu des messages manquante est la première question de support pour chaque bot Discord.
Conservez votre token et votre clé hors de l'historique Git. Si l'un d'eux fuit, révoquez-le dans le portail Discord ou sur la page des clés API et émettez-en un nouveau.
Hébergement et ce que cela coûte
Le bot est un seul processus continu avec une faible utilisation du CPU. Un petit VPS, une machine de rechange ou une plateforme de conteneurs suffit. Il n'y a pas de serveur web à exposer, car le bot se connecte à Discord.
Le coût de l'API est facile à calculer. Une réponse typique ici utilise 1 500 tokens d'entrée (prompt système plus douze tours courts) et 300 tokens de sortie.
- Entrée : 1 500 x $0,15 / 1M = $0,000225
- Sortie : 300 x $0,50 / 1M = $0,00015
- Par réponse : $0,000375
Cela fait 1 000 réponses à 0,375 $ et 10 000 réponses à 3,75 $. Le crédit d'essai de 0,50 $ couvre environ 1 333 réponses. Un rechargement de 20 $ en couvre plus de 53 000. Les rechargements vont de 20 $ à 500 $, avec +5 % à partir de 50 $, +10 % à partir de 100 $ et +15 % à partir de 200 $. Le crédit n'expire jamais et il n'y a pas d'abonnement, donc un serveur inactif coûte presque rien. Consultez la page tarifaire pour les détails. Le paiement est en crypto uniquement, en utilisant USDT sur TRC20 ou USDC sur Base.
Où aller ensuite
Trois améliorations valent l'effort. Ajoutez le streaming en modifiant un message unique au fur et à mesure que les blocs arrivent, mais attention aux limites de débit d'édition de Discord. Ajoutez une commande slash qui réinitialise l'historique du canal. Ajoutez l'appel de fonctions pour que le bot puisse lancer des dés ou consulter une fiche de personnage ; l'API prend en charge tools, tool_choice et role: "tool" au format OpenAI.
La documentation de l'API liste tous les paramètres pris en charge, et l'article sur l'API Hermes couvre le comportement des modèles sans censure dans un projet. Les prompts envoyés à l'API ne sont pas utilisés pour l'entraînement, ce qui vaut la peine d'être mentionné dans les règles de votre serveur si vos membres le demandent.
Plus de guides
Questions et réponses
Le bot a-t-il besoin de l'intention Message Content ?
Oui. Activez-le dans le portail développeur Discord et dans le code avec intents.message_content défini sur true. Sinon, le bot voit des messages vides.
Combien de réponses le bot peut-il gérer à la fois ?
Une clé complète permet 8 requêtes simultanées et 300 par minute ; une clé d'essai en permet 2 et 60. Un sémaphore dans le bot vous maintient en dessous de la limite.
Puis-je publier le code du bot ?
Oui, tant que le token Discord et la clé API ne se trouvent pas dans le dépôt. Lisez-les depuis des variables d’environnement et fournissez un fichier .env.example.
L’utilisation de thèmes pour adultes est-elle autorisée ?
Uniquement pour une utilisation adulte légale, conformément aux règles de Discord et à ses paramètres de salons réservés aux adultes. Le contenu sexuel impliquant des mineurs n'est jamais autorisé.
Quel est le coût d’exécution ?
Une réponse avec 1 500 tokens d'entrée et 300 tokens de sortie coûte $0,000375, soit environ $3,75 pour 10 000 réponses, plus le coût d'hébergement du processus.
Votre clé est à un formulaire de vous
Créez un compte, copiez la clé, modifiez l'URL de base. C'est toute la configuration.
Obtenir une clé API