February 20, 2026 ยท 15 min read

AI Agent for Discord: Build Bots That Moderate, Answer Questions & Engage Your Community

150 million people use Discord monthly. If you run a community, an AI agent can moderate 24/7, answer questions from your docs instantly, onboard new members, and keep engagement high โ€” without burning out your mod team.

Why Discord Communities Need AI Agents

Running a Discord community of 1,000+ members is a full-time job. The same questions get asked daily. Spam and rule violations need constant monitoring. New members feel lost. Active members churn because nobody responds to their posts.

An AI agent solves the scaling problem:

๐Ÿ’ก The ROI

Communities with AI agents see: 60% fewer repeated questions, 3x faster response times, 40% reduction in mod workload, and 25% higher member retention (because questions get answered).

5 Discord Agent Types

Type 1

Knowledge Base Q&A Bot

Members ask questions, the bot answers from your docs, FAQ, past conversations, and pinned messages. Cites sources. Knows when to say "I don't know โ€” let me ping a human." The #1 most impactful Discord agent.

Type 2

Smart Moderation Bot

Goes beyond keyword filtering. Understands context: "kill it" in a gaming channel is fine, in a general channel it's not. Handles spam, toxicity, NSFW content, and scam links. Auto-escalates edge cases to human mods.

Type 3

Onboarding Bot

Welcomes new members with a personalized DM. Asks about their interests. Guides them to the right channels. Assigns roles based on responses. Checks in after 3 days: "Getting value? Need help finding anything?"

Type 4

Engagement Bot

Daily discussion prompts, weekly challenges, polls, topic of the day, and "this day in history" for your community. Tracks activity and surfaces top contributors. Gamification: XP, levels, leaderboards.

Type 5

Support Ticket Bot

Creates private threads for support requests. Tries to solve common issues from your knowledge base first. If it can't, creates a ticket thread and pings the right team member. Tracks resolution time and satisfaction.

Build: Q&A Knowledge Agent

const { Client, GatewayIntentBits, Events } = require("discord.js");
const Anthropic = require("@anthropic-ai/sdk");
const { createClient } = require("@supabase/supabase-js");

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
});

const anthropic = new Anthropic();
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);

// Respond to @mentions and messages in #help channels
client.on(Events.MessageCreate, async (message) => {
  if (message.author.bot) return;

  const isHelp = message.channel.name.includes("help") ||
                 message.channel.name.includes("support") ||
                 message.channel.name.includes("questions");
  const isMentioned = message.mentions.has(client.user);

  if (!isHelp && !isMentioned) return;

  const question = message.content.replace(/<@!?\d+>/g, "").trim();
  if (question.length < 5) return;

  // Show typing indicator
  await message.channel.sendTyping();

  try {
    // Search knowledge base
    const embedding = await getEmbedding(question);
    const { data: docs } = await supabase.rpc("match_documents", {
      query_embedding: embedding,
      match_threshold: 0.7,
      match_count: 5,
    });

    // Search past answered questions in Discord
    const pastAnswers = await searchPastAnswers(question);

    const context = [
      ...docs.map(d => `[Docs: ${d.title}]\n${d.content}`),
      ...pastAnswers.map(a => `[Past answer in #${a.channel}]\n${a.content}`),
    ].join("\n\n---\n\n");

    const response = await anthropic.messages.create({
      model: "claude-sonnet-4-20250514",
      max_tokens: 800,
      system: `You're a helpful community assistant for a Discord server.

Rules:
- Answer from the provided context ONLY
- If you're not sure, say "I'm not 100% sure โ€” let me ping a mod"
- Keep answers concise (Discord messages should be scannable)
- Use Discord formatting: **bold**, \`code\`, > quotes
- Add relevant emoji sparingly
- If the question is off-topic, gently redirect to the right channel
- Never share private/admin information
- Credit community members who answered similar questions before`,
      messages: [{
        role: "user",
        content: `Context:\n${context}\n\nQuestion: ${question}`,
      }],
    });

    const answer = response.content[0].text;

    // Send reply (split if too long for Discord's 2000 char limit)
    if (answer.length > 1900) {
      const parts = splitMessage(answer, 1900);
      for (const part of parts) {
        await message.reply(part);
      }
    } else {
      await message.reply(answer);
    }

    // Log for analytics
    await supabase.from("qa_log").insert({
      question,
      answer,
      channel: message.channel.name,
      user_id: message.author.id,
      docs_used: docs.map(d => d.title),
      timestamp: new Date().toISOString(),
    });

  } catch (error) {
    console.error("Q&A error:", error);
    await message.reply(
      "Sorry, I hit an error! A mod will help you shortly. ๐Ÿ™"
    );
  }
});

