分类: Discord 机器人开发
Discord 机器人开发#32打造服务器日志·审核日志(Audit Log)频道!自动记录消息删除、编辑、成员进出和踢出(Python 示例)🕵️
本文译自韩语原文。
要点速览
Discord 自带的审核日志只会告诉你'谁删了几条',却看不到被删的内容。本文把 raw 事件和 on_audit_log_entry_create 组合起来,做一个把被删内容、删除者、成员进出、身份组变更和踢出都以嵌入消息记录到同一个频道的日志机器人。
- Python 3.10.12 · discord.py 2.7.1 · python-dotenv 1.2.3 · 2026-09-25 亲自运行验证
- 被删消息的'内容'只有在机器人缓存里时才能看到 → 把 max_messages 调大,并且必须开启 Message Content 和 Server Members Intent
- 删除者要在 guild.audit_logs() 里按 target、频道和时间(15 秒)查找;自己删自己的消息不会在审核日志里留下记录
- 踢出和封禁通过 on_audit_log_entry_create(2.2+,Intents.moderation)实时收到,连执行者和原因都有
目录13 项

大家好!我是 Mojangcam 😎
上一篇 #31 我们做了一个临时语音频道(Temp Voice)机器人:进入大厅就自动创建频道,人走空了就自动删除。这一篇要做的是服务器管理员迟早都会想要的功能:"这是谁删的?"
今天要做的日志机器人能做这些事:
- 有人删除消息时,删除前的内容会原样留在日志频道里
- 如果是管理员删了别人的消息,连是谁删的也会记下来
- 成员加入时会记录账号创建日期(识别小号和机器人!),离开时会记录他拥有过的身份组
- 踢出和封禁会实时记录执行的管理员和原因
为什么需要机器人?🧠 Discord 自己也有 服务器设置 → 审核日志 菜单,但它不显示被删消息的内容。只会显示"谁删了几条"。一旦发生纠纷,想证明"刚才那个人骂了人又删掉了",就只能靠机器人提前记下来。

