Bot de Discord de código abierto con un LLM sin censura
Un bot de Discord de código abierto que habla a través de un LLM tiene unas ochenta líneas de Python. Esta guía te proporciona el código, los límites que debes respetar y el coste por respuesta, utilizando una API compatible con OpenAI con un modelo que no rechaza peticiones adultas lícitas.

Puntos clave
- discord.py más el SDK de OpenAI es suficiente; apunta el SDK a https://api.openrouternsfw.com/v1 y usa el modelo uncensored.
- Activa el permiso de contenido de mensajes en el portal de desarrolladores de Discord o el bot verá mensajes vacíos.
- Usa un semáforo por debajo de 8 para mantenerse dentro del límite de concurrencia y mantén el contenido para adultos en canales marcados como restringidos por edad.
- Una respuesta con 1.500 tokens de entrada y 300 de salida cuesta $0,000375, es decir, unos $3,75 por 10.000 respuestas.
Sin tarjeta. Tras registrarte, reclama $0,50 de crédito de prueba gratis con un clic (una vez por persona).
Obtener clave de APILo que estás construyendo
El bot de abajo responde cuando alguien lo menciona. Mantiene un historial corto por canal, lo envía al endpoint de finalización de chat y publica la respuesta. Es Python puro, compatible con la licencia MIT y no tiene base de datos. Puedes leerlo todo de una sentada, que es el punto de un proyecto de código abierto: alguien más puede bifurcarlo y entenderlo.
El modelo detrás de esto es un único modelo de texto de pesos abiertos, ejecutado por un proveedor independiente y ajustado para responder sin rechazos de contenido para uso adulto lícito. Eso se adapta a comunidades de Discord basadas en ficción, roleplay o conversación para adultos. Dos reglas se aplican desde el principio. Primero, el contenido sexual que involucre a menores de edad no está permitido por la API y no debe formar parte del diseño de tu bot. Segundo, Discord tiene sus propias normas y configuraciones de canales restringidos por edad, y tú eres responsable de cumplirlas. Mantén el contenido para adultos en canales que estén marcados como tales y en servidores donde los miembros sean adultos.
Configura Discord y tus claves
- Abre el portal de desarrolladores de Discord y crea una aplicación, luego añade un bot a ella.
- En la configuración del bot, habilita la Intención de Contenido de Mensajes. Sin ella, el bot recibe mensajes con texto vacío.
- Copia el token del bot. Trátalo como una contraseña.
- Usa el generador de URL OAuth2 para invitar al bot con permiso para leer y enviar mensajes en los canales que elijas.
- Obtén una clave de API en la página de claves. Los nuevos usuarios pueden reclamar $0,50 de crédito de prueba con un clic, sin necesidad de detalles de pago, válido durante 7 días.
Almacena ambos secretos como variables de entorno, nunca en el repositorio. Para un proyecto de código abierto esto es más importante de lo habitual, porque el código es público.
pip install discord.py openai python-dotenv
printf 'DISCORD_TOKEN=your-discord-token
API_KEY=your-api-key
' > .env
echo ".env" >> .gitignore
El código del bot
Guarda esto como bot.py. Los comentarios explican las decisiones que no son evidentes.
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"])
Ejecútalo con python bot.py, luego menciona al bot en un canal que pueda leer. La primera respuesta debería llegar en unos segundos.
Si no pasa nada, revisa tres cosas en orden. El bot debe estar en línea en la lista de miembros, lo que indica que el token es válido. Debe tener permiso para leer y enviar mensajes en ese canal. Y la mención debe ser una mención real de Discord, seleccionada de la lista de autocompletado, porque el texto plano con el nombre del bot no aparece en message.mentions. La terminal muestra errores de API, así que una clave incorrecta aparece allí como un fallo de autenticación.
Por qué el código está estructurado así
El historial es pequeño a propósito
La ventana de contexto es de 100.000 tokens, así que podrías enviar mucho. Pero cada token de entrada se factura en cada llamada, y el chat de Discord son principalmente líneas cortas. Doce turnos mantienen las respuestas coherentes sin convertir cada mensaje en una factura grande. Aumenta maxlen para canales de historias donde la continuidad importa.
El semáforo protege tu clave
Una clave completa permite 8 peticiones simultáneas y 300 peticiones por minuto. Una clave de prueba solo permite 2 y 60. Si diez personas mencionan el bot al mismo tiempo y envías diez peticiones, las adicionales reciben HTTP 429 con el código de error concurrency. El semáforo las encola en tu propio proceso. Configúralo en 2 mientras usas la clave de prueba. Si alguna vez activas el streaming, recuerda que una petición en streaming mantiene su ranura hasta que finalice el flujo.
Los reintentos vienen del SDK
El SDK de Python de OpenAI reintenta en 429 y respeta el encabezado Retry-After, que el servicio envía como Retry-After: 5 en sobrecarga temporal. Establecer max_retries en 4 cubre picos cortos. Las peticiones fallidas o rechazadas no se cobran, así que los reintentos no te cuestan tokens cuando fallan.
Una personalidad compartida
El prompt del sistema va primero en cada llamada. Las personalidades por canal son una pequeña extensión: mantén un diccionario desde el ID del canal al prompt y búscalo en ask.
Hazlo un buen proyecto de código abierto
El código funciona, pero un repositorio público necesita algunos extras antes de que los desconocidos puedan usarlo.
- Una licencia. MIT o Apache 2.0 son las opciones habituales para bots pequeños. Añade el archivo en la raíz del repositorio.
- Un .env.example. Lista
DISCORD_TOKENyAPI_KEYcon valores falsos para que la gente sepa qué configurar. - Una URL base configurable. Lee
BASE_URLyMODELdesde el entorno, por defecto a los valores anteriores. Cualquier persona que lo bifurque puede entonces usar cualquier servidor compatible con OpenAI. - Un Dockerfile. Un archivo corto basado en una imagen Python slim, copiando
bot.py, instalando los tres paquetes y ejecutando el script, permite a la gente alojarlo en cualquier lugar. - Un README con la advertencia de intents. La falta de la intención de contenido de mensajes es la pregunta de soporte principal para cada bot de Discord.
Mantén tu propio token y clave fuera del historial de Git. Si uno se filtra, revócalo en el portal de Discord o en la página de claves de API y emite uno nuevo.
Alojamiento y cuánto cuesta
El bot es un único proceso de larga duración con uso ligero de CPU. Un VPS pequeño, una máquina de repuesto o una plataforma de contenedores es suficiente. No hay servidor web que exponer, porque el bot se conecta a Discord.
El coste de la API es fácil de calcular. Una respuesta típica aquí usa 1.500 tokens de entrada (prompt del sistema más doce turnos cortos) y 300 tokens de salida.
- Entrada: 1.500 x $0,15 / 1M = $0,000225
- Salida: 300 x $0,50 / 1M = $0,00015
- Por respuesta: $0.000375
Eso hace que 1.000 respuestas cuesten $0,375 y 10.000 respuestas cuesten $3,75. El crédito de prueba de $0,50 cubre unas 1.333 respuestas. Una recarga de $20 cubre más de 53.000. Las recargas van de $20 a $500, con +5% desde $50, +10% desde $100 y +15% desde $200. El crédito no caduca y no hay suscripción, así que un servidor tranquilo cuesta casi nada. Consulta la página de precios para los detalles. El pago es solo cripto, usando USDT en TRC20 o USDC en Base.
A dónde ir a continuación
Tres mejoras valen la pena. Añade streaming editando un solo mensaje a medida que llegan los fragmentos, pero ten cuidado con los límites de edición de Discord. Añade un comando slash que restablezca el historial del canal. Añade llamadas a funciones para que el bot pueda tirar dados o buscar una ficha de personaje; la API soporta tools, tool_choice y role: "tool" en el formato de OpenAI.
La documentación de la API lista todos los parámetros admitidos, y el artículo de la API de Hermes cubre cómo se comportan los modelos sin censura dentro de un proyecto. Los prompts enviados a la API no se usan para entrenamiento, lo cual vale la pena decir en las reglas de tu servidor si tus miembros preguntan.
Más guías
Preguntas y respuestas
¿El bot necesita el permiso de contenido de mensajes?
Sí. Actívalo en el portal de desarrolladores de Discord y en el código con intents.message_content establecido en true. De lo contrario, el bot ve mensajes vacíos.
¿Cuántas respuestas puede manejar el bot a la vez?
Una clave completa permite 8 peticiones simultáneas y 300 por minuto; una clave de prueba permite 2 y 60. Un semáforo en el bot te mantiene por debajo del límite.
¿Puedo publicar el código del bot?
Sí, siempre que el token de Discord y la clave de API permanezcan fuera del repositorio. Léelos desde variables de entorno e incluye un .env.example.
¿Se permiten temas para adultos?
Solo para uso adulto lícito, de acuerdo con las normas de Discord y su configuración de canales restringidos por edad. El contenido sexual que involucre a menores de edad nunca está permitido.
¿Cuánto cuesta ejecutarlo?
Una respuesta con 1,500 tokens de entrada y 300 de salida cuesta $0,000375, es decir, unos $3,75 por cada 10,000 respuestas, más el costo de alojar el proceso.
Tu clave está a un formulario de distancia
Crea una cuenta, copia la clave, cambia la URL base. Esa es toda la configuración.
Obtener clave de API