function splitMessage(text, maxLength) {
  const parts = [];
  let current = "";
  for (const line of text.split("\n")) {
    if ((current + "\n" + line).length > maxLength) {
      parts.push(current);
      current = line;
    } else {
      current += (current ? "\n" : "") + line;
    }
  }
  if (current) parts.push(current);
  return parts;
}

Build: Smart Moderation Agent

client.on(Events.MessageCreate, async (message) => {
  if (message.author.bot) return;

  // Quick checks first (no API call needed)
  if (containsScamLinks(message.content)) {
    await message.delete();
    await message.channel.send(
      `โš ๏ธ Removed a message with a suspicious link. ` +
      `<@${message.author.id}>, please don't share unknown links.`
    );
    await logModAction(message, "scam_link", "auto");
    return;
  }

  // AI-powered moderation for nuanced content
  const response = await anthropic.messages.create({
    model: "claude-sonnet-4-20250514",
    max_tokens: 200,
    messages: [{
      role: "user",
      content: `Moderate this Discord message. Return JSON:
{
  "action": "allow|warn|delete|mute|escalate",
  "reason": "why this action",
  "severity": "none|low|medium|high",
  "category": "clean|spam|toxicity|nsfw|scam|off_topic|self_promo"
}

Channel: #${message.channel.name}
Server context: Tech/gaming community
Message: "${message.content}"

Rules:
- Gaming language and casual swearing is generally OK
- Slurs and targeted harassment are never OK
- Self-promotion is only OK in #showcase
- Context matters: "this kills" in #gaming is fine
- Be lenient on first offenses, stricter on repeats
- When in doubt, escalate to human mods`
    }],
  });

  const modResult = JSON.parse(response.content[0].text);

  switch (modResult.action) {
    case "delete":
      await message.delete();
      await message.author.send(
        `Your message in #${message.channel.name} was removed. ` +
        `Reason: ${modResult.reason}. ` +
        `If you think this was a mistake, contact a mod.`
      );
      break;

    case "warn":
      await message.reply(
        `โš ๏ธ Hey <@${message.author.id}>, friendly reminder: ` +
        `${modResult.reason}. Thanks for keeping the community great! ๐Ÿ™`
      );
      break;

    case "escalate":
      const modChannel = message.guild.channels.cache
        .find(c => c.name === "mod-alerts");
      if (modChannel) {
        await modChannel.send(
          `๐Ÿ”” **Needs human review**\n` +
          `Channel: <#${message.channel.id}>\n` +
          `User: <@${message.author.id}>\n` +
          `Content: "${message.content.substring(0, 500)}"\n` +
          `AI assessment: ${modResult.reason}\n` +
          `[Jump to message](${message.url})`
        );
      }
      break;
  }

  if (modResult.action !== "allow") {
    await logModAction(message, modResult.category, modResult.action);
  }
});

function containsScamLinks(text) {
  const scamPatterns = [
    /discord\.gift\/(?!actual)/i,
    /discord\.com\.(?!com)/i,
    /free\s*nitro/i,
    /steamcommunity\.(?!com)/i,
  ];
  return scamPatterns.some(p => p.test(text));
}
โš ๏ธ Don't over-moderate

