9.8 KiB
9.8 KiB
🔧 插件开发故障排除指南
本指南帮助你快速解决 MoFox-Bot 插件开发中的常见问题。
📋 快速诊断清单
遇到问题时,首先按照以下步骤检查:
- ✅ 检查日志文件
logs/app_*.jsonl - ✅ 确认插件已在
_manifest.json中正确配置 - ✅ 验证你使用的是
PlusCommand而不是BaseCommand - ✅ 检查
execute()方法签名是否正确 - ✅ 确认返回值格式正确
🔴 严重问题:插件无法加载
错误 #1: "未检测到插件"
症状:
- 插件目录存在,但日志中没有加载信息
get_plugin_components()返回空列表
可能原因与解决方案:
❌ 缺少 @register_plugin 装饰器
# 错误 - 缺少装饰器
class MyPlugin(BasePlugin): # 不会被检测到
pass
# 正确 - 添加装饰器
@register_plugin # 必须添加!
class MyPlugin(BasePlugin):
pass
❌ plugin.py 文件不存在或位置错误
plugins/
└── my_plugin/
├── _manifest.json ✅
└── plugin.py ✅ 必须在这里
❌ _manifest.json 格式错误
{
"manifest_version": 1,
"name": "My Plugin",
"version": "1.0.0",
"description": "插件描述",
"author": {
"name": "Your Name"
}
}
错误 #2: "ActionInfo.init() missing required argument: 'component_type'"
症状:
TypeError: ActionInfo.__init__() missing 1 required positional argument: 'component_type'
原因:手动创建 ActionInfo 时未指定 component_type 参数
解决方案:
from src.plugin_system import ActionInfo, ComponentType
# ❌ 错误 - 缺少 component_type
action_info = ActionInfo(
name="my_action",
description="我的动作"
)
# ✅ 正确方法 1 - 使用自动生成(推荐)
class MyAction(BaseAction):
action_name = "my_action"
action_description = "我的动作"
def get_plugin_components(self):
return [
(MyAction.get_action_info(), MyAction) # 自动生成,推荐!
]
# ✅ 正确方法 2 - 手动指定 component_type
action_info = ActionInfo(
name="my_action",
description="我的动作",
component_type=ComponentType.ACTION # 必须指定!
)
🟡 命令问题:命令无响应
错误 #3: 命令被识别但不执行
症状:
- 输入
/mycommand后没有任何反应 - 日志显示命令已匹配但未执行
可能原因与解决方案:
❌ 使用了 BaseCommand 而不是 PlusCommand
# ❌ 错误 - 使用 BaseCommand
from src.plugin_system import BaseCommand
class MyCommand(BaseCommand): # 不推荐!
command_name = "mycommand"
command_pattern = r"^/mycommand$" # 需要手动写正则
async def execute(self): # 签名错误!
pass
# ✅ 正确 - 使用 PlusCommand
from src.plugin_system import PlusCommand, CommandArgs
class MyCommand(PlusCommand): # 推荐!
command_name = "mycommand"
# 不需要 command_pattern,会自动生成!
async def execute(self, args: CommandArgs): # 正确签名
await self.send_text("命令执行成功")
return True, "执行了mycommand", True
❌ execute() 方法签名错误
# ❌ 错误的签名(缺少 args 参数)
async def execute(self) -> Tuple[bool, Optional[str], bool]:
pass
# ❌ 错误的签名(参数类型错误)
async def execute(self, args: list[str]) -> Tuple[bool, Optional[str], bool]:
pass
# ✅ 正确的签名
async def execute(self, args: CommandArgs) -> Tuple[bool, Optional[str], bool]:
await self.send_text("响应用户")
return True, "日志描述", True
错误 #4: 命令发送了消息但用户没收到
症状:
- 日志显示命令执行成功
- 但用户没有收到任何消息
原因:在返回值中返回消息,而不是使用 self.send_text()
解决方案:
# ❌ 错误 - 在返回值中返回消息
async def execute(self, args: CommandArgs):
message = "这是给用户的消息"
return True, message, True # 这不会发送给用户!
# ✅ 正确 - 使用 self.send_text()
async def execute(self, args: CommandArgs):
# 发送消息给用户
await self.send_text("这是给用户的消息")
# 返回日志描述(不是用户消息)
return True, "执行了某个操作", True
错误 #5: "notice处理失败" 或重复消息
症状:
- 日志中出现 "notice处理失败"
- 用户收到重复的消息
原因:同时使用了 send_api.send_text() 和返回消息
解决方案:
# ❌ 错误 - 混用不同的发送方式
from src.plugin_system.apis.chat_api import send_api
async def execute(self, args: CommandArgs):
await send_api.send_text(self.stream_id, "消息1") # 不要这样做
return True, "消息2", True # 也不要返回消息
# ✅ 正确 - 只使用 self.send_text()
async def execute(self, args: CommandArgs):
await self.send_text("这是唯一的消息") # 推荐方式
return True, "日志:执行成功", True # 仅用于日志
🟢 配置问题
错误 #6: 配置警告 "配置中不存在字空间或键"
症状:
获取全局配置 plugins.my_plugin 失败: "配置中不存在字空间或键 'plugins'"
这是正常的吗?
✅ 是的,这是正常行为! 不需要修复。
说明:
- 系统首先尝试从全局配置加载:
config/plugins/my_plugin/config.toml - 如果不存在,会自动回退到插件本地配置:
plugins/my_plugin/config.toml - 这个警告可以安全忽略
如果你想消除警告:
- 在
config/plugins/目录创建你的插件配置目录 - 或者直接忽略 - 使用本地配置完全正常
🔧 返回值问题
错误 #7: 返回值格式错误
Action 返回值 (2个元素):
async def execute(self) -> Tuple[bool, str]:
await self.send_text("消息")
return True, "日志描述" # 2个元素
Command 返回值 (3个元素):
async def execute(self, args: CommandArgs) -> Tuple[bool, Optional[str], bool]:
await self.send_text("消息")
return True, "日志描述", True # 3个元素(增加了拦截标志)
对比表格:
| 组件类型 | 返回值 | 元素说明 |
|---|---|---|
| Action | (bool, str) |
(成功标志, 日志描述) |
| Command | (bool, str, bool) |
(成功标志, 日志描述, 拦截标志) |
🎯 参数解析问题
错误 #8: 无法获取命令参数
症状:
args为空或不包含预期的参数
解决方案:
async def execute(self, args: CommandArgs):
# 检查是否有参数
if args.is_empty():
await self.send_text("❌ 缺少参数\n用法: /command <参数>")
return True, "缺少参数", True
# 获取原始参数字符串
raw_input = args.get_raw()
# 获取解析后的参数列表
arg_list = args.get_args()
# 获取第一个参数
first_arg = args.get_first("默认值")
# 获取指定索引的参数
second_arg = args.get_arg(1, "默认值")
# 检查标志
if args.has_flag("--verbose"):
# 处理 --verbose 模式
pass
# 获取标志的值
output = args.get_flag_value("--output", "default.txt")
📝 类型注解问题
错误 #9: IDE 报类型错误
解决方案:确保使用正确的类型导入
from typing import Tuple, Optional, List, Type
from src.plugin_system import (
BasePlugin,
PlusCommand,
BaseAction,
CommandArgs,
ComponentInfo,
CommandInfo,
ActionInfo,
ComponentType
)
# 正确的类型注解
def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]:
return [
(MyCommand.get_command_info(), MyCommand),
(MyAction.get_action_info(), MyAction)
]
🚀 性能问题
错误 #10: 插件响应缓慢
可能原因:
- 阻塞操作:在
execute()中使用了同步 I/O - 大量数据处理:在主线程处理大文件或复杂计算
- 频繁的数据库查询:每次都查询数据库
解决方案:
import asyncio
async def execute(self, args: CommandArgs):
# ✅ 使用异步操作
result = await some_async_function()
# ✅ 对于同步操作,使用 asyncio.to_thread
result = await asyncio.to_thread(blocking_function)
# ✅ 批量数据库操作
from src.common.database.optimization.batch_scheduler import get_batch_scheduler
scheduler = get_batch_scheduler()
await scheduler.schedule_batch_insert(Model, data_list)
return True, "执行成功", True
📞 获取帮助
如果以上方案都无法解决你的问题:
- 查看日志:检查
logs/app_*.jsonl获取详细错误信息 - 查阅文档:
- 在线文档:https://mofox-studio.github.io/MoFox-Bot-Docs/
- 提交 Issue:在 GitHub 仓库提交详细的问题报告
🎓 最佳实践速查
| 场景 | 推荐做法 | 避免 |
|---|---|---|
| 创建命令 | 使用 PlusCommand |
❌ 使用 BaseCommand |
| 发送消息 | await self.send_text() |
❌ 在返回值中返回消息 |
| 注册组件 | 使用 get_action_info() |
❌ 手动创建不带 component_type 的 Info |
| 参数处理 | 使用 CommandArgs 方法 |
❌ 手动解析字符串 |
| 异步操作 | 使用 async/await |
❌ 使用同步阻塞操作 |
| 配置读取 | self.get_config() |
❌ 硬编码配置值 |
最后更新:2024-12-17
版本:v1.0.0
有问题欢迎反馈,帮助我们改进这份指南!