Bot de Discord con Ollama
Qué cubre este artículo
- Cómo construir un bot de Discord con Ollama como backend de IA.
- Cómo funcionan los Slash Commands, las respuestas en chat y RAG.
- Cómo configurar e implementar el bot en Discord.
- Casos prácticos para bots de FAQ, moderación y soporte comunitario.
- Mejores prácticas para rate-limiting, seguridad y moderación.
Introducción: Bot de Discord con Ollama explicado
Un bot de Discord con Ollama responde preguntas en tu servidor de Discord usando un modelo de IA local, sin que el contenido del chat se envíe a OpenAI u otros servicios en la nube. El bot puede responder FAQ, buscar en documentos (RAG), moderar y activar flujos de trabajo.
Este artículo va dirigido a quienes quieren construir un bot de Discord con IA local. Encontrarás fundamentos en Ollama y Discord Bot Grundlagen.
¿Por qué necesito un bot de Discord con Ollama?
Imagina que tu comunidad hace preguntas recurrentes: “¿Cómo instalo X?”, “¿Dónde encuentro Y?”, “¿Qué es Z?”. Un bot con Ollama responde estas preguntas automáticamente, usando tu propio conocimiento (RAG) y de forma local, sin costos de API.
Bot de Discord con Ollama en pocas palabras
Creas un bot de Discord (discord.py o discord.js) que llama a Ollama cuando recibe mensajes y publica la respuesta. Con RAG, el bot puede buscar en tus documentos. Con Slash Commands, los usuarios pueden invocar funciones de forma dirigida.
La idea central es simple: Discord como interfaz, Ollama como cerebro.
Para quién es este artículo
- Administradores de comunidades que quieren un bot de IA.
- Desarrolladores que construyen bots de Discord.
- Self-hosters que ejecutan bots de IA localmente.
- Equipos que automatizan el soporte interno.
Experiencia con Python/JavaScript y Ollama es útil.
Conceptos clave
- Discord Bot - Programa en Discord. Cuándo es útil: la interfaz.
- Ollama - Servidor de modelos local. Cuándo es útil: el backend de IA.
- Slash Commands - Comandos como /ask. Cuándo es útil: para invocaciones estructuradas.
- RAG - Base de conocimiento. Cuándo es útil: para FAQ.
- discord.py / discord.js - Librerías de bot. Cuándo es útil: para la implementación.
- Intent - Permiso de Discord. Cuándo es útil: para acceso a mensajes.
- Discord Bot Grundlagen - Conceptos básicos. Cuándo es útil: para configuración.
Configuración: Crear un bot de Discord
1. Discord Developer Portal
- Ve a https://discord.com/developers/applications
- “New Application” → Ingresa el nombre
- Pestaña “Bot” → “Add Bot”
- Copia el token (¡nunca lo compartas!)
- Pestaña “OAuth2” → “URL Generator”
- Scope:
bot,applications.commands - Permissions:
Send Messages,Read Messages,Use Slash Commands
- Scope:
- Abre la URL generada → Invita el bot a tu servidor
2. Bot con discord.py
# bot.py
import discord
from discord import app_commands
import requests
import os
OLLAMA_URL = os.environ.get("OLLAMA_URL", "http://ollama:11434")
TOKEN = os.environ.get("DISCORD_TOKEN")
intents = discord.Intents.default()
intents.message_content = True
client = discord.Client(intents=intents)
tree = app_commands.CommandTree(client)
def call_ollama(prompt, system=None):
"""Llamar a Ollama"""
messages = []
if system:
messages.append({"role": "system", "content": system})
messages.append({"role": "user", "content": prompt})
response = requests.post(
f"{OLLAMA_URL}/api/chat",
json={
"model": "llama3.1",
"messages": messages,
"stream": False
},
timeout=60
)
return response.json()["message"]["content"]
@client.event
async def on_ready():
await tree.sync()
print(f"Bot online: {client.user}")
# Slash Command: /ask
@tree.command(name="ask", description="Haz una pregunta al bot de IA")
async def ask(interaction: discord.Interaction, frage: str):
await interaction.response.defer() # La IA necesita tiempo
antwort = call_ollama(
frage,
system="Eres un asistente útil en un servidor de Discord. Responde brevemente y con utilidad."
)
await interaction.followup.send(f"**Pregunta:** {frage}\n\n{antwort}")
# Responder mensajes (opcional)
@client.event
async def on_message(message):
if message.author.bot:
return
# Solo responder a menciones
if client.user.mentioned_in(message):
async with message.channel.typing():
antwort = call_ollama(
message.content.replace(f"<@{client.user.id}>", ""),
system="Eres un asistente útil en Discord."
)
await message.reply(antwort)
client.run(TOKEN)
3. Iniciar el bot
pip install discord.py requests
export DISCORD_TOKEN="tu-bot-token"
export OLLAMA_URL="http://localhost:11434"
python bot.py
Caso práctico 1: Bot de FAQ con RAG
import chromadb
class FAQBot:
def __init__(self):
self.chroma = chromadb.HttpClient(host="chromadb", port=8000)
self.collection = self.chroma.get_collection("faq")
async def answer(self, question):
"""Responder pregunta con RAG"""
# Buscar documentos similares
results = self.collection.query(
query_texts=[question],
n_results=3
)
context = "\n".join(results["documents"][0])
# Generar respuesta
response = call_ollama(
f"Contexto:\n{context}\n\nPregunta: {question}",
system="Responde la pregunta basándote en el contexto. Proporciona las fuentes."
)
return {
"answer": response,
"sources": results["metadatas"][0]
}
# Slash Command
@tree.command(name="faq", description="Pregunta a la FAQ")
async def faq(interaction: discord.Interaction, frage: str):
await interaction.response.defer()
result = await faq_bot.answer(frage)
embed = discord.Embed(
title="Respuesta de FAQ",
description=result["answer"],
color=discord.Color.blue()
)
embed.set_footer(text=f"Fuentes: {', '.join(s['source'] for s in result['sources'])}")
await interaction.followup.send(embed=embed)
Caso práctico 2: Bot de moderación
@client.event
async def on_message(message):
if message.author.bot:
return
# La IA analiza el mensaje
analysis = call_ollama(
f"Analiza este mensaje:\n{message.content}\n\n"
"Categorías: normal, spam, tóxico, nsfw, fuera de tema\n"
"Responde: CATEGORÍA|RAZÓN",
system="Eres un asistente de moderación."
)
category, reason = analysis.split("|", 1)
if category in ["spam", "tóxico", "nsfw"]:
await message.delete()
await message.channel.send(
f"⚠️ Mensaje de {message.author.mention} eliminado: {reason}"
)
# Log
log_moderation(message, category, reason)
Caso práctico 3: Carga de documentos → Indexación
@tree.command(name="index", description="Indexar documento para FAQ")
async def index(interaction: discord.Interaction, anhang: discord.Attachment):
await interaction.response.defer()
# Descargar archivo
content = await anhang.read()
# Extraer texto
if anhang.filename.endswith(".pdf"):
text = extract_pdf(content)
else:
text = content.decode("utf-8")
# Crear chunks
chunks = split_into_chunks(text, 500)
# Crear embeddings
for i, chunk in enumerate(chunks):
embedding = get_embedding(chunk)
collection.add(
ids=[f"{anhang.filename}_{i}"],
documents=[chunk],
embeddings=[embedding],
metadatas=[{"source": anhang.filename}]
)
await interaction.followup.send(
f"✅ {anhang.filename} indexado ({len(chunks)} chunks)"
)
Ejemplo práctico 4: Desencadenar un flujo de trabajo
@tree.command(name="workflow", description="Desencadenar un flujo de trabajo")
async def workflow(interaction: discord.Interaction, name: str, parameter: str):
await interaction.response.defer()
# Llamar al webhook de n8n
response = requests.post(
f"http://n8n:5678/webhook/{name}",
json={"parameter": parameter, "user": str(interaction.user)}
)
await interaction.followup.send(f"Flujo de trabajo {name} iniciado: {response.text}")
Configuración con Docker
version: "3.8"
services:
discord-bot:
build: .
container_name: discord-bot
restart: unless-stopped
environment:
- DISCORD_TOKEN=${DISCORD_TOKEN}
- OLLAMA_URL=http://ollama:11434
networks:
- ai-network
depends_on:
- ollama
ollama:
image: ollama/ollama:latest
container_name: ollama
restart: unless-stopped
ports:
- "11434:11434"
volumes:
- ollama_data:/root/.ollama
networks:
- ai-network
volumes:
ollama_data:
networks:
ai-network:
driver: bridge
Consideraciones de seguridad
- Token del bot confidencial: Nunca lo incluyas en el código ni en Git. Usa variables de entorno. Consulta Secrets.
- Permisos mínimos: El bot debe tener solo permisos de lectura y escritura, nunca derechos de administrador.
- Rate-Limiting: Discord aplica límites de velocidad. Implementa throttling.
- Filtro de contenido: La IA puede generar contenido inapropiado. Filtra las salidas. Consulta Guardrails.
- Inyección de prompts: Los usuarios pueden enviar inyecciones maliciosas. Consulta Prompt Injection.
- Registro de auditoría: Registra todas las acciones del bot. Consulta Audit Logging.
Errores comunes
- Token en el código: Nunca incluyas el token directamente. Siempre usa variables de entorno.
- Intents no configurados: Sin el intent
message_content, el bot no puede leer mensajes. - Rate-Limits: Discord limita las llamadas a la API. Implementa lógica de reintentos.
- Respuestas demasiado largas: Discord tiene un límite de 2000 caracteres. Acorta las respuestas o divídelas en partes.
- Ollama lento: Los modelos grandes requieren tiempo. Usa
defer()para Slash Commands. - Manejo de errores insuficiente: Si Ollama falla, el bot no debe bloquearse.
Enlaces relacionados
- Fundamentos del bot de Discord - Conceptos básicos del bot.
- Ollama - Servidor de modelos.
- RAG local - Base de conocimientos.
- Discord.py - Biblioteca del bot.
- Prompt Injection - Seguridad.
- Guardrails - Filtro de contenido.
Key Takeaways:
- Bot de Discord + Ollama: Un bot de IA local para tu servidor.
- discord.py o discord.js para la implementación.
- Slash Commands para llamadas estructuradas, on_message para chat.
- RAG para preguntas frecuentes y consultas sobre documentos.
- Seguridad: Token confidencial, rate-limiting, filtro de contenido.
FAQ
¿Cómo creo un bot de Discord?
¿discord.py o discord.js?
¿Cómo llamar a Ollama desde el bot?
¿Puede el bot buscar en documentos?
¿Puede el bot moderar?
¿Cuánto cuesta el bot?
¿Es seguro el bot?
¿Hay límite de mensajes?
Fuentes y lecturas adicionales
- Discord Developer Portal - Crear bots.
- discord.py - Biblioteca Python.
- discord.js - Biblioteca JavaScript.
- Ollama - Servidor de modelos local.