An AI mod that's too strict kills the community faster than spam. Start with "escalate" as the default action. Only auto-delete obvious spam and scam links. Let human mods decide on borderline cases. Review mod logs weekly and adjust sensitivity.

Build: Member Onboarding Agent

client.on(Events.GuildMemberAdd, async (member) => {
  // Welcome in #welcome channel
  const welcomeChannel = member.guild.channels.cache
    .find(c => c.name === "welcome" || c.name === "introductions");

  if (welcomeChannel) {
    await welcomeChannel.send(
      `Welcome to the server, <@${member.id}>! ๐ŸŽ‰\n\n` +
      `Here's how to get started:\n` +
      `1๏ธโƒฃ Check out <#rules> and react to accept\n` +
      `2๏ธโƒฃ Pick your roles in <#roles>\n` +
      `3๏ธโƒฃ Introduce yourself here!\n` +
      `4๏ธโƒฃ Got questions? Ask in <#help>\n\n` +
      `I'm the community AI assistant โ€” mention me anytime!`
    );
  }

  // DM with personalized onboarding
  try {
    await member.send({
      content: `Hey ${member.displayName}! Welcome! ๐Ÿ‘‹\n\n` +
        `I'm the community bot. Quick question to help you get the ` +
        `most out of the server:\n\n` +
        `What brings you here?\n` +
        `๐Ÿ…ฐ๏ธ Learning about the topic\n` +
        `๐Ÿ…ฑ๏ธ Building a project\n` +
        `๐Ÿ…ฒ Networking with others\n` +
        `๐Ÿ…ณ Just exploring\n\n` +
        `Reply with A, B, C, or D and I'll point you to the best channels!`,
    });
  } catch (e) {
    // DMs might be disabled
    console.log(`Couldn't DM ${member.displayName}`);
  }

  // 3-day check-in
  setTimeout(async () => {
    try {
      // Check if they've sent any messages
      const active = await checkMemberActivity(member.id, member.guild.id);

      if (!active) {
        await member.send(
          `Hey ${member.displayName}! Just checking in โ€” ` +
          `I noticed you haven't posted yet. No pressure!\n\n` +
          `If you're looking for a good starting point:\n` +
          `โ€ข Introduce yourself in <#introductions>\n` +
          `โ€ข Check out today's discussion in <#general>\n` +
          `โ€ข Got any questions? <#help> is super friendly\n\n` +
          `We're glad you're here! ๐Ÿ˜Š`
        );
      }
    } catch (e) {}
  }, 3 * 24 * 60 * 60 * 1000); // 3 days
});

Build: Engagement & Activity Agent

const cron = require("node-cron");

// Daily discussion prompt at 10 AM
cron.schedule("0 10 * * *", async () => {
  const channel = client.channels.cache
    .find(c => c.name === "general" || c.name === "daily-discussion");
  if (!channel) return;

  const response = await anthropic.messages.create({
    model: "claude-sonnet-4-20250514",
    max_tokens: 200,
    messages: [{
      role: "user",
      content: `Generate a fun, engaging discussion prompt for a tech
community Discord server. Today is ${new Date().toLocaleDateString("en-US", {
  weekday: "long" })}.

Make it:
- Conversational and fun (not corporate)
- Easy to answer (low barrier to participate)
- Related to tech/AI/building things
- Include 2-3 emoji
- Occasionally spicy/controversial takes are OK

Return ONLY the prompt text, nothing else.`
    }],
  });

  await channel.send(`๐Ÿ’ฌ **Daily Discussion**\n\n${response.content[0].text}`);
});