这一篇的日志机器人会和 #21 违禁词过滤、#25 错误处理 一起,担当 "社区综合管理机器人"的运营透明度模块。
📌 准备工作
- Python 3.9 以上 (推荐 3.10+) — 代码里用了
dict[str, int]写法,所以 3.9 起才能运行 - discord.py 2.7.1 (截至 2026-09-25 PyPI 最新版) —
on_audit_log_entry_create从 2.2 才开始有,旧版本一定要升级 - python-dotenv 1.x
- 已在 Discord 开发者门户创建机器人并邀请进服务器 (权限:查看审核日志、发送消息、嵌入链接)
pip install -U discord.py python-dotenv在项目文件夹里新建 .env 文件并填入令牌。把令牌直接写进代码,上传到 GitHub 时非常容易泄露 😱
token=여기에_봇_토큰💡 记得把 .env 加进 .gitignore。(echo .env >> .gitignore)
⚠️ 这一篇需要两个特权 Intent(Privileged Intents)。请在开发者门户 → Bot 标签页里打开 Message Content Intent(想看到被删消息的内容就必须开)和 Server Members Intent(检测成员进出和身份组变更)。不开的话,删除日志里的内容会是空的,或者成员进出事件根本不会触发。
🧩 日志机器人要记录的内容
今天要做的日志一共 6 种。用颜色区分,只要滚动一下就能看出发生了什么。
| 事件 | 记录内容 | 嵌入消息颜色 |
|---|---|---|
| 消息删除 | 作者、频道、删除前的内容、附件文件名、删除者 | 红色 |
| 消息编辑 | 编辑前后的内容、消息跳转链接 | 橙色 |
| 加入·离开 | 账号创建日期(识别新账号)、加入日期、拥有过的身份组 | 绿色 / 灰色 |
| 昵称·身份组变更 | 变更前后、新增·移除的身份组 | 蓝色 |
| 踢出·封禁·解封 | 执行的管理员、对象、原因 | 深红色 |
| 频道创建·删除 | 频道名称·类型 | 绿色 / 红色 |
📌 第 1 步 - 基本设置和 3 个 Intent
# discord.py 2.7.1 / Python 3.9+ / python-dotenv 1.x
import os
import json
import asyncio
import discord
from discord import app_commands
from discord.ext import commands
from dotenv import load_dotenv
load_dotenv()
token = os.getenv("token")
CONFIG_FILE = "log_config.json" # {服务器ID(str): 日志频道ID(int)}
MAX_CONTENT = 1000 # 嵌入字段最多 1024 字 → 留点余量截断
intents = discord.Intents.default()
intents.message_content = True # 想看被删消息的'内容'就必须开 (特权 Intent)
intents.members = True # 检测成员进出·昵称·身份组变更 (特权 Intent)
intents.moderation = True # 踢出·封禁 + 审核日志事件
bot = commands.Bot(command_prefix="!", intents=intents, max_messages=5000)
log_channels: dict[str, int] = {}
lock = asyncio.Lock()我们逐个拆开来看 💡
- intents.message_content : 让机器人能看到别人发的消息的内容。关掉的话,删除日志里的
content会是空字符串。这是一个也需要在门户里打开的特权 Intent。 - intents.members :
on_member_join/on_member_remove/on_member_update都绑定在这个 Intent 上。同样是特权 Intent。 - intents.moderation :
on_member_ban/on_member_unban以及今天的主角on_audit_log_entry_create都属于它。它不是特权 Intent,只在代码里打开就行。(和旧名字intents.bans是同一个东西。) - max_messages=5000 : 机器人记住的消息数量。默认值是 1000,而被删消息的内容只有在这个缓存里时才能看到,所以调大了一些。
📌 第 2 步 - 保存日志频道和嵌入消息公共函数
每个服务器的日志频道都不一样,所以把 {服务器ID: 频道ID} 存进 JSON。和 #31 完全一样的写法。
def save():
with open(CONFIG_FILE, "w", encoding="utf-8") as f:
json.dump(log_channels, f, ensure_ascii=False, indent=2)
def load():
global log_channels
if os.path.exists(CONFIG_FILE):
with open(CONFIG_FILE, encoding="utf-8") as f:
log_channels = json.load(f)
def get_log_channel(guild: discord.Guild):
cid = log_channels.get(str(guild.id))
return guild.get_channel(cid) if cid else None
def make_embed(title: str, color: discord.Color, user=None) -> discord.Embed:
embed = discord.Embed(title=title, color=color, timestamp=discord.utils.utcnow())
if user is not None:
embed.set_author(name=f"{user} ({user.id})", icon_url=user.display_avatar.url)
return embed
async def send_log(guild: discord.Guild, embed: discord.Embed):
channel = get_log_channel(guild)
if channel is None:
return
try:
await channel.send(embed=embed)
except discord.Forbidden:
print(f"⚠️ {guild.name}: 没有在日志频道发送消息的权限。")
def cut(text: str) -> str:
text = text or "(没有内容 — 只有嵌入/附件,或不在缓存中)"
return text if len(text) <= MAX_CONTENT else text[:MAX_CONTENT] + " …(已省略)"- timestamp=discord.utils.utcnow() : 嵌入消息底部会自动显示"今天 下午3:12"这样的时间,而且是按查看者自己的时区显示。日志里最重要的就是时间嘛!
- set_author(name, icon_url) : 在嵌入消息最上方放上头像 +
名字 (ID)。之所以把 ID 一起留下,是因为之后就算对方改了昵称或者退出服务器,ID 也不会变。 - send_log 里的 try/except : 如果有人改了日志频道的权限,机器人可能会因为
Forbidden崩掉。按 #25 学过的方法把它捕获,只在控制台打印一下就跳过。 - cut() : 嵌入字段的值有 1024 字的限制。超过就会报
400 Bad Request,所以提前截断。
📌 第 3 步 - 核心!捕获消息删除和编辑
这里要用到 raw 事件。on_message_delete 只会通知缓存里有的消息,而 on_raw_message_delete 即使不在缓存里,也会告诉你"哪个频道的哪个 ID 被删了"。

