☰
NoneBot2 响应规则(Rule)深度指南:从 RuleChecker 组合到内置规则实战
2026/9/28 7:59:07 网站建设 项目流程
  • 后端
  • 即时通讯

【免费下载链接】nonebot2

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

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

导读

在 NoneBot2 中,机器人会接收到来自各种适配器(QQ、微信、Telegram、Discord 等)的多种事件,而响应规则(Rule)正是控制“哪些事件应该被哪个事件响应器处理”的核心机制。本指南以 NoneBot2 官方文档《响应规则》为骨架,结合 nonebot/internal/rule.py 与 nonebot/rule.py 的源码实现,系统讲解RuleChecker依赖注入、Rule并发检查原理、&运算符合并规则、主动调用规则判定事件,以及全部内置响应规则的用法。读完本文,你将能编写插件级开关规则、黑名单规则,并熟练组合出符合业务需求的响应条件。

响应规则的作用:为事件处理把关

机器人在实际应用中,往往会接收到多种多样的事件类型:普通消息、群成员变动、加好友请求、元事件等。NoneBot 通过响应规则来控制事件的处理——只有通过规则检查的事件,才会交给对应的事件响应器(Matcher)执行后续逻辑。

在指南中,我们为weather命令添加了一个rule=to_me()参数,这个参数就是一个响应规则,确保只有在私聊或者@bot时才会响应。这就是响应规则最典型的应用场景:把“该事件是否与我相关”这类判断从业务逻辑中抽离出来,交给框架在事件分发阶段统一完成。

从源码结构看,每个事件响应器都拥有一个Rule对象,事件传递时会先经过规则检查再运行处理函数(参见 nonebot/internal/rule.py 中Rule的类文档)。响应规则是一个Rule对象,它由一系列的RuleChecker函数组成,每个RuleChecker函数都会检查事件是否符合条件,如果所有的检查都通过,则事件会被处理。

RuleChecker:可依赖注入的判定函数

RuleChecker是一个返回值为bool类型的依赖函数,即RuleChecker支持依赖注入。在 nonebot/typing.py 中,其类型别名定义为_DependentCallable[bool],文档明确说明“RuleChecker 即判断是否响应事件的处理函数”,且支持依赖参数。

这意味着我们可以直接在RuleChecker的参数列表中声明Bot、Event、State,甚至声明其他依赖(如Depend)和配置项。框架会像处理事件处理函数一样,对RuleChecker进行依赖解析后再调用。

我们可以根据配置项在weather插件目录中编写一个响应规则:

from nonebot import get_plugin_config from .config import Config plugin_config = get_plugin_config(Config) async def is_enable() -> bool: return plugin_config.weather_plugin_enabled weather = on_command("天气", rule=is_enable)

在上面的代码中,我们定义了一个函数is_enable,它会检查配置项weather_plugin_enabled是否为True。这个函数is_enable即为一个RuleChecker。这里传入rule=的参数既可以是一个Rule对象,也可以直接是一个RuleChecker函数——从 nonebot/internal/rule.py 可以看到,Rule.__init__会对传入的每个 checker 做归一化处理:如果传入的是Dependent实例则直接使用,否则调用Dependent[bool].parse(call=checker, allow_types=...)将其解析为依赖对象,并存入self.checkers集合中。

得益于依赖注入,RuleChecker还可以声明事件参数,例如检查用户是否在某个黑名单中:

from nonebot.adapters import Event BLACKLIST: set[str] = set() async def is_blacklisted(event: Event) -> bool: return event.get_user_id() not in BLACKLIST

RuleChecker支持的所有依赖参数类型在源码中有明确约束:Rule.HANDLER_PARAM_TYPES声明了DependParam、BotParam、EventParam、StateParam、DefaultParam五种(见 nonebot/internal/rule.py),与事件处理函数的依赖参数范围一致。

Rule:多个 RuleChecker 的并发集合

Rule是若干个RuleChecker的集合,它会并发调用每个RuleChecker,只有当所有RuleChecker检查通过时匹配成功。例如:我们可以组合两个RuleChecker,一个用于检查插件是否启用,一个用于检查用户是否在黑名单中:

from nonebot.rule import Rule from nonebot.adapters import Event async def is_enable() -> bool: return plugin_config.weather_plugin_enabled async def is_blacklisted(event: Event) -> bool: return event.get_user_id() not in BLACKLIST rule = Rule(is_enable, is_blacklisted) weather = on_command("天气", rule=rule)

并发检查的底层实现

“并发调用每个RuleChecker”并非泛泛而谈,源码实现位于 nonebot/internal/rule.py 的Rule.__call__:

  • 当self.checkers为空时直接返回True(空规则恒匹配);
  • 使用anyio.create_task_group()创建任务组,通过tg.start_soon(_run_checker, checker)为每个 checker 启动一个并发任务;
  • 每个_run_checker将检查结果与最终结果做result &= is_passed累加,先计算再累加以避免数据竞争;
  • 若某个 checker 抛出SkippedException(被catch捕获),则整体结果置为False,即“跳过”同样视为未通过。

因此,Rule的语义是严格的AND(与):任意一个 checker 返回False或抛出SkippedException,整个规则就不通过。测试用例 tests/test_rule.py 对此有直接验证:await Rule(truthy, falsy)(bot, event, {}) is False、await Rule(truthy, skipped)(bot, event, {}) is False。

空 Rule 的行为

从上述实现可以推断:Rule()不包含任何 checker,__call__直接返回True,即不附加任何约束。这在动态构建规则链时很实用,例如根据配置条件决定是否追加额外的 checker。

合并响应规则:&运算符与 None 忽略

在定义响应规则时,我们可以将规则进行细分,来更好地复用规则。而在使用时,我们需要合并多个规则。除了使用Rule对象来组合多个RuleChecker外,我们还可以对Rule对象进行合并。在原weather插件中,我们可以将rule=to_me()与rule=is_enable使用&运算符合并:

from nonebot.rule import to_me from nonebot import get_plugin_config from .config import Config plugin_config = get_plugin_config(Config) async def is_enable() -> bool: return plugin_config.weather_plugin_enabled weather = on_command( "天气", rule=to_me() & is_enable, aliases={"weather", "查天气"}, priority=plugin_config.weather_command_priority, block=True, )

这样,weather命令就只会在插件启用且在私聊或者@bot时才会响应。注意to_me() & is_enable中&左侧是Rule对象、右侧是普通函数,这种混合合并是允许的。

支持的所有合并形式

合并响应规则可以有多种形式,例如:

rule1 = Rule(foo_checker) rule2 = Rule(bar_checker) rule = rule1 & rule2 rule = rule1 & bar_checker rule = foo_checker & rule2

源码中的__and__与__rand__(见 nonebot/internal/rule.py)保证了这些写法全部合法:

  • Rule & Rule:把两个规则的 checker 集合合并成新Rule;
  • Rule & RuleChecker:把单个 checker 追加进原规则;
  • RuleChecker & Rule:通过__rand__将 checker 置于规则之前;
  • 合并操作不会修改原Rule对象,而是返回新的Rule(因为checkers是新建的 set)。

合并 None 值的安全保证

同时,我们也无需担心合并了一个None值,Rule会忽略None值:

assert (rule & None) is rule

__and__与__rand__的第一分支就是if other is None: return self——注意这里返回的是原对象本身,因此不仅是语义上忽略,连对象引用都保持不变,assert成立。测试用例 tests/test_rule.py 也覆盖了Rule(truthy) & None、None & Rule(truthy)、Rule(truthy) & falsy、truthy & Rule(falsy)四种组合。这一设计在“按配置项条件性追加规则”的场景中非常顺手:

rule = to_me() if plugin_config.enable_blacklist: rule = rule & is_not_blacklisted

无需担心if分支外的规则变量为None导致崩溃。

注意:Rule只支持&(AND)合并,源码中__or__被显式定义为直接抛出RuntimeError("Or operation between rules is not allowed."),即不存在|或运算,请勿混用。