// Weekly leaderboard every Sunday
cron.schedule("0 18 * * 0", async () => {
  const channel = client.channels.cache
    .find(c => c.name === "general");
  if (!channel) return;

  // Get top contributors this week
  const topMembers = await getWeeklyTopContributors(channel.guild.id);

  const leaderboard = topMembers.slice(0, 5).map((m, i) => {
    const medals = ["๐Ÿฅ‡", "๐Ÿฅˆ", "๐Ÿฅ‰", "4๏ธโƒฃ", "5๏ธโƒฃ"];
    return `${medals[i]} <@${m.userId}> โ€” ${m.messages} messages, ` +
           `${m.helpfulReactions} helpful reactions`;
  }).join("\n");

  await channel.send(
    `๐Ÿ“Š **Weekly Leaderboard**\n\n` +
    `Top contributors this week:\n${leaderboard}\n\n` +
    `Thanks for making this community awesome! ๐Ÿ™Œ`
  );
});

Slash Commands Architecture

const { SlashCommandBuilder } = require("discord.js");

// Register slash commands
const commands = [
  new SlashCommandBuilder()
    .setName("ask")
    .setDescription("Ask the AI assistant a question")
    .addStringOption(opt =>
      opt.setName("question").setDescription("Your question").setRequired(true)
    ),

  new SlashCommandBuilder()
    .setName("summarize")
    .setDescription("Summarize recent discussion in this channel")
    .addIntegerOption(opt =>
      opt.setName("messages").setDescription("Number of messages to summarize").setRequired(false)
    ),

  new SlashCommandBuilder()
    .setName("ticket")
    .setDescription("Create a support ticket")
    .addStringOption(opt =>
      opt.setName("issue").setDescription("Describe your issue").setRequired(true)
    ),
];

client.on(Events.InteractionCreate, async (interaction) => {
  if (!interaction.isChatInputCommand()) return;

  if (interaction.commandName === "ask") {
    await interaction.deferReply();
    const question = interaction.options.getString("question");
    const answer = await answerFromKnowledgeBase(question);
    await interaction.editReply(answer);
  }

  if (interaction.commandName === "summarize") {
    await interaction.deferReply();
    const count = interaction.options.getInteger("messages") || 50;
    const messages = await interaction.channel.messages.fetch({ limit: count });

    const conversation = messages.reverse().map(m =>
      `${m.author.displayName}: ${m.content}`
    ).join("\n");

    const response = await anthropic.messages.create({
      model: "claude-sonnet-4-20250514",
      max_tokens: 500,
      messages: [{
        role: "user",
        content: `Summarize this Discord conversation in 5-7 bullet points.
Highlight: key decisions, questions asked, links shared, action items.

${conversation}`
      }],
    });

    await interaction.editReply(
      `๐Ÿ“ **Channel Summary** (last ${count} messages)\n\n` +
      response.content[0].text
    );
  }

  if (interaction.commandName === "ticket") {
    const issue = interaction.options.getString("issue");
    // Create a private thread for the support ticket
    const thread = await interaction.channel.threads.create({
      name: `๐ŸŽซ ${interaction.user.displayName}: ${issue.substring(0, 50)}`,
      type: 12, // PrivateThread
      reason: "Support ticket",
    });

    await thread.members.add(interaction.user.id);
    await thread.send(
      `**Support Ticket**\n\n` +
      `**From:** <@${interaction.user.id}>\n` +
      `**Issue:** ${issue}\n\n` +
      `I'll try to help first. If I can't solve it, a team member will jump in.`
    );

    // Try to auto-solve
    const solution = await answerFromKnowledgeBase(issue);
    await thread.send(solution);

    await interaction.reply({
      content: `๐ŸŽซ Ticket created! Check ${thread}`,
      ephemeral: true,
    });
  }
});

Level up your Discord community

The AI Employee Playbook includes the complete Discord agent with Q&A, moderation, onboarding, and engagement โ€” plus 12 other production-ready agent templates.

Get the Playbook โ€” โ‚ฌ29

Tool Comparison: 6 Discord AI Tools

