☰
NoneBot2 适配器(Adapter)完全指南:注册、获取 Bot 与事件通用信息
2026/9/27 8:45:02 网站建设 项目流程
  • 后端
  • 即时通讯

【免费下载链接】nonebot2

跨平台 Python 异步聊天机器人框架 / Asynchronous multi-platform chatbot framework written in Python

项目地址:https://gitcode.com/gh_mirrors/no/nonebot2
点击查看免费下载

适配器(Adapter)是 NoneBot2 机器人与平台交互的核心桥梁,负责在驱动器和机器人插件之间转换与传递消息。本文以 NoneBot2 官方文档"使用适配器"为主线,系统讲解适配器的功能组成、注册方式、获取已注册适配器与 Bot 对象的方法,以及事件通用信息的获取接口,并结合本仓库源码(nonebot/__init__.py、nonebot/internal/adapter/、nonebot/internal/driver/abstract.py等)剖析底层实现,帮助你真正理解并熟练使用适配器 API。

适配器功能与组成

适配器在 NoneBot2 中承担两种核心功能:

  • 接收事件:将驱动器收到的来自平台的事件消息,转换为 NoneBot 定义的事件模型,然后交由机器人插件处理;
  • 调用平台接口:将机器人插件调用平台接口的数据转换为平台指定的格式,交由驱动器发送,并接收接口返回数据。

为了实现这两种功能,一个完整的适配器通常由四个部分组成:

  • Adapter:负责转换事件和调用接口,正确创建 Bot 对象并注册到 NoneBot 中;
  • Bot:负责存储平台机器人相关信息,并提供回复事件的方法;
  • Event:负责定义事件内容,以及事件主体对象;
  • Message:负责正确序列化消息,以便机器人插件处理。

从源码结构看,NoneBot2 在 nonebot/internal/adapter/init.py 中导出了Adapter、Bot、Event、Message、MessageSegment、MessageTemplate六个基类,并在 nonebot/adapters/init.py 中作为nonebot.adapters模块的公共接口对外提供。所有具体平台的适配器(如 OneBot、Console、Telegram 等)都是继承这些基类实现的,它们均定义在nonebot/adapters/{adapter-name}命名空间包中,并注册到nonebot.adapters模块之下。

注册适配器

在使用适配器之前,需要先将适配器注册到驱动器中,这样适配器才能通过驱动器接收事件和调用接口。以 Console 适配器为例,注册过程如下(bot.py):

import nonebot from nonebot.adapters.console import Adapter driver = nonebot.get_driver() driver.register_adapter(Adapter)

首先从适配器模块中导入所需的适配器类,然后通过驱动器的register_adapter方法将适配器注册到驱动器中。如果需要多平台支持,可以多次调用register_adapter方法注册多个适配器,例如:

import nonebot from nonebot.adapters.console import Adapter from nonebot.adapters.onebot.v11 import Adapter as OneBotV11Adapter driver = nonebot.get_driver() driver.register_adapter(Adapter) driver.register_adapter(OneBotV11Adapter)

底层实现:register_adapter 做了什么

从 nonebot/internal/driver/abstract.py 的源码可以看到,Driver.register_adapter的核心逻辑为:

  • 通过adapter.get_name()获取适配器名称(由适配器类的get_name类方法返回);
  • 若同名适配器已注册,则打印 debug 日志并直接返回(幂等);
  • 否则实例化适配器:self._adapters[name] = adapter(self, **kwargs),存入驱动器的类变量_adapters字典中。

其中get_name是 nonebot/internal/adapter/adapter.py 中定义的抽象类方法,每个适配器必须实现并返回自己的唯一名称(通常形如"Console"、"OneBot V11")。另外,register_adapter还接受**kwargs额外参数,这些参数会原样传递给适配器的构造函数__init__(self, driver, **kwargs)。

注意:driver对象需要通过nonebot.get_driver()获取,该函数定义于 nonebot/init.py,它返回全局唯一的Driver实例;如果nonebot.init()尚未被调用,它会抛出ValueError: NoneBot has not been initialized.。因此register_adapter调用必须发生在nonebot.init()之后。

