常见问题 Q&A
约 1714 字大约 6 分钟
本章汇总 EasyBot SDK 开发过程中常见的问题及解决方案。
一、安装与配置
Q1: 安装后导入报错 ModuleNotFoundError
现象:
ModuleNotFoundError: No module named 'easybot'解决方案:
# 确认使用正确的 Python
python --version
# 安装 SDK
pip install easybot-qq
# 验证安装
python -c "from easybot import Bot; print('OK')"Q2: AppID 和 AppSecret 在哪里获取?
步骤:
- 访问 QQ 开放平台
- 登录并进入「机器人」管理页面
- 创建或选择你的机器人应用
- 在「开发设置」中查看 AppID 和 AppSecret
⚠️ 安全提示: 不要将 AppSecret 提交到公开仓库。建议使用环境变量管理。
import os
from easybot import Bot
bot = Bot(
app_id=os.environ["BOT_APP_ID"],
app_secret=os.environ["BOT_APP_SECRET"],
)二、连接问题
Q3: WebSocket 连接失败 / 超时
现象:
WebSocket connection failed: timeout排查步骤:
检查网络连通性
curl https://sandbox.api.sgroup.qq.com/websocket/gateway检查是否需要代理
import os os.environ["HTTP_PROXY"] = "http://127.0.0.1:7890"调整超时时间
from easybot import Proto bot = Bot( app_id="xxx", app_secret="xxx", protocol=Proto.websocket(connect_timeout=60.0), )
Q4: Webhook 模式下无法接收事件
排查清单:
| 检查项 | 说明 |
|---|---|
| 端口是否被占用 | netstat -ano | findstr :8080 |
| 公网可达性 | 使用 ngrok/frp 等工具暴露本地端口 |
| QQ 开放平台回调地址 | 必须填写公网可访问的 URL |
| SSL 证书 | 生产环境要求 HTTPS |
示例 — 本地开发使用 Webhook:
# 安装 ngrok
ngrok http 8080
# 获得 https://xxxx.ngrok-free.appfrom easybot import Bot, Proto
bot = Bot(
app_id="xxx",
app_secret="xxx",
protocol=Proto.webhook(port=8080, path="/callback"),
)
# 在 QQ 开放平台设置回调地址:
# https://xxxx.ngrok-free.app/callback三、消息收发
Q5: 收不到频道消息
常见原因及解决:
| 原因 | 解决方案 |
|---|---|
| 未订阅 Intent | 确保 on_guild_message 已注册 |
| 公域未 @机器人 | 公域机器人只能接收 @它的消息 |
| 私域未开启全量消息 | 私域需在开放平台开启 GUILD_MESSAGES Intent |
| 沙箱过滤 | 检查 SandBox 配置 |
验证方式:
from easybot import Model
@bot.on_guild_message
async def debug_msg(msg: Model.GuildMessage) -> None:
print(f"收到消息: {msg.content}")Q6: 发送消息失败 — 权限不足
现象:
API Error: 403 Forbidden解决方案:
检查子频道发言权限
perms = await bot.api.get_channel_user_permissions( channel_id=ch_id, user_id=bot.bot_id )授予机器人发送消息权限
- 进入频道 → 子频道设置 → 权限管理
- 为机器人角色添加「发送消息」权限
Q7: 发送图片不显示
排查步骤:
图片 URL 是否可访问
- 必须是公网可访问的 HTTPS URL
使用 file_image 发送本地图片
await bot.api.send_guild_message( channel_id="xxx", content="图片", file_image="./image.png", )群聊/单聊场景发送图片
# 先上传获取 file_info file_info = await bot.api.upload_media( file_type=1, # 1=图片 file_data="./image.png", group_openid="xxx", )
使用 media_file_info 发送
await bot.api.send_group_message( group_openid="xxx", content="图片消息", media_file_info=file_info.file_info, )
---
## 四、命令系统
### Q8: 注册的命令没有被触发
**排查清单**:
1. **命令词是否完全匹配**
```python
from easybot import Model
# ✅ 同时注册多种写法
@bot.on_command(command=["/ping", "/Ping", "/PING"])
async def ping(
msg: Model.GuildMessage | Model.GroupMessage | Model.C2CMessage | Model.DirectMessage,
) -> None:
await msg.reply("Pong!")valid_scenes 场景限制
# 仅频道可用 @bot.on_command( command="/guild_only", valid_scenes=CommandValidScenes.GUILD )预处理器中断了流程
from easybot import Model @bot.before_command() async def pre( msg: Model.GuildMessage | Model.GroupMessage | Model.C2CMessage | Model.DirectMessage, ) -> bool: if some_condition: return False # 这会导致后续命令不被执行 return True
Q9: 正则命令匹配不到
常见错误:
# ❌ 忘记 ^ 和 $ 导致部分匹配
@bot.on_command(regex=r"计算\s+\d+")
# ✅ 使用 ^ 匹配开头
@bot.on_command(regex=r"^计算\s+(.+)$")
# ❌ 正则中有特殊字符未转义
@bot.on_command(regex=r"/cmd\?id=\d+")
# ✅ 转义特殊字符
@bot.on_command(regex=r"/cmd\?id=(\d+)")Q10: 如何实现命令别名?
from easybot import Model
# 方式一: command 参数传入列表
@bot.on_command(command=["/help", "/h", "帮助"])
async def help_cmd(
msg: Model.GuildMessage | Model.GroupMessage | Model.C2CMessage | Model.DirectMessage,
) -> None:
await msg.reply("帮助信息...")
# 方式二: 多个装饰器绑定同一函数
async def handle_ping(
msg: Model.GuildMessage | Model.GroupMessage | Model.C2CMessage | Model.DirectMessage,
) -> None:
await msg.reply("Pong!")
bot.on_command("/ping")(handle_ping)
bot.on_command("/p")(handle_ping)五、API 调用
Q11: API 返回错误码
常见错误码:
| 错误码 | 含义 | 解决方案 |
|---|---|---|
| 40001 | access_token 无效 | 检查 AppSecret 是否正确 |
| 40002 | access_token 过期 | SDK 自动刷新 |
| 40303 | 权限不足 | 检查机器人权限配置 |
| 42900 | 请求过于频繁 | 降低调用频率 |
| 50001 | 内部服务器错误 | 稍后重试 |
查看详细错误信息:
from easybot.exceptions import APIError
try:
guild = await bot.api.get_guild(guild_id="xxx")
except APIError as e:
print(f"API 调用失败: {e}")Q12: API 调用超时
解决方案:
# 增加 API 超时时间
bot = Bot(app_id="xxx", app_secret="xxx", api_timeout=60)
# 配置重试次数
bot = Bot(app_id="xxx", app_secret="xxx", is_retry=5)Q13: 分页数据如何完整获取?
async def get_all_members(bot, guild_id):
"""获取频道全部成员"""
all_members = []
after = "0"
while True:
members = await bot.api.get_guild_members(
guild_id=guild_id,
after=after,
limit=100,
)
if not members:
break
all_members.extend(members)
after = members[-1].user.id
return all_members六、会话管理
Q14: Session 数据丢失
可能原因:
- 超时过期 — 设置了
timeout且长时间未访问 - 作用域/标识不匹配 —
new()和get()使用了不同的参数 - 程序重启后未恢复 — 确认持久化文件可写
调试方法:
from easybot import Scope
with bot.session.bind(msg) as s:
session = await s.get(scope=Scope.USER, key="my_key")
if session and session.status == 0:
print(f"会话数据: {session.data}")
else:
print("会话不存在或已失活")Q15: 如何持久化 Session?
EasyBot 的 SessionManager 内置自动持久化功能:
- 默认存储路径:
<工作目录>/sdk_data/sessions.pickle - 每次
new()/update()/remove()后自动写入 - Bot 启动时自动从文件恢复
七、性能与部署
Q16: 内存占用过高
优化建议:
合理设置 timeout
from easybot import Scope # 减少超时时间 with bot.session.bind(msg) as s: await s.new(scope=Scope.USER, key="temp", data={...}, timeout=120)避免在事件处理器中存储大量数据
# ✅ 只存必要的状态 with bot.session.bind(msg) as s: await s.new(scope=Scope.USER, key="chat", data={ "last_msg_id": msg.id, "step": "waiting_reply", })
Q17: 如何部署到 Linux 服务器?
推荐方案:
使用 systemd 管理
# /etc/systemd/system/easybot.service [Unit] Description=EasyBot Robot After=network.target [Service] Type=simple User=www-data WorkingDirectory=/opt/easybot ExecStart=/usr/bin/python3 main.py Restart=always [Install] WantedBy=multi-user.target使用 Docker
FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . CMD ["python", "main.py"]
Q18: 日志级别如何调整?
# 通过 Bot 参数
bot = Bot(app_id="xxx", app_secret="xxx", is_debug=True)
# is_debug=True 会自动启用 DEBUG 级别日志八、其他问题
Q19: 如何同时监听多个事件类型?
async def log_all(event_data):
print(f"收到事件: {type(event_data).__name__}")
bot.on_guild_message(log_all)
bot.on_at_group_message(log_all)
bot.on_group_message(log_all)
bot.on_c2c_message(log_all)Q20: 如何优雅关闭机器人?
# 方式一: Ctrl+C(自动捕获 KeyboardInterrupt)
bot.start()
# 方式二: 异步上下文管理器
async def main():
async with bot:
await bot.start_async()
# 方式三: 手动停止
await bot.stop_async()Q21: 如何获取机器人的用户 ID?
from easybot import Model
# 启动后: 自动填充
bot.start()
# 或在启动事件中获取
@bot.on_startup
async def on_ready(event: Model.StartupEvent) -> None:
me = await bot.api.get_me()
print(f"机器人 ID: {me.id}, 名称: {me.username}")九、下一步
如果你遇到的问题不在上述列表中,请查阅以下资源:
- GitHub Issues — 搜索已有问题
- 联系和反馈 — 获取技术支持