Tool Best For Price Custom AI
Discord AutoMod Basic keyword filtering Free (built-in) โŒ None
MEE6 Moderation, leveling, commands Free / $12/mo โš ๏ธ Basic AI
Carl-bot Advanced automod, reaction roles Free / $5/mo โŒ None
Clyde (Discord AI) Native Discord AI chat Free (limited) โŒ No custom
Poe Bot Multi-model AI in Discord Free / $20/mo โš ๏ธ Some
Custom Agent (this guide) Full control, your knowledge base ~$5-15/mo (API) โœ… Full

Build Your Discord Agent in 30 Minutes

Step 1 (5 min)

Create the Discord App

Go to discord.com/developers. Create an application. Add a bot. Enable Message Content Intent. Copy the bot token. Generate an invite URL with permissions: Send Messages, Manage Messages, Read Message History, Create Threads.

Step 2 (5 min)

Set Up the Project

npm init -y && npm install discord.js @anthropic-ai/sdk @supabase/supabase-js. Copy the Q&A agent code. Set env vars: DISCORD_TOKEN, ANTHROPIC_API_KEY, SUPABASE_URL, SUPABASE_KEY.

Step 3 (10 min)

Index Your Knowledge Base

Take your FAQ, docs, and pinned messages. Chunk into 500-token segments. Create embeddings and store in Supabase. For a small community (< 100 docs), this takes minutes.

Step 4 (10 min)

Deploy & Test

Run locally: node bot.js. Test in a private channel. Ask 10 common questions. Adjust the system prompt. Deploy to Railway ($5/mo) or a VPS. Set up process manager (PM2) for auto-restart.

7 Mistakes That Kill Community Vibes

Mistake 1

Responding to every message

An AI bot that replies to everything is annoying. Only respond when: @mentioned, message is in a #help channel, or a slash command is used. Silent by default. Helpful when asked.

Mistake 2

Corporate tone in a casual community

"Thank you for your inquiry. I would be happy to assist you with your question." โ€” Nobody talks like that on Discord. Match the community's tone. Use emoji. Be casual. Add personality.

Mistake 3

Not handling the 2000-character limit

Discord messages max out at 2000 characters. If your bot sends a wall of text that gets cut off, it looks broken. Always check length and split into multiple messages with logical breaks.

Mistake 4

Over-aggressive moderation

Deleting messages that don't need deleting kills trust instantly. Start with "warn" as the default, not "delete." Let human mods handle anything borderline. Review mod actions weekly.

Mistake 5

No rate limiting per user

One user can drain your API budget by spamming the bot. Limit to 10 questions per user per hour. Add a cooldown message: "You're asking a lot of questions! Give me a moment. ๐Ÿ˜…"

Mistake 6

Ignoring thread context

If someone asks a follow-up in a thread, the bot needs the thread history. Without it, every reply is disconnected. Always fetch the thread's message history before responding in threads.

Mistake 7

No feedback mechanism

Add reaction-based feedback: โœ… for helpful, โŒ for wrong. Track the ratio. Review โŒ answers weekly. Without feedback, you'll never know if your bot is helping or hurting.

Build your community's AI assistant

The AI Employee Playbook includes the complete Discord agent with Q&A, moderation, onboarding, and engagement โ€” plus 12 other agent templates.

Get the Playbook โ€” โ‚ฌ29

What's Next

Start with the Q&A bot in your #help channel. Get it answering your top 20 questions accurately. Then add moderation (start lenient). Then onboarding for new members. Finally, add engagement features once the community trusts the bot.

The best Discord communities don't just have great members โ€” they have great systems that make it easy to participate, get help, and feel welcome. An AI agent is the backbone of that system.

Want the complete agent-building system?

The AI Employee Playbook covers the 3-file framework, memory systems, autonomy rules, and real production examples.

Get the Playbook โ€” โ‚ฌ29