主动使用响应规则:程序化判定事件

除了在事件响应器中使用响应规则外,我们也可以主动使用响应规则来判断事件是否符合条件。例如:

rule = Rule(some_checker) result: bool = await rule(bot, event, state)

我们只需要传入Bot对象、事件和会话状态,Rule会并发调用所有RuleChecker进行检查,并返回结果。

从 nonebot/internal/rule.py 的签名看,Rule.__call__的完整参数为(bot, event, state, stack=None, dependency_cache=None)。其中stack(异步上下文栈)与dependency_cache(依赖缓存)为可选参数,在事件响应器内部调用时由框架自动注入;手动调用时通常只需提供前三个参数。这种方式非常适合在自定义分发逻辑、消息预处理管道或二次开发框架能力时复用现成的规则。

内置响应规则:开箱即用的规则库

NoneBot 内置了一些常用的响应规则,可以直接通过事件响应器辅助函数或者自行合并其他规则使用。内置响应规则列表可以参考事件响应器进阶。

全部内置规则定义在 nonebot/rule.py 中,每个规则都同时提供规则类(如CommandRule)与工厂函数(如command(...)),工厂函数返回Rule对象。下面分类展开:

命令类规则

command(*cmds, force_whitespace=None)—— 根据全局配置command_start(命令起始符,默认/)与command_sep(命令分隔符,默认.)判断消息是否为命令,对应实现CommandRule(nonebot/rule.py):

# 匹配 "/test" 开头的消息 rule = command("test") # 匹配 "/test.sub" 开头的消息 rule = command("test", "sub") # force_whitespace=True 时,命令后必须有空白才匹配(如 "/test xxx") rule = command("test", force_whitespace=True)
  • 命令内容与后续消息之间无需空格;
  • 可通过Command()、RawCommand()、CommandArg()参数在处理器中获取匹配到的命令元组、原始命令文本和参数部分;
  • 底层还会向TrieRule前缀树注册命令前缀,用于消息的快速预匹配(见 nonebot/rule.py),注册重复前缀时会输出Duplicated prefix rule警告。

shell_command(*cmds, parser=None)—— shell 风格的命令匹配,支持用ArgumentParser解析参数,对应ShellCommandRule(nonebot/rule.py):

from nonebot.rule import ArgumentParser parser = ArgumentParser() parser.add_argument("-a", action="store_true") rule = shell_command("ls", parser=parser)
  • 解析前可通过ShellCommandArgv()获取原始参数列表,解析后通过ShellCommandArgs()获取参数字典;
  • 若参数解析失败,ShellCommandArgs()返回的将是ParserExit异常对象;
  • parser必须是nonebot.rule.ArgumentParser实例,否则抛出TypeError。

消息文本类规则

startswith(msg, ignorecase=False)/endswith(msg, ignorecase=False)—— 匹配消息纯文本的开头 / 结尾(nonebot/rule.py):

rule = startswith("今天", ignorecase=True) rule = endswith(("吗", "呢"))

匹配成功后,匹配到的字符串会被写入state(键分别为_prefix、_suffix对应的常量)。

fullmatch(msg, ignorecase=False)—— 消息纯文本与指定内容完全一致才匹配(nonebot/rule.py):

rule = fullmatch("签到")

ignorecase=True时使用str.casefold()做大小写无关比较。

keyword(*keywords)—— 消息纯文本包含任意指定关键词即匹配(nonebot/rule.py):

rule = keyword("天气", "气象")

按关键词在文本中出现的顺序取第一个命中写入state。

regex(regex, flags=0)—— 用正则表达式匹配消息字符串(注意是str(EventMessage)而非纯文本,nonebot/rule.py):

rule = regex(r"^天气(\d+)$", flags=re.I)
  • 使用re.search而非re.match,如需从头匹配请用r"^xxx";
  • 可通过RegexStr()、RegexGroup()、RegexDict()获取匹配字符串、分组元组与分组字典。

事件类规则