获取已注册的适配器

NoneBot2 提供了get_adapter方法来获取已注册的适配器,可以通过适配器的名称或类型来获取指定的适配器实例:

import nonebot from nonebot.adapters.console import Adapter adapters = nonebot.get_adapters() console_adapter = nonebot.get_adapter(Adapter) console_adapter = nonebot.get_adapter(Adapter.get_name())
  • nonebot.get_adapters():返回所有已注册适配器实例的字典,键为适配器名称;
  • nonebot.get_adapter(Adapter):按适配器类型获取实例;
  • nonebot.get_adapter(Adapter.get_name()):按适配器名称(字符串)获取实例。

底层实现与异常行为

从 nonebot/init.py 的源码看,get_adapter定义了两个重载:接受str名称或type[A]类型。内部实现为:

adapters = get_adapters() target = name if isinstance(name, str) else name.get_name() if target not in adapters: raise ValueError(f"Adapter {target} not registered.") return adapters[target]

即:若传入类型,则先调用其get_name()转成名称再查找;若目标适配器未注册,会抛出ValueError: Adapter {target} not registered.。而get_adapters()返回的是get_driver()._adapters.copy(),即驱动器内部注册表的一份拷贝,避免外部直接修改内部状态。

这一行为在仓库的测试 tests/test_init.py 中也有验证:test_get_adapter断言了get_adapters()返回的字典内容、按名称与按类型两种方式都能取到同一个实例,以及查询不存在的适配器会抛出异常。

获取 Bot 对象

当前所有适配器已连接的 Bot 对象可以通过get_bots方法获取,这是一个以机器人 ID 为键的字典:

import nonebot bots = nonebot.get_bots()

也可以通过get_bot方法获取指定 ID 的 Bot 对象。如果省略 ID 参数,将返回所有 Bot 中的第一个:

import nonebot bot = nonebot.get_bot("bot_id")

如果需要获取指定适配器连接的 Bot 对象,可以通过适配器的bots属性获取,这也是一个以机器人 ID 为键的字典:

import nonebot from nonebot.adapters.console import Adapter console_adapter = nonebot.get_adapter(Adapter) bots = console_adapter.bots

Bot 对象都具有一个self_id属性,它是机器人的唯一 ID,由适配器填写,通常为机器人的账号 ID 或者 APP ID。

底层实现:Bot 的注册与生命周期

  • nonebot.get_bots()定义于 nonebot/init.py,返回get_driver().bots,即驱动器中的_bots字典(见 nonebot/internal/driver/abstract.py 的bots属性);
  • nonebot.get_bot(self_id)定义于 nonebot/init.py:传入self_id时等价于get_bots()[self_id],未找到会抛出KeyError;不传时返回字典中第一个 Bot,若没有任何可用 Bot 则抛出ValueError: There are no bots to get.;
  • 适配器的bots属性定义于 nonebot/internal/adapter/adapter.py,在Adapter.__init__中被初始化为空字典。

Bot 连接建立与断开时,适配器会调用bot_connect/bot_disconnect(见 nonebot/internal/adapter/adapter.py):前者将 Bot 写入适配器自身的bots字典,并调用driver._bot_connect(bot)注册到驱动器;后者则从两个字典中移除。驱动器侧 nonebot/internal/driver/abstract.py 的_bot_connect/_bot_disconnect还会触发由Driver.on_bot_connect/Driver.on_bot_disconnect装饰器注册的连接钩子函数,因此你可以在 Bot 上下线时执行自定义逻辑。

Bot 基类(nonebot/internal/adapter/bot.py)的__init__接收adapter与self_id两个参数,其中self_id即机器人唯一 ID;同时提供type属性(返回所属适配器名称)、config属性(全局配置)、call_api方法与send抽象方法用于调用平台接口与回复消息。测试 tests/test_init.py 的test_get_bot覆盖了get_bot()无参、get_bot("test")指定 ID 以及get_bots()三种调用场景。

获取事件通用信息

