NEO Bot Framework
📖 概述
NEO 是一个基于 Python 的现代化 OneBot 11 协议机器人框架,专为需要高性能、可扩展性和开发效率的团队设计。该框架通过 WebSocket 与各种 OneBot 实现端(如 NapCatQQ、LLOneBot 等)通信,提供了一套完整的机器人开发解决方案。
设计理念
NEO 框架的设计遵循以下核心理念:
- 开发者友好:简洁的 API 设计、完整的类型提示和详细的文档,让开发者能够快速上手和高效开发
- 架构清晰:采用模块化设计,分离关注点,使代码易于维护和扩展
- 高性能异步:基于
asyncio和websockets构建,支持高并发消息处理 - 类型安全:全面使用 Python 类型系统,提供编译时类型检查,减少运行时错误
- 热重载支持:支持插件热重载,开发过程中修改代码无需重启机器人
核心价值
- 快速原型开发:通过简洁的装饰器语法快速定义指令和事件处理器
- 生产环境就绪:内置断线重连、错误处理和性能监控机制
- 可扩展架构:支持自定义插件、中间件和权限系统
- 现代化开发体验:支持热重载、类型提示和完整的 API 文档
适用场景
- QQ 群机器人管理
- 自动化客服与问答系统
- 游戏社区管理
- 团队内部工具集成
- 教育与培训辅助
✨ 特性
- OneBot 11 标准支持:完整支持 OneBot 11 的消息、通知、请求和元事件。
- 类型安全:基于
dataclasses的强类型事件模型,开发体验更佳。 - 插件系统:轻量级的装饰器风格插件系统,支持指令 (
@matcher.command) 和事件监听 (@matcher.on_notice,@matcher.on_request)。 - 插件元数据与内置帮助:插件可通过
__plugin_meta__变量进行自我描述。框架核心内置了/help指令,可自动收集并展示所有插件的帮助信息,无需手动维护。 - 🔥 热重载支持:内置文件监控,修改
base_plugins下的代码自动重载,无需重启,极大提升调试效率。 - 异步核心:基于
asyncio和websockets的高性能异步核心。 - 自动重连:内置 WebSocket 断线重连机制。
⚡️ 性能优化
Redis 缓存机制
为了提升响应速度并减少对 OneBot API 的重复调用,框架核心集成了一套基于 Redis 的缓存系统。对于一些不频繁变更的数据(如群信息、好友列表等),首次查询后会将其缓存至 Redis,在缓存有效期内(默认为 1 小时),后续请求将直接从 Redis 读取,极大提升了性能。
工作原理
- 自动缓存:框架会自动缓存特定 API 的调用结果。
- 缓存键:缓存键根据 API 名称和关键参数(如
group_id,user_id)生成,确保唯一性。 - 过期时间:默认缓存 1 小时,之后会自动失效,下次调用时将重新从 OneBot 实现端获取最新数据。
受影响的 API
以下核心 API 已默认启用缓存:
get_group_infoget_group_member_infoget_friend_listget_stranger_infoget_login_info
如何绕过缓存
在某些场景下,你可能需要获取实时数据而非缓存数据。为此,所有受缓存影响的 API 方法都增加了一个 no_cache: bool = False 的可选参数。
当你需要强制从服务器获取最新信息时,只需在调用时传入 no_cache=True 即可。
示例:
# 正常调用,会使用缓存
group_info = await bot.get_group_info(group_id=12345)
# 强制获取最新信息,不使用缓存
latest_group_info = await bot.get_group_info(group_id=12345, no_cache=True)
__slots__ 内存优化
框架内的所有数据模型(包括事件、消息段、API 返回对象等)均已启用 __slots__ = True 优化。这可以显著减少每个对象实例的内存占用,特别是在处理大量事件和数据时,能够有效降低机器人的整体内存消耗。
📝 待办事项 (TODO)
API 封装
- 消息相关
delete_msg: 撤回消息get_msg: 获取消息get_forward_msg: 获取合并转发消息send_like: 发送点赞
- 群组管理
set_group_kick: 群组踢人set_group_ban: 群组单人禁言set_group_anonymous_ban: 群组匿名禁言set_group_whole_ban: 群组全员禁言set_group_admin: 群组设置管理员set_group_anonymous: 群组匿名set_group_card: 设置群名片(群备注)set_group_name: 设置群名set_group_leave: 退出群组set_group_special_title: 设置群组专属头衔
- 群组信息
get_group_info: 获取群信息get_group_list: 获取群列表get_group_member_info: 获取群成员信息get_group_member_list: 获取群成员列表get_group_honor_info: 获取群荣誉信息
- 用户相关
get_login_info: 获取登录号信息get_stranger_info: 获取陌生人信息get_friend_list: 获取好友列表
- 请求处理
set_friend_add_request: 处理加好友请求set_group_add_request: 处理加群请求/邀请
- 系统/其他
get_version_info: 获取版本信息get_status: 获取状态can_send_image: 检查是否可以发送图片can_send_record: 检查是否可以发送语音clean_cache: 清理缓存
待实现 API
- Web 凭证类
get_cookiesget_csrf_tokenget_credentials
- 文件/资源信息
get_imageget_recordget_file
- 系统控制
set_restart
- 扩展功能
send_forward_msg: 发送合并转发消息
其他改进
- API 强类型封装: 将 API 返回值从
dict转换为数据模型对象。 - Redis 支持: 集成 Redis 连接池,便于插件复用连接。
- 日志系统优化: 引入更完善的日志记录机制,支持文件输出和日志级别控制。
- 异常处理增强: 增强插件执行过程中的异常捕获,防止单个插件崩溃影响整个 Bot。
- 中间件支持: 添加消息处理中间件,支持在指令执行前/后进行拦截和处理。
- 权限系统: 实现基础的权限管理(如超级管理员、群管理员等)。
📂 项目结构
NEO/
├── plugins/ # 插件目录,新建插件文件即可自动加载(支持热重载)
│ ├── echo.py # 示例插件:实现 /echo 和 /赞我 指令
│ ├── forward_test.py # 示例插件:演示合并转发消息的构建和发送
│ ├── jrcd.py # 娱乐插件:提供 /jrcd 和 /bbcd 指令
│ └── thpic.py # 图片插件:提供 /thpic 指令,发送随机东方图片
├── core/ # 核心框架代码
│ ├── api/ # API 模块抽象层 (MessageAPI, GroupAPI, FriendAPI, AccountAPI)
│ │ ├── __init__.py
│ │ ├── account.py
│ │ ├── base.py
│ │ ├── friend.py
│ │ ├── group.py
│ │ └── message.py
│ ├── bot.py # Bot API 封装,提供 send_group_msg 等方法
│ ├── command_manager.py # 命令与事件分发器
│ ├── config_loader.py # 配置加载器
│ ├── plugin_manager.py # 插件加载与管理
│ ├── redis_manager.py # Redis 连接管理器
│ └── ws.py # WebSocket 客户端核心
├── models/ # 数据模型
│ ├── events/ # OneBot 事件定义 (Message, Notice, Request, Meta)
│ ├── message.py # 消息段定义 (MessageSegment)
│ └── sender.py # 发送者定义 (Sender)
├── config.toml # 配置文件
├── main.py # 启动入口(包含热重载监控)
└── requirements.txt # 项目依赖
🚀 快速开始
1. 环境准备
- Python 3.8+
- OneBot 11 实现端(推荐 NapCatQQ 或 LLOneBot)
2. 安装依赖
pip install -r requirements.txt
3. 配置文件
修改根目录下的 config.toml,配置 WebSocket 连接信息:
[napcat_ws]
uri = "ws://127.0.0.1:30004" # OneBot 实现端的 WebSocket 地址
token = "your_token" # Access Token (如果有)
reconnect_interval = 5 # 断线重连间隔(秒)
[bot]
command = ["/"] # 指令前缀,支持多个,如 ["/", "#"]
4. 运行
python main.py
🛠️ 开发指南
🔥 热重载调试
项目集成了 watchdog 文件监控。在开发过程中,你只需要:
- 保持
main.py运行。 - 修改或新建
base_plugins目录下的.py插件文件。 - 保存文件。
- 控制台会自动提示
[HotReload] 插件重载完成,新的逻辑立即生效。
创建新插件
在 base_plugins 目录下创建一个新的 .py 文件(例如 my_plugin.py),框架会自动加载它。
示例代码
1. 注册消息指令
使用 @matcher.command("指令名") 注册指令。
from core.command_manager import matcher
from core.bot import Bot
from models import MessageEvent
# 注册 /hello 指令
@matcher.command("hello")
async def handle_hello(bot: Bot, event: MessageEvent, args: list[str]):
# args 是去除指令后的参数列表
await event.reply("你好!这里是 NEO Bot。")
2. 监听通知事件
使用 @matcher.on_notice("通知类型") 监听通知。
from core.command_manager import matcher
from core.bot import Bot
from models import GroupIncreaseNoticeEvent
# 监听群成员增加事件
@matcher.on_notice("group_increase")
async def welcome_new_member(bot: Bot, event: GroupIncreaseNoticeEvent):
await bot.send_group_msg(event.group_id, f"欢迎新成员 {event.user_id} 加入!")
3. 监听请求事件
使用 @matcher.on_request("请求类型") 监听请求。
from core.command_manager import matcher
from core.bot import Bot
from models import FriendRequestEvent
# 自动同意好友请求
@matcher.on_request("friend")
async def auto_approve_friend(bot: Bot, event: FriendRequestEvent):
await bot.call_api("set_friend_add_request", {
"flag": event.flag,
"approve": True
})
4. API 调用方式对比
框架提供两种 API 调用方式:类型化 API(推荐)和 通用 API(备用)。
方式一:类型化 API(推荐)
对于已封装的 API,框架提供了类型化的方法,返回数据模型对象而非原始字典:
from core.command_manager import matcher
from core.bot import Bot
from models import MessageEvent
from models.objects import Group
@matcher.command("info")
async def get_group_info_typed(bot: Bot, event: MessageEvent, args: list[str]):
# 使用类型化 API,返回 Group 对象
group: Group = await bot.get_group_info(event.group_id)
await event.reply(f"群名:{group.group_name}\n成员数:{group.member_count}\n创建时间:{group.create_time}")
方式二:通用 API(备用)
如果框架尚未封装某个 OneBot API,你可以使用 bot.call_api 直接调用。这是通用的备用调用方法。
from core.command_manager import matcher
from core.bot import Bot
from models import MessageEvent
@matcher.command("info_legacy")
async def get_group_info_legacy(bot: Bot, event: MessageEvent, args: list[str]):
# 直接调用 get_group_info API
# action: API 名称
# params: API 参数字典
resp = await bot.call_api("get_group_info", {
"group_id": event.group_id,
"no_cache": False
})
if resp.get("status") == "ok":
group_name = resp["data"]["group_name"]
await event.reply(f"当前群名:{group_name}")
建议:优先使用类型化 API,获得更好的类型安全和代码提示。仅在框架未封装特定 API 时使用通用 API。
📖 插件开发指南
插件基本结构
一个标准的插件文件应该包含以下部分:
- 模块文档字符串:描述插件功能
- 导入必要的模块:从
core和models导入所需类 - 使用装饰器注册事件处理器:
@matcher.command(),@matcher.on_notice(),@matcher.on_request() - 异步函数实现业务逻辑:使用
async def定义处理函数
插件元数据 (__plugin_meta__)
为了实现插件的自动发现和帮助信息的自动生成,框架引入了插件元数据机制。你需要在你的插件模块中定义一个名为 __plugin_meta__ 的字典。
load_all_plugins 函数在加载插件时会自动读取这个变量,并将其注册到 CommandManager 中。/help 指令会遍历所有已注册的元数据,生成格式化的帮助信息。
一个标准的 __plugin_meta__ 包含以下字段:
name(str): 插件的友好名称,例如 "回声"。description(str): 对插件功能的简短描述。usage(str): 插件的使用方法,可以包含多个指令和它们的说明。
示例:
# base_plugins/echo.py
__plugin_meta__ = {
"name": "回声与交互",
"description": "提供 echo 和 赞我 功能",
"usage": "/echo [内容] - 复读内容\n/赞我 - 让机器人给你点赞",
}
使用类型化 API
框架现已提供完整的类型化 API 封装,建议优先使用这些封装方法而非原始的 call_api:
| API 方法 | 返回类型 | 说明 |
|---|---|---|
bot.send_group_msg() |
Message |
发送群消息 |
bot.get_group_info() |
Group |
获取群信息 |
bot.get_group_member_info() |
GroupMember |
获取群成员信息 |
bot.get_friend_list() |
List[Friend] |
获取好友列表 |
bot.get_login_info() |
LoginInfo |
获取登录信息 |
bot.get_version_info() |
VersionInfo |
获取版本信息 |
示例:使用类型化 API 重构群信息查询
from core.command_manager import matcher
from core.bot import Bot
from models import MessageEvent
from models.objects import Group
@matcher.command("group_info")
async def get_group_info_typed(bot: Bot, event: MessageEvent, args: list[str]):
# 使用类型化 API,返回 Group 对象而非字典
group: Group = await bot.get_group_info(event.group_id)
await event.reply(f"群名:{group.group_name}\n成员数:{group.member_count}\n创建时间:{group.create_time}")
事件处理模式
除了基本的消息指令,还可以处理多种事件类型:
1. 通知事件处理
from models import GroupCardChangeEvent
@matcher.on_notice("group_card")
async def handle_group_card_change(bot: Bot, event: GroupCardChangeEvent):
# event.card_new 是新名片,event.card_old 是旧名片
await bot.send_group_msg(event.group_id, f"成员 {event.user_id} 的名片从 '{event.card_old}' 改为 '{event.card_new}'")
2. 请求事件处理
from models import GroupRequestEvent
@matcher.on_request("group")
async def handle_group_request(bot: Bot, event: GroupRequestEvent):
# 根据请求类型处理
if event.sub_type == "add":
# 自动同意加群请求
await bot.set_group_add_request(event.flag, event.sub_type, approve=True)
await bot.send_group_msg(event.group_id, f"已同意用户 {event.user_id} 的加群请求")
错误处理
建议在插件中添加适当的错误处理,避免单个插件崩溃影响整个机器人:
@matcher.command("dangerous")
async def dangerous_command(bot: Bot, event: MessageEvent, args: list[str]):
try:
# 可能失败的操作
result = await bot.call_api("some_api", {"param": "value"})
await event.reply(f"成功:{result}")
except Exception as e:
await event.reply(f"执行失败:{str(e)}")
# 记录日志
import logging
logging.error(f"插件执行错误:{e}", exc_info=True)
插件开发最佳实践
- 单一职责:每个插件专注于一个功能领域
- 错误处理:妥善处理可能发生的异常
- 类型提示:为函数参数和返回值添加类型提示
- 文档完整:为每个函数添加文档字符串
- 性能考虑:避免在插件中执行耗时同步操作
- 资源清理:必要时使用
try...finally确保资源释放
🚀 高性能插件开发规范 (避坑指南)
为了保证整个机器人框架的响应速度和稳定性,所有插件都必须遵循异步、非阻塞的开发原则。任何一个插件中的阻塞操作都可能导致整个机器人卡顿或无响应。
以下是必须遵守的核心规范:
1. 禁止任何形式的同步网络请求
- 错误示范: 使用
requests库发起网络请求。import requests # 错误!这会阻塞整个程序 response = requests.get("https://api.example.com") - 正确做法: 必须使用异步 HTTP 客户端,如
aiohttp或httpx。import httpx # 正确,使用 async with 和 await async with httpx.AsyncClient() as client: response = await client.get("https://api.example.com")
2. 禁止使用 time.sleep()
- 错误示范: 使用
time.sleep()进行等待。import time # 错误!这会阻塞事件循环 time.sleep(5) - 正确做法: 必须使用
asyncio.sleep()。import asyncio # 正确,这会将控制权交还给事件循环 await asyncio.sleep(5)
3. 谨慎处理文件 I/O
- 对于读写小型、本地文件,直接使用
with open(...)通常是可接受的。 - 但对于大型文件或网络文件系统(NFS)上的文件,同步 I/O 可能会导致明显的阻塞。
- 推荐做法: 对于可能耗时较长的文件操作,使用
aiofiles库。import aiofiles async with aiofiles.open('large_file.dat', mode='rb') as f: contents = await f.read()
4. 将 CPU 密集型任务移出事件循环
- 如果插件需要执行复杂的计算(例如,图像处理、视频转码、数据分析),这些任务会长时间占用 CPU,同样会阻塞事件循环。
- 正确做法: 使用
loop.run_in_executor()将这类任务抛到独立的线程池或进程池中执行。import asyncio def cpu_bound_task(data): # 这是一个耗时的同步函数 # ... 进行大量计算 ... return "计算结果" # 在异步的事件处理器中调用 loop = asyncio.get_running_loop() # `None` 表示使用默认的线程池 result = await loop.run_in_executor(None, cpu_bound_task, "一些数据") await event.reply(result)
遵循以上规范,可以确保您开发的插件不会成为整个机器人应用的性能瓶颈。
示例:完整插件模板
"""
天气查询插件
提供 /weather 指令,查询指定城市的天气信息。
"""
from core.command_manager import matcher
from core.bot import Bot
from models import MessageEvent
# 插件元数据,用于 help 指令
__plugin_meta__ = {
"name": "天气查询",
"description": "查询指定城市的天气信息",
"usage": "/weather [城市名称]",
}
@matcher.command("weather")
async def handle_weather(bot: Bot, event: MessageEvent, args: list[str]):
"""
查询天气信息
:param bot: Bot 实例
:param event: 消息事件对象
:param args: 指令参数列表(城市名称)
"""
if not args:
await event.reply("请输入城市名称,例如:/weather 北京")
return
city = " ".join(args)
try:
# 这里可以调用天气 API
weather_info = f"{city} 的天气:晴,25℃"
await event.reply(weather_info)
except Exception as e:
await event.reply(f"查询天气失败:{str(e)}")
# 可以注册多个事件处理器
@matcher.on_notice("group_increase")
async def welcome_new_member(bot: Bot, event):
await bot.send_group_msg(event.group_id, f"欢迎新成员 {event.user_id} 加入!")
📚 事件模型说明
项目采用了基于工厂模式的事件处理系统,所有事件定义在 models/events/ 下:
- MessageEvent: 消息事件,包含
PrivateMessageEvent和GroupMessageEvent。支持await event.reply()快速回复。 - NoticeEvent: 通知事件,如
FriendAddNoticeEvent,GroupRecallNoticeEvent等。 - RequestEvent: 请求事件,如
FriendRequestEvent,GroupRequestEvent。 - MetaEvent: 元事件,如心跳
HeartbeatEvent。
所有事件均继承自 OneBotEvent,并包含 bot 属性用于调用 API。
🏗️ 技术架构
NEO 框架采用分层架构设计,各层职责明确,便于维护和扩展:
架构层次
-
通信层 (WebSocket Client)
- 负责与 OneBot 实现端的 Web Socket连接
- 实现断线自动重连机制
- 处理原始消息的收发和协议解析
-
API 抽象层 (API Mixins)
- 提供类型安全的 API 封装
- 按功能领域划分:消息、群组、好友、账号
- 所有 API 返回强类型数据模型对象
-
业务逻辑层 (Bot & Command Manager)
- Bot 类组合所有 API 功能
- 指令和事件分发器
- 插件加载和管理
-
插件层 (Plugins)
- 支持热重载的插件系统
- 装饰器风格的注册方式
- 独立的业务逻辑模块
-
数据模型层 (Models)
- 基于 dataclasses 的事件模型
- API 响应数据模型
- 类型安全的序列化/反序列化
核心组件交互
┌─────────────────────────────────────┐
│ 插件层 (Plugins) │
│ @matcher.command() │
│ @matcher.on_notice() │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ 业务逻辑层 (Command Manager) │
│ • 事件分发与路由 │
│ • 指令参数解析 │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ Bot 组合类 │
│ • 继承所有 API Mixin │
│ • 提供统一接口 │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ API 抽象层 (Mixin) │
│ • MessageAPI │
│ • GroupAPI │
│ • FriendAPI │
│ • AccountAPI │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ 通信层 (WebSocket) │
│ • 连接管理 │
│ • 消息编解码 │
│ • 断线重连 │
└─────────────────────────────────────┘
设计模式应用
- 工厂模式:事件对象的创建和管理
- 装饰器模式:插件和指令的注册
- 组合模式:Bot 类通过继承组合 API 功能
- 观察者模式:事件监听和处理
- 策略模式:不同的消息处理策略
性能特点
- 异步非阻塞:全面基于 asyncio,支持高并发
- 内存高效:事件和模型对象使用 dataclasses,内存占用小
- 快速响应:插件热重载和事件分发机制确保快速响应
- 可扩展性:模块化设计便于功能扩展和定制
Internal Use Only - DOGSOHA ond baby2016 by Fairy-Oracle-Sanctuary