to_me()—— 匹配与机器人有关的事件(私聊或@bot),对应ToMeRule(nonebot/rule.py)。它内部通过EventToMe()参数判断,是文档示例中最常用的规则之一。

is_type(*types)—— 检查事件是否为指定类型,对应IsTypeRule(nonebot/rule.py):

from nonebot.adapters.onebot.v11 import GroupMessageEvent, PrivateMessageEvent rule = is_type(GroupMessageEvent, PrivateMessageEvent)

事件响应器辅助函数

多数内置规则都有对应的on_*快捷注册函数(定义于 nonebot/plugin/on.py),每个函数都接受可选的rule参数用于追加额外规则:

辅助函数对应规则说明
on_command(cmd, aliases=None, force_whitespace=None)command命令触发(nonebot/plugin/on.py)
on_shell_command(cmd, aliases=None, parser=None)shell_commandshell 风格命令触发(nonebot/plugin/on.py)
on_startswith(msg, ignorecase=False)startswith文本开头触发(nonebot/plugin/on.py)
on_endswith(msg, ignorecase=False)endswith文本结尾触发(nonebot/plugin/on.py)
on_fullmatch(msg, ignorecase=False)fullmatch文本全匹配触发(nonebot/plugin/on.py)
on_keyword(keywords)keyword关键词触发(nonebot/plugin/on.py)
on_regex(pattern, flags=0)regex正则触发(nonebot/plugin/on.py)
on_message()/on_notice()/on_request()/on_metaevent()is_type等按事件类型触发

例如:

from nonebot import on_command weather = on_command( "天气", aliases={"weather", "查天气"}, rule=to_me(), priority=10, block=True, )

这里的rule=参数即可接收Rule对象或单个RuleChecker,且可以与&合并的结果配合使用。

实战示例:插件开关 + 黑名单 + 私聊限定

将本文所有知识点串起来,一个完整的 weather 插件响应规则定义如下:

from nonebot import get_plugin_config, on_command from nonebot.adapters import Event from nonebot.rule import Rule, to_me from .config import Config plugin_config = get_plugin_config(Config) BLACKLIST = {"10001", "10002"} async def is_enable() -> bool: # 插件开关,来自插件配置项 return plugin_config.weather_plugin_enabled async def is_not_blacklisted(event: Event) -> bool: # 黑名单检查,来自事件依赖注入 return event.get_user_id() not in BLACKLIST # 组合三个 RuleChecker:插件启用、不在黑名单、私聊或 @bot weather = on_command( "天气", rule=Rule(is_enable, is_not_blacklisted) & to_me(), aliases={"weather", "查天气"}, priority=plugin_config.weather_command_priority, block=True, )

规则检查会在事件分发阶段并发执行:任一条件不满足(插件未启用、用户在黑名单、既非私聊也未被 @)都会导致该事件不进入weather的处理流程。这正体现了响应规则的设计意图——把“是否响应”的决定权从业务代码中彻底剥离,以声明式、可组合、可复用的方式表达。

小结

  • RuleChecker是支持依赖注入的bool判定函数,可声明Bot、Event、State等依赖参数;
  • Rule是RuleChecker的集合,通过anyio任务组并发执行并做 AND 累加,任一失败(含SkippedException)即整体不通过;
  • 使用&运算符合并规则,支持Rule & Rule、Rule & checker、checker & Rule三种形式,且自动忽略None值(返回原对象);
  • 可通过await rule(bot, event, state)主动调用规则判定任意事件;
  • 内置command、shell_command、startswith、endswith、fullmatch、keyword、regex、to_me、is_type九类规则,并有对应on_*快捷注册函数。

响应规则与事件响应器进阶、权限系统共同构成了 NoneBot2 事件分发的完整控制体系,是编写高质量插件时最值得熟练掌握的框架能力之一。

  • 后端
  • 即时通讯

【免费下载链接】nonebot2

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

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

相关推荐

上一篇:抖音无水印下载完整指南:3 条命令跑通单条到主页批量
下一篇:5分钟掌握LinkSwift:八大网盘直链下载的终极解决方案

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

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

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

立即咨询