关于 discord-bot-architect
discord-bot-architect 是面向 Discord 机器人开发者的技能,涵盖 JavaScript 和 Python。它提供斜杠命令、网关事件及交互组件的实现模式,并说明常见陷阱。
主要功能
- 01Discord.js v14 机器人配置
- 02Pycord 机器人配置
- 03斜杠命令模式
- 04按钮、菜单和模态框
- 05机器人常见问题指引
适用场景
- 01启动 JavaScript 或 TypeScript Discord 机器人
- 02使用应用命令构建 Python 机器人
- 03添加交互菜单和表单
- 04规避常见命令及事件循环问题
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ davila7/ claude-code-templates --skill discord-bot-architect安装后在 Claude Code 中输入/discord-bot-architect确认已加载。
详细介绍
Discord Bot 架构师
模式
Discord.js v14 基础
使用 Discord.js v14 和斜杠命令的现代 Discord 机器人设置
适用场景:['使用 JavaScript/TypeScript 构建 Discord 机器人', '需要带事件的完整网关连接', '构建具有复杂交互的机器人']
```javascript
// src/index.js
const { Client, Collection, GatewayIntentBits, Events } = require('discord.js');
const fs = require('node:fs');
const path = require('node:path');
require('dotenv').config();
// Create client with minimal required intents
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
// Add only what you need:
// GatewayIntentBits.GuildMessages,
// GatewayIntentBits.MessageContent, // PRIVILEGED - avoid if possible
]
});
// Load commands
client.commands = new Collection();
const commandsPath = path.join(__dirname, 'commands');
const commandFiles = fs.readdirSync(commandsPath).filter(f => f.endsWith('.js'));
for (const file of commandFiles) {
const filePath = path.join(commandsPath, file);
const command = require(filePath);
if ('data' in command && 'execute' in command) {
client.commands.set(command.data.name, command);
}
}
// Load events
const eventsPath = path.join(__dirname, 'events');
const eventFiles = fs.readdirSync(eventsPath).filter(f => f.endsWith('.js'));
for (const file of eventFiles) {
const filePath = path.join(eventsPath, file);
const event = require(filePath);
if (event.once) {
client.once(event.name, (...args) => event.execute(...args));
} else {
client.on(event.name, (...args) => event.execute(...args));
}
}
client.login(process.env.DISCORD_TOKEN);
// src/commands/ping.js
const { SlashCommandBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('ping')
.setDescription('Replies with Pong!'),
async execute(interaction) {
const sent = await interaction.reply({
content: 'Pinging...',
fetchReply: true
});
const latency = sent.createdTimestamp - interaction.createdTimestamp;
await interaction.editReply(`Pong! Latency: ${latency}ms`);
}
};
// src/events/interactionCreate.js
const { Events } = require('discord.js');
module.exports = {
name: Event
Pycord 机器人基础
使用 Pycord(Python)和应用程序命令的 Discord 机器人
适用场景:['使用 Python 构建 Discord 机器人', '偏好 async/await 模式', '需要良好的斜杠命令支持']
```python
# main.py
import os
import discord
from discord.ext import commands
from dotenv import load_dotenv
load_dotenv()
# Configure intents - only enable what you need
intents = discord.Intents.default()
# intents.message_content = True # PRIVILEGED - avoid if possible
# intents.members = True # PRIVILEGED
bot = commands.Bot(
command_prefix="!", # Legacy, prefer slash commands
intents=intents
)
@bot.event
async def on_ready():
print(f"Logged in as {bot.user}")
# Sync commands (do this carefully - see sharp edges)
# await bot.sync_commands()
# Slash command
@bot.slash_command(name="ping", description="Check bot latency")
async def ping(ctx: discord.ApplicationContext):
latency = round(bot.latency * 1000)
await ctx.respond(f"Pong! Latency: {latency}ms")
# Slash command with options
@bot.slash_command(name="greet", description="Greet a user")
async def greet(
ctx: discord.ApplicationContext,
user: discord.Option(discord.Member, "User to greet"),
message: discord.Option(str, "Custom message", required=False)
):
msg = message or "Hello!"
await ctx.respond(f"{user.mention}, {msg}")
# Load cogs
for filename in os.listdir("./cogs"):
if filename.endswith(".py"):
bot.load_extension(f"cogs.{filename[:-3]}")
bot.run(os.environ["DISCORD_TOKEN"])
# cogs/general.py
import discord
from discord.ext import commands
class General(commands.Cog):
def __init__(self, bot):
self.bot = bot
@commands.slash_command(name="info", description="Bot information")
async def info(self, ctx: discord.ApplicationContext):
embed = discord.Embed(
title="Bot Info",
description="A helpful Discord bot",
color=discord.Color.blue()
)
embed.add_field(name="Servers", value=len(self.bot.guilds))
embed.add_field(name="Latency", value=f"{round(self.bot.latency * 1000)}ms")
await ctx.respond(embed=embed)
@commands.Cog.
交互组件模式
使用按钮、选择菜单和模态框实现丰富的用户体验
适用场景:['需要交互式用户界面', '收集超出斜杠命令选项的用户输入', '构建菜单、确认或表单']
```javascript
// Discord.js - Buttons and Select Menus
const {
SlashCommandBuilder,
ActionRowBuilder,
ButtonBuilder,
ButtonStyle,
StringSelectMenuBuilder,
ModalBuilder,
TextInputBuilder,
TextInputStyle
} = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('menu')
.setDescription('Shows an interactive menu'),
async execute(interaction) {
// Button row
const buttonRow = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('confirm')
.setLabel('Confirm')
.setStyle(ButtonStyle.Primary),
new ButtonBuilder()
.setCustomId('cancel')
.setLabel('Cancel')
.setStyle(ButtonStyle.Danger),
new ButtonBuilder()
.setLabel('Documentation')
.setURL('https://discord.js.org')
.setStyle(ButtonStyle.Link) // Link buttons don't emit events
);
// Select menu row (one per row, takes all 5 slots)
const selectRow = new ActionRowBuilder()
.addComponents(
new StringSelectMenuBuilder()
.setCustomId('select-role')
.setPlaceholder('Select a role')
.setMinValues(1)
.setMaxValues(3)
.addOptions([
{ label: 'Developer', value: 'dev', emoji: '💻' },
{ label: 'Designer', value: 'design', emoji: '🎨' },
{ label: 'Community', value: 'community', emoji: '🎉' }
])
);
await interaction.reply({
content: 'Choose an option:',
components: [buttonRow, selectRow]
});
// Collect responses
const collector = interaction.channel.createMessageComponentCollector({
filter: i => i.user.id === interaction.user.id,
time: 60_000 // 60 seconds timeout
});
collector.on('collect', async i => {
if (i.customId === 'confirm') {
await i.update({ content: 'Confirmed!', components: [] });
collector.stop();
} else if (i.custo
反模式
❌ 使用消息内容处理命令
为什么不好:Message Content Intent 属于特权权限,且已不推荐用于机器人命令。 斜杠命令才是推荐的方式。
❌ 每次启动时同步命令
为什么不好:命令注册有速率限制。全局命令最多需要 1 小时 才能生效。每次启动时同步会浪费 API 调用,并可能触及限制。
❌ 阻塞事件循环
为什么不好:Discord 网关需要定期发送心跳。阻塞操作 会导致心跳丢失和连接断开。
⚠️ 尖锐边缘
| 问题 | 严重程度 | 解决方案 |
|---|---|---|
| 问题 | critical | ## 立即确认,稍后处理 |
| 问题 | critical | ## 第 1 步:在开发者门户中启用 |
| 问题 | high | ## 使用单独的部署脚本(不要放在启动时) |
| 问题 | critical | ## 绝不硬编码令牌 |
| 问题 | high | ## 生成正确的邀请 URL |
| 问题 | medium | ## 开发:使用服务器命令 |
| 问题 | medium | ## 绝不阻塞事件循环 |
| 问题 | medium | ## 立即显示模态框 |
评论
支持 Markdown