QBot项目模块开发的接口规范、最佳实践和开发指南。所有新模块必须遵循此规范。
本skill定义了QBot项目中所有功能模块必须遵循的接口规范和最佳实践。在开发新模块前,必须完整阅读本文档。
BaseModule并实现标准接口modules/
└── your_module/
├── __init__.py # 空文件
├── module.py # 主模块类(必须)
└── [其他文件] # 可选辅助文件
"""
模块名称 - 简短描述
"""
import re
from typing import Optional
from core.base_module import BaseModule, ModuleContext, ModuleResponse
from config import get_bot_qq_list, DEBUG_MODE
class YourModule(BaseModule):
"""模块功能详细描述"""
# ===== 必须实现的属性 =====
@property
def name(self) -> str:
return "模块名称"
@property
def version(self) -> str:
return "1.0.0"
@property
def description(self) -> str:
return "模块功能描述"
@property
def author(self) -> str:
return "QBot Team"
# ===== 生命周期钩子 =====
async def on_load(self, config: dict) -> None:
"""模块加载时初始化"""
await super().on_load(config)
# 保存配置
self.config = config
settings = config.get('settings', {})
# 获取机器人列表(必须)
self.bot_qq_list = get_bot_qq_list()
# 初始化配置
self.watched_groups = settings.get('watched_groups', [])
# 编译正则表达式
self.pattern = re.compile(r'your_pattern')
print(f"[{self.name}] 模块已加载 (v{self.version})")
# ===== 必须实现的方法 =====
async def can_handle(self, message: str, context: ModuleContext) -> bool:
"""判断是否能处理该消息"""
# 1. 过滤机器人消息(必须)
if context.user_id in self.bot_qq_list:
if DEBUG_MODE:
print(f"[{self.name}] 跳过机器人消息: {context.user_id}")
return False
# 2. 私聊处理(可选)
if context.group_id is None:
return self.check_private_message(message)
# 3. 群组过滤
if context.group_id not in self.watched_groups:
return False
# 4. 内容匹配
return bool(self.pattern.search(message))
async def handle(self, message: str, context: ModuleContext) -> Optional[ModuleResponse]:
"""处理消息并返回响应"""
try:
# 处理逻辑
result = await self.process_message(message, context)
# 返回响应
return ModuleResponse(
content=result,
auto_recall=False,
recall_delay=30
)
except Exception as e:
print(f"[{self.name}] ❌ 处理失败: {e}")
if DEBUG_MODE:
import traceback
traceback.print_exc()
return None
| 属性 | 类型 | 必须 | 说明 | 示例 |
|---|---|---|---|---|
name |
str |
✅ | 模块唯一标识 | "返利模块" |
version |
str |
✅ | 语义化版本号 | "1.0.0" |
description |
str |
✅ | 功能描述 | "自动转换推广链接" |
author |
str |
📝 | 作者信息 | "QBot Team" |
dependencies |
List[str] |
📝 | 依赖模块列表 | ["数据库模块"] |
can_handle(message, context) -> bool必须实现。判断模块是否能处理当前消息。
关键检查项:
if context.user_id in self.bot_qq_list: return Falsehandle(message, context) -> Optional[ModuleResponse]必须实现。处理消息并返回响应。
关键要点:
async/awaittry-except包裹所有逻辑[{self.name}]必须在can_handle开头过滤机器人消息:
async def can_handle(self, message: str, context: ModuleContext) -> bool:
# 过滤所有机器人消息(防止循环)
if context.user_id in self.bot_qq_list:
if DEBUG_MODE:
print(f"[{self.name}] 跳过机器人消息: {context.user_id}")
return False
# ... 其他逻辑
如需实现多机器人优先级响应:
from config import get_bot_priority
import main
def should_respond_by_priority(self, context: ModuleContext) -> bool:
"""只让优先级最高的在线机器人响应"""
current_bot = context.self_id
online_bots = main.get_online_bots()
# 找出在线的优先级机器人
online_priority_bots = [bot for bot in self.bot_priority if bot in online_bots]
if not online_priority_bots:
return True
# 只有优先级最高的在线机器人响应
return current_bot == online_priority_bots[0]
async def can_handle(self, message: str, context: ModuleContext) -> bool:
# ... 其他检查
# 优先级检查
if not self.should_respond_by_priority(context):
return False
# ...
# 基本日志
print(f"[{self.name}] 消息内容")
# 调试日志
if DEBUG_MODE:
print(f"[{self.name}] 调试: {data}")
# 错误日志
print(f"[{self.name}] ❌ 错误: {error}")
# 成功日志
print(f"[{self.name}] ✅ 成功: {result}")
async def handle(self, message: str, context: ModuleContext) -> Optional[ModuleResponse]:
try:
result = await self.process(message)
return ModuleResponse(content=result)
except Exception as e:
print(f"[{self.name}] ❌ 处理失败: {e}")
if DEBUG_MODE:
import traceback
traceback.print_exc()
return None
在on_load中编译正则,避免重复编译:
async def on_load(self, config: dict) -> None:
await super().on_load(config)
# 编译正则表达式
self.url_pattern = re.compile(r'https?://[^\s]+')
self.keyword_pattern = re.compile(r'关键词1|关键词2', re.IGNORECASE)
YOUR_MODULE_CONFIG = {
"enabled": True, # 是否启用
"priority": 50, # 优先级(越小越高)
"settings": {
# 模块特定配置
"watched_groups": [123456],
"bot_priority": [435438881, 3121201314], # 如需优先级响应
"api_key": "your_key",
# ...
}
}
async def on_load(self, config: dict) -> None:
await super().on_load(config)
settings = config.get('settings', {})
self.watched_groups = settings.get('watched_groups', [])
self.api_key = settings.get('api_key', '')
from config import get_bot_qq_list, get_bot_priority, DEBUG_MODE
# 在on_load中
self.bot_qq_list = get_bot_qq_list()
self.bot_priority = get_bot_priority() # 如需优先级响应
@dataclass
class ModuleContext:
group_id: Optional[int] # 群号,私聊为None
user_id: int # 发送者QQ号
message_id: Optional[int] # 消息ID
self_id: int # 当前机器人QQ号
ws: Any # WebSocket对象
raw_message: str # 原始消息(含CQ码)
extra: Dict[str, Any] # 额外数据
@dataclass
class ModuleResponse:
content: str # 回复内容
auto_recall: bool = False # 是否自动撤回
recall_delay: int = 30 # 撤回延迟(秒)
quoted_msg_id: Optional[int] = None # 引用的消息ID
extra: Dict[str, Any] = field(default_factory=dict)
YOUR_MODULE_CONFIG = {
"enabled": True,
"priority": 50,
"settings": { ... }
}
from config import YOUR_MODULE_CONFIG
# 在lifespan函数中
if YOUR_MODULE_CONFIG.get('enabled', True):
try:
await module_loader.load_module_from_path('modules/your_module', YOUR_MODULE_CONFIG)
print("[系统] 您的模块加载成功")
except Exception as e:
print(f"[系统] 您的模块加载失败: {e}")
提交模块前,请确认:
BaseModulename, version, description属性can_handle()和handle()方法can_handle开头过滤了机器人消息on_load()并正确初始化配置[{self.name}]try-except异常处理config.py中添加了模块配置main.py的lifespan中加载了模块core/base_module.py - 基类定义modules/rebate/module.py - 完整实现,包含优先级响应modules/news_jd/module.py - 数据库交互,API调用modules/news_forwarder/module.py - 后台任务,多账号轮询参考文档中的EchoModule示例,包含所有必需接口的最简实现。
# 错误示例
async def can_handle(self, message: str, context: ModuleContext) -> bool:
return bool(self.pattern.search(message)) # 会导致机器人间循环!
# 正确示例
async def can_handle(self, message: str, context: ModuleContext) -> bool:
if context.user_id in self.bot_qq_list: # 必须先过滤
return False
return bool(self.pattern.search(message))
# 错误示例
if DEBUG_MODE: # NameError: name 'DEBUG_MODE' is not defined
print("debug")
# 正确示例
from config import DEBUG_MODE
if DEBUG_MODE:
print("debug")
# 错误示例
async def handle(self, message: str, context: ModuleContext) -> Optional[ModuleResponse]:
result = await self.api_call(message) # 可能抛出异常
return ModuleResponse(content=result)
# 正确示例
async def handle(self, message: str, context: ModuleContext) -> Optional[ModuleResponse]:
try:
result = await self.api_call(message)
return ModuleResponse(content=result)
except Exception as e:
print(f"[{self.name}] ❌ 处理失败: {e}")
return None
开发新模块时,请严格遵循以下流程:
config.pymain.py中加载模块记住: 机器人消息过滤是强制性的,忘记过滤会导致严重的消息循环问题!