async def find_deleter(guild: discord.Guild, author_id: int, channel_id: int):
"""在审核日志里查找'刚刚在这个频道删了这个人消息的管理员'。"""
try:
async for entry in guild.audit_logs(limit=5, action=discord.AuditLogAction.message_delete):
same_target = entry.target is not None and entry.target.id == author_id
same_channel = entry.extra.channel.id == channel_id
recent = (discord.utils.utcnow() - entry.created_at).total_seconds() < 15
if same_target and same_channel and recent:
return entry.user
except discord.Forbidden:
return None
return None
@bot.event
async def on_raw_message_delete(payload: discord.RawMessageDeleteEvent):
if payload.guild_id is None: # 忽略私信
return
guild = bot.get_guild(payload.guild_id)
msg = payload.cached_message
embed = make_embed("🗑️ 消息删除", discord.Color.red(), msg.author if msg else None)
embed.add_field(name="频道", value=f"<#{payload.channel_id}>", inline=True)
if msg is None:
embed.add_field(name="内容", value="不在缓存中的消息 (机器人启动前的消息)", inline=False)
embed.set_footer(text=f"消息 ID: {payload.message_id}")
else:
if msg.author.bot:
return
deleter = await find_deleter(guild, msg.author.id, payload.channel_id)
who = deleter.mention if deleter else "本人 (或无法确认)"
embed.add_field(name="删除者", value=who, inline=True)
embed.add_field(name="内容", value=cut(msg.content), inline=False)
if msg.attachments:
files = "\n".join(a.filename for a in msg.attachments)
embed.add_field(name="附件", value=files, inline=False)
embed.set_footer(text=f"消息 ID: {msg.id}")
await send_log(guild, embed)
@bot.event
async def on_raw_message_edit(payload: discord.RawMessageUpdateEvent):
if payload.guild_id is None:
return
before = payload.cached_message
after = payload.message
if before is None or after.author.bot:
return
if before.content == after.content: # 过滤掉生成嵌入预览等'假编辑'
return
guild = bot.get_guild(payload.guild_id)
embed = make_embed("✏️ 消息编辑", discord.Color.orange(), after.author)
embed.add_field(name="频道", value=after.channel.mention, inline=True)
embed.add_field(name="跳转", value=f"[跳到消息]({after.jump_url})", inline=True)
embed.add_field(name="编辑前", value=cut(before.content), inline=False)
embed.add_field(name="编辑后", value=cut(after.content), inline=False)
await send_log(guild, embed)
@bot.event
async def on_raw_bulk_message_delete(payload: discord.RawBulkMessageDeleteEvent):
if payload.guild_id is None:
return
guild = bot.get_guild(payload.guild_id)
embed = make_embed("🧹 批量删除消息", discord.Color.dark_red())
embed.add_field(name="频道", value=f"<#{payload.channel_id}>", inline=True)
embed.add_field(name="数量", value=f"{len(payload.message_ids)} 条", inline=True)
await send_log(guild, embed)我们逐个拆开来看 💡
- payload.cached_message : 被删的消息如果在机器人缓存里,就是
Message对象,不在就是None。机器人启动前发出的消息不在缓存里,所以记为"无法确认内容",但频道和消息 ID 还是会留下。这对调查也有帮助。 - guild.audit_logs(limit=5, action=...) : 按从新到旧的顺序遍历服务器审核日志的异步迭代器。不能用
for,必须用async for来遍历。机器人没有查看审核日志权限时会抛出Forbidden,所以用 try 包起来了。 - entry.target / entry.extra.channel / entry.created_at :
message_delete条目里,target 是发消息的人,extra.channel是被删消息所在的频道,extra.count是删除的条数。三项都对得上、并且是 15 秒内生成的条目,那它的entry.user(执行者)就是删除者。 - "本人 (或无法确认)" : 自己删自己的消息,审核日志里根本不会留下记录。所以在审核日志里找不到时,就当作本人删除。不过,如果同一个管理员连续删除同一个人的消息,Discord 只会把已有条目的 count 加一,而不会新建条目,这时可能会因为 15 秒的条件而漏掉。只要记住它不是 100% 准确就好。
- payload.message (编辑事件) : 这是编辑后的消息(2.5 起新增)。编辑前的消息从
cached_message里取。贴上链接时,Discord 生成预览嵌入会再发一次编辑事件,这里让content相同时直接跳过,避免日志变得乱七八糟。 - on_raw_bulk_message_delete : 管理员执行"删除 100 条消息"这类批量删除(purge)时,不会逐条触发删除事件,而是只来一次这个事件。把内容全部记下来日志会爆炸,所以只记录了条数。
📌 第 4 步 - 加入·离开·昵称·身份组变更
@bot.event
async def on_member_join(member: discord.Member):
embed = make_embed("📥 成员加入", discord.Color.green(), member)
embed.add_field(name="成员", value=member.mention, inline=True)
embed.add_field(name="账号创建日期", value=discord.utils.format_dt(member.created_at, "R"), inline=True)
embed.add_field(name="当前人数", value=f"{member.guild.member_count} 人", inline=True)
await send_log(member.guild, embed)
@bot.event
async def on_member_remove(member: discord.Member):
embed = make_embed("📤 成员离开", discord.Color.light_grey(), member)
embed.add_field(name="成员", value=f"{member} ({member.mention})", inline=True)
if member.joined_at:
embed.add_field(name="加入日期", value=discord.utils.format_dt(member.joined_at, "R"), inline=True)
roles = [r.mention for r in member.roles if r != member.guild.default_role]
if roles:
embed.add_field(name="拥有过的身份组", value=" ".join(roles), inline=False)
await send_log(member.guild, embed)
@bot.event
async def on_member_update(before: discord.Member, after: discord.Member):
if before.nick != after.nick:
embed = make_embed("🏷️ 昵称变更", discord.Color.blue(), after)
embed.add_field(name="变更前", value=before.nick or "(无)", inline=True)
embed.add_field(name="变更后", value=after.nick or "(无)", inline=True)
await send_log(after.guild, embed)
added = [r for r in after.roles if r not in before.roles]
removed = [r for r in before.roles if r not in after.roles]
if added or removed:
embed = make_embed("🎭 身份组变更", discord.Color.blurple(), after)
if added:
embed.add_field(name="➕ 新增", value=" ".join(r.mention for r in added), inline=False)
if removed:
embed.add_field(name="➖ 移除", value=" ".join(r.mention for r in removed), inline=False)
await send_log(after.guild, embed)- format_dt(时间, "R") : 转换成
<t:1790291186:R>格式,Discord 就会显示成 "3 天前"、"2 年前" 这样的相对时间。加入日志里账号创建日期如果是"12 分钟前"呢?那很可能是机器人账号或小号。这是管理员们最喜欢的字段 👀 - on_member_remove : 自己退出也好,被踢出、被封禁也好,全部都走这个事件。所以"为什么离开"要靠下一步的审核日志事件另外记录。
- 比较 before.roles / after.roles :
on_member_update在昵称、身份组、禁言、服务器头像等任何东西变化时都会触发。所以要在里面自己比较"到底变了什么"。这里用身份组列表的差集来区分新增和移除。
📌 第 5 步 - 踢出·封禁用审核日志事件(谁·为什么)
MOD_ACTIONS = {
discord.AuditLogAction.kick: ("👢 踢出(Kick)", discord.Color.dark_orange()),
discord.AuditLogAction.ban: ("🔨 封禁(Ban)", discord.Color.dark_red()),
discord.AuditLogAction.unban: ("🕊️ 解除封禁(Unban)", discord.Color.teal()),
}
@bot.event
async def on_audit_log_entry_create(entry: discord.AuditLogEntry):
if entry.action not in MOD_ACTIONS:
return
title, color = MOD_ACTIONS[entry.action]
embed = make_embed(title, color, entry.user)
target = entry.target
embed.add_field(name="对象", value=f"{target} (<@{target.id}>)" if target else "(未知)", inline=True)
embed.add_field(name="执行者", value=entry.user.mention if entry.user else "(未知)", inline=True)
embed.add_field(name="原因", value=entry.reason or "(未填写原因)", inline=False)
await send_log(entry.guild, embed)- on_audit_log_entry_create : 服务器审核日志里生成新条目的那一刻就会实时调用(discord.py 2.2+,需要
Intents.moderation,机器人必须有查看审核日志权限)。不像第 3 步那样事后去翻找,而是 Discord 主动通知你,所以准确得多。 - entry.action : 表示是什么操作的
AuditLogAction枚举。今天只挑了踢出、封禁、解封三种,但还有channel_create、role_update、member_role_update等几十种。只要在字典里加一行,日志种类就会增加。 - entry.user / entry.target / entry.reason : 分别是执行的管理员、被处理的人,以及管理员踢人时填写的原因。没填原因时是
None,所以换成了"(未填写原因)"。
💡 执行者显示为 None?用户信息不在缓存里时可能会这样。entry.user_id(2.2+)总是有值的,所以直接用 f"<@{entry.user_id}>" 打出提及也可以。
📌 第 6 步 - 频道创建·删除 + 日志频道设置命令
@bot.event
async def on_guild_channel_create(channel: discord.abc.GuildChannel):
embed = make_embed("📁 频道创建", discord.Color.green())
embed.add_field(name="频道", value=f"{channel.mention} (`{channel.name}`)", inline=True)
embed.add_field(name="类型", value=str(channel.type), inline=True)
await send_log(channel.guild, embed)
@bot.event
async def on_guild_channel_delete(channel: discord.abc.GuildChannel):
embed = make_embed("🗂️ 频道删除", discord.Color.red())
embed.add_field(name="频道", value=f"`{channel.name}`", inline=True)
embed.add_field(name="类型", value=str(channel.type), inline=True)
await send_log(channel.guild, embed)
@bot.tree.command(name="로그설정", description="[管理员] 设置发送服务器日志的频道")
@app_commands.describe(채널="用来存放日志的文字频道")
@app_commands.checks.has_permissions(administrator=True)
async def set_log(interaction: discord.Interaction, 채널: discord.TextChannel):
me = interaction.guild.me
perms = 채널.permissions_for(me)
if not (perms.send_messages and perms.embed_links):
return await interaction.response.send_message(
f"❌ 我在 {채널.mention} 没有**发送消息·嵌入链接**权限。", ephemeral=True)
async with lock:
log_channels[str(interaction.guild.id)] = 채널.id
save()
await interaction.response.send_message(f"✅ 以后服务器日志会记录在 {채널.mention}!", ephemeral=True)
await 채널.send(embed=make_embed("🟢 已设为日志频道", discord.Color.green(), interaction.user))
@bot.tree.command(name="로그해제", description="[管理员] 停止记录服务器日志")
@app_commands.checks.has_permissions(administrator=True)
async def unset_log(interaction: discord.Interaction):
async with lock:
log_channels.pop(str(interaction.guild.id), None)
save()
await interaction.response.send_message("⏹️ 已关闭日志记录。", ephemeral=True)
@bot.tree.error
async def on_app_command_error(interaction: discord.Interaction, error: app_commands.AppCommandError):
if isinstance(error, app_commands.MissingPermissions):
await interaction.response.send_message("❌ 只有管理员才能使用这个命令。", ephemeral=True)
else:
raise error
@bot.event
async def on_ready():
load()
await bot.tree.sync()
print(f"✅ 已登录: {bot.user} / 已设置日志的服务器 {len(log_channels)} 个")
bot.run(token)
- 채널: discord.TextChannel : 把斜杠命令参数的类型设为频道,Discord 就会弹出频道选择界面。就是我们在 #15 命令组篇 里见过的那个功能。
- 채널.permissions_for(me) : 在设置的时候就提前检查机器人能不能真的在日志频道里发消息。比起之后事件触发时悄悄失败,现在就告诉管理员要友好得多。
- bot.tree.error : 非管理员输入命令时会抛出
MissingPermissions,不捕获的话只会弹出"交互失败"这种不友好的提示。和 #25 里的写法完全一样。
📎 把第 1~6 步的代码块按顺序拼起来,就是完整版。保存为 logbot.py 直接运行就行。
📌 运行结果
- 执行
python logbot.py→ 控制台显示✅ 已登录: 机器人名字 / 已设置日志的服务器 0 个 - 管理员新建一个类似
#서버-로그(服务器日志) 的私密频道,然后执行/로그설정 채널:#서버-로그(日志设置命令) → 会收到一条绿色的"🟢 已设为日志频道"嵌入消息。 - 在任意频道发一条消息再删掉 → 🗑️ 红色嵌入消息里会原样留下删除的内容。管理员删除别人的消息时,"删除者"一栏会显示管理员的提及。
- 编辑消息 → ✏️ 橙色嵌入消息会并排显示编辑前后的内容,点链接就能跳到那条消息。
- 用小号加入服务器再退出 → 会依次出现 📥 加入(账号创建日期"N 分钟前"!) → 📤 离开;如果执行踢出,📤 离开后面还会跟着一条带执行者和原因的 👢 踢出嵌入消息。
💡 日志频道一定要锁好权限,只让管理员看得到。这个频道会原样保留被删消息的内容,普通成员看到的话,就会有人抱怨"我都删了怎么还留着"。另外别忘了大概每个月清理一次旧日志。
💡 附赠 - 增加日志种类
只要在 MOD_ACTIONS 字典里添加条目,审核日志的种类就会增加。下面是常用的几个。
discord.AuditLogAction.member_update: ("⏳ 禁言/昵称变更", discord.Color.gold()),
discord.AuditLogAction.role_create: ("🎨 身份组创建", discord.Color.green()),
discord.AuditLogAction.role_delete: ("🎨 身份组删除", discord.Color.red()),
discord.AuditLogAction.message_bulk_delete: ("🧹 批量删除 (管理员)", discord.Color.dark_red()),打印 entry.changes.before / entry.changes.after 看看,连"身份组名称从 A 改成了 B""禁言到什么时候"这样的详细变更也能取出来。语音频道进出日志,只要在 #31 用过的 on_voice_state_update 里加一行嵌入消息就搞定了。
📌 常见错误
- 删除日志里的内容只显示"(没有内容)" → 原因:没在开发者门户打开 Message Content Intent,或者代码里漏了
intents.message_content = True→ 解决:两边都打开并重启机器人。机器人启动之前发出的消息不在缓存里,本来就看不到,这是正常的。 - on_member_join / on_member_remove 不触发 → 原因:没设置 Server Members Intent → 解决:在门户 Bot 标签页打开它,并确认
intents.members = True。不开的话连错误都没有,只是悄悄地不触发,很容易让人摸不着头脑。 discord.errors.Forbidden: 403 Forbidden (error code: 50013): Missing Permissions→ 原因:机器人的身份组没有查看审核日志权限 → 解决:服务器设置 → 身份组 → 在机器人身份组里勾选"查看审核日志"。没有这个权限的话,on_audit_log_entry_create也不会触发。HTTPException: 400 Bad Request (error code: 50035): Invalid Form Body—In embeds.0.fields.2.value: Must be 1024 or fewer in length→ 原因:往嵌入字段里放了超过 1024 字的内容 → 解决:像示例里的cut()那样截断。如果长消息很多,也可以把内容用discord.File作为文本文件附上。TypeError: 'async_generator' object is not iterable→ 原因:用for遍历了guild.audit_logs()→ 解决:改成async for。它是异步迭代器。- 每次贴链接,编辑日志都会出现两次 → 原因:Discord 附加链接预览(嵌入)时会再发送一次编辑事件 → 解决:像示例那样,
before.content == after.content时直接跳过。 - 机器人报
discord.errors.PrivilegedIntentsRequired,连启动都启动不了 → 原因:代码里打开了特权 Intent,门户里却没打开 → 解决:门户 Bot 标签页 → Privileged Gateway Intents 里把两个都设为 ON。
🙌 结语
今天我们把 raw 事件 + 审核日志(Audit Log)查询 + on_audit_log_entry_create 三者组合起来,完成了一个从消息删除·编辑到成员进出·身份组变更·踢出·封禁,都以嵌入消息记录到同一个频道的日志机器人。总结一下:
- 被删消息的内容只有在缓存里时才能看到 → 把
max_messages调大,打开 2 个特权 Intent - 是谁删的要在
guild.audit_logs()里按 target、频道和时间查找 (本人删除没有记录) - 踢出和封禁用
on_audit_log_entry_create实时接收,连执行者和原因都有 - 嵌入字段有 1024 字限制,日志频道要锁成仅管理员可见
下一篇会讲 #31 里预告过的临时语音频道扩展 — 转让房主、踢人、仅限邀请(白名单)的房间,以及会同时生成文字频道的"派对房"。敬请期待 🙌
你的服务器最需要哪种日志?欢迎在评论里告诉我,我会考虑加到附赠部分里 😎
📚 推荐一起阅读
连载 · 共 32 篇中的第 31 篇
Discord 机器人开发
- #1Discord 机器人开发 - Slash Command 完全攻略!
- #2为 Slash Command 添加选项(Arguments)!
- #3在 Slash Command 中添加子命令(Subcommand)!
- #4用 Slash Command 发送 Embed 嵌入消息!
- #5实现按钮(Button)交互!
- #6实现下拉菜单(Select Menu)!
- #7用模态框(Modal)接收用户输入(Python 示例)
- #8用嵌入消息(Embed)的图片和字段美化消息(Python 示例)
- #9接入 AI(Claude·ChatGPT API)!(Python 示例)
- #10支持多语言(i18n)!(Python 示例)
- #11用 Flask 制作网页仪表盘!(Python 示例)
- #12管理命令冷却时间(Cooldown)与权限(Permission)!(Python 示例)
- #13用身份组·频道自动化管理服务器!(Python 示例)
- #14保存数据!JSON vs SQLite(Python 示例)
- #15슬래시 명령어 그룹(Group)으로 명령어 정리하기! (파이썬 예제) (韩语)
- #16리마인더·알림 기능 만들기! 봇이 먼저 말 걸게 하기 (파이썬 예제) (韩语)
- #17RAG로 문서 기반 답변봇 만들기! 우리 서버 전용 FAQ 봇 (파이썬 예제) (韩语)
- #18투표(Poll) 기능 만들기! 다수결로 정하는 서버 규칙 (파이썬 예제) (韩语)
- #19Cog로 코드 쪼개기! 1000줄 봇도 안 더러워지는 구조 (파이썬 예제) (韩语)
- #20자동 환영 메시지·온보딩 만들기! 규칙 동의 버튼으로 자동 역할 부여 (파이썬 예제) (韩语)
- #21키워드 자동응답·금지어 필터 만들기! 경고 누적으로 자동 제재까지 (파이썬 예제) (韩语)
- #22슬래시 명령어 자동완성(Autocomplete) 만들기! 금지어를 골라서 추가·삭제 (파이썬 예제) (韩语)
- #23aiosqlite로 비동기 DB 제대로 설계하기! JSON 탈출 (파이썬 예제) (韩语)
- #24채널 난독화(Channel Obfuscation) 대응하기! 11/16부터 안 보이는 채널이 생겨요 (파이썬 예제) (韩语)
- #25봇이 죽지 않게! 에러 핸들링·로깅 체계 잡기 (파이썬 예제) (韩语)
- #26티켓(Ticket) 문의 시스템 만들기! 버튼 하나로 1:1 상담 채널 자동 생성 (파이썬 예제) (韩语)
- #27티켓 담당자 배정·우선순위 만들기! 스태프가 여러 명이어도 안 꼬이게 (파이썬 예제) (韩语)
- #28레벨·경험치(XP) 시스템 만들기! 채팅할수록 레벨업, 랭킹판까지 (파이썬 예제) (韩语)
- #29화폐·상점(Economy) 시스템 만들기! 코인 벌어서 아이템 사기 (파이썬 예제) (韩语)
- #30打造投票·问卷(Poll)机器人!原生投票 + 按钮实时统计(Python 示例)🗳️
- #32打造服务器日志·审核日志(Audit Log)频道!自动记录消息删除、编辑、成员进出和踢出(Python 示例)🕵️当前文章
- #33임시 음성방 확장, 파티방 만들기! 방장 위임·강퇴·초대 전용(비공개) 방 + 전용 채팅방 자동 생성 (파이썬 예제) 🎉 (韩语)