适配器的所有事件模型均继承自Event基类(nonebot/internal/adapter/event.py)。在事件类型与重载一节中,也提到了如何使用基类抽象方法来获取事件通用信息。基类能提供如下信息:

事件类型

事件类型通常为meta_event、message、notice、request,可通过get_type()获取:

type: str = event.get_type()

事件名称

事件名称由适配器定义,通常用于日志记录:

name: str = event.get_event_name()

事件描述

事件描述由适配器定义,通常用于日志记录:

description: str = event.get_event_description()

事件日志字符串

事件日志字符串由事件名称和事件描述组成,用于日志记录。其默认实现(见 nonebot/internal/adapter/event.py)为[{event_name}]: {event_description},通常无需修改;若希望 NoneBot 隐藏该事件日志,可以抛出NoLogException异常:

log: str = event.get_log_string()

事件主体 ID

事件主体 ID 通常为机器人用户 ID:

user_id: str = event.get_user_id()

事件会话 ID

事件会话 ID 通常为机器人用户 ID 与群聊/频道 ID 组合而成,用于判断当前事件属于哪一个会话:

session_id: str = event.get_session_id()

事件消息

如果事件包含消息,则可以通过get_message()获取,否则会产生异常。返回值为该适配器定义的Message类型:

message: Message = event.get_message()

事件纯文本消息

通常为事件消息的纯文本内容,如果事件不包含消息则会产生异常。基类默认实现为get_message().extract_plain_text(),即过滤出所有纯文本消息段并拼接(见 nonebot/internal/adapter/message.py):

text: str = event.get_plaintext()

事件是否与机器人有关

由适配器实现的判断,通常将事件目标主体为机器人、消息中包含"@机器人"或以"机器人的昵称"开始视为与机器人有关:

is_tome: bool = event.is_tome()

底层实现要点

上述方法中,get_type、get_event_name、get_event_description、get_user_id、get_session_id、get_message、is_tome均为Event基类中的抽象方法(@abc.abstractmethod),必须由各平台适配器的事件模型实现;而get_log_string与get_plaintext在基类中提供了默认实现,适配器通常无需覆写。此外,Event基类还基于 pydantic 定义了model_config = ConfigDict(extra="allow"),允许事件模型携带平台上报的额外字段,便于插件直接通过事件属性访问扩展信息。

更进一步:了解事件在适配器中的流转

结合适配器开发文档可以更完整地理解上述 API 在整个框架中的位置:

  • 适配器通过setup_http_server、setup_websocket_server(需驱动器支持 ASGI)注册平台回调路由,或通过request、websocket(需驱动器支持客户端)主动连接平台,将收到的原始数据解析为Event对象后交给 NoneBot 的事件分发机制;
  • 插件处理事件后,通过bot.call_api(api, **data)或直接以属性形式调用(如await bot.send_msg(message="hello world"),由Bot.__getattr__实现,见 nonebot/internal/adapter/bot.py),最终由适配器实现的抽象方法_call_api(nonebot/internal/adapter/adapter.py)转换为平台指定的数据格式,经驱动器发送;
  • 如需在调用 API 前后插入自定义逻辑,可使用Bot.on_calling_api与Bot.on_called_api钩子。

更多

官方支持的适配器和社区贡献的适配器均可在商店(商店数据源见 assets/adapters.json5)中查看。如果你想要开发自己的适配器,可以参考开发文档(也可使用nb adapter create脚手架快速创建适配器项目),欢迎通过商店发布你的适配器。

  • 后端
  • 即时通讯

【免费下载链接】nonebot2

跨平台 Python 异步聊天机器人框架 / Asynchronous multi-platform chatbot framework written in Python

项目地址:https://gitcode.com/gh_mirrors/no/nonebot2
点击查看免费下载

相关推荐

上一篇:深度解析ResNet-50 v1.5架构:为什么它比原始版本更准确?
下一篇:在 Windows 上为 graphify 技能引导正确的 Python 解释器:PowerShell 安装片段剖析与 skillgen 渲染机制

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询