本文详解为何加载 Cog 后显示 “0 commands synced”,核心原因在于混淆了传统文本命令(@commands.command)与应用命令(@app_commands.command)的注册机制,需使用正确的装饰器并确保 Cog 正确支持 Slash 命令。
本文详解为何加载 cog 后显示 “0 commands synced”,核心原因在于混淆了传统文本命令(`@commands.command`)与应用命令(`@app_commands.command`)的注册机制,需使用正确的装饰器并确保 cog 正确支持 slash 命令。
在 Discord.py 2.0+(尤其是启用 discord.app_commands 的 Slash 命令场景)中,
Cog 必须显式继承 app_commands.Group 或通过 @app_commands.command 定义命令,并配合 Tree.sync() 才能被识别为可同步的全局/服务器命令
。你当前的代码中使用了 @commands.command(name="say") —— 这是一个传统的前缀命令(如 .say hello),它
完全不会被 client.tree.sync() 检测或同步
,因此日志中始终显示 synced 0 commands,且无法在 Discord 客户端看到或触发 /say。
✅ 正确做法:在 Cog 中定义 Slash 命令
你需要将命令装饰器从 @commands.command 改为 @app_commands.command,并确保该命令定义在继承自 commands.Cog 的类中(无需额外继承 app_commands.Group,除非需分组)。同时,setup() 函数必须调用 await client.add_cog(...),这是 Discord.py 加载 Slash 命令 Cog 的标准入口。
以下是修复后的 say_cog.py 示例(建议文件名小写、无空格):
⚠️ 关键注意事项
装饰器不可混用
:@commands.command 和 @app_commands.command 是两类独立系统,前者用于 .prefix 命令,后者用于 /slash 命令;二者不能共存于同一函数。
参数类型约束
:app_commands.command 的参数不支持 str | None 写法(会引发同步失败)。如需可选文本,请改用 str = "" 默认值 + 逻辑判断,或使用 app_commands.Transform 自定义转换器。
权限检查推荐用 @app_commands.checks
:如 @app_commands.checks.has_permissions(administrator=True),比手动 if not interaction.user.guild_permissions... 更安全、更易维护,且自动返回标准拒绝响应。
setup() 是唯一加载入口
:确保 main.py 中 await client.load_extension("cogs.say_cog")(注意模块名匹配文件名),且 say_cog.py 位于 cogs/ 目录下。
同步时机很重要
:client.tree.sync() 应在所有 Cog 加载完成后调用(你当前代码中放在 on_ready 内是正确的),但首次同步可能需等待 Discord API 缓存刷新(最多 1 小时),可加 guild=discord.Object(id=YOUR_GUILD_ID) 实现测试服即时同步。
✅ 验证是否成功
启动 Bot 后查看控制台输出:应显示 synced 1 commands;
在 Discord 中输入 /,检查是否出现 /say 命令;
若未出现,尝试重启 Bot、清空客户端缓存,或在开发服务器中指定 guild 参数进行局部同步(调试更高效)。
遵循以上规范,你的 Slash 命令即可被正确识别、同步并投入使用。记住:
Cog 中的 Slash 命令 = @app_commands.command + await client.add_cog() + client.tree.sync()
—— 缺一不可。
import discord
from discord import app_commands
from discord.ext import commands
class SayCog(commands.Cog):
def __init__(self, client: commands.Bot):
self.client = client
@app_commands.command(
name="say",
description="让机器人发送指定消息(仅管理员可用)"
)
@app_commands.describe(thing_to_say="要发送的文本内容")
@app_commands.checks.has_permissions(administrator=True)
async def say(self, interaction: discord.Interaction, thing_to_say: str):
# 注意:app_commands.command 不支持 None 类型参数的默认值处理,
# 若需可选参数,请使用 app_commands.Range[str, 1, 2000] 或保留必填 + 提供帮助说明
await interaction.response.send_message(f"✅ 已发送:{thing_to_say}")
# 可选:添加权限检查的错误处理器
@say.error
async def say_error(self, interaction: discord.Interaction, error: app_commands.AppCommandError):
if isinstance(error, app_commands.MissingPermissions):
await interaction.response.send_message("❌ 你没有管理员权限,无法使用此命令。", ephemeral=True)
else:
await interaction.response.send_message("⚠️ 命令执行出错,请联系开发者。", ephemeral=True)
# 必须提供 setup 函数,且签名需为 async def setup(bot: commands.Bot)
async def setup(client: commands.Bot):
await client.add_cog(SayCog(client))