麻麻专属 — 说「闭嘴」就让窝真正安静,说「忽略」就让杂鱼消息消失,说「限频」就把刷屏的号按分钟卡住!
版本:v1.4.0 | 作者:小七月 | 平台:aiocqhttp
| 功能 | 指令 | 作用 |
|---|---|---|
| 🤐 闭嘴 | 闭嘴 [秒数] |
窝在当前会话内真正停止回复 |
| 🗣️ 说话 | 说话 |
提前解除当前会话的闭嘴状态 |
| 🚫 忽略用户 | 忽略 <QQ号> [秒数] |
指定用户的留言在时效内被跳过 |
| ✅ 取消忽略 | 取消忽略 <QQ号> |
提前解除对某用户的忽略 |
| ⏱️ 限频 | 限频 <QQ号> <次数> |
限制指定用户每分钟最多发 N 条消息 |
| ❌ 取消限频 | 取消限频 <QQ号> |
移除对某用户的限频限制 |
| 📋 限频列表 | 限频列表 |
查看当前所有限频配置 |
- 所有指令都支持
/前缀,例如/闭嘴 30。 - 指令按长度优先匹配,所以
取消限频不会被限频抢先吃掉。 - 只有
mama_ids里的 QQ 号能触发,其他人发指令没有任何反应。
三种功能的生效范围不一样,别搞混啦:
| 功能 | 作用域 | 键 |
|---|---|---|
| 闭嘴 / 说话 | 会话隔离:群聊只影响当前群,私聊只影响当前私聊 | group:<群号> / private:<发送者QQ> |
| 忽略 / 取消忽略 | 全局:按 QQ 号生效,跨群跨私聊 | <QQ号> |
| 限频 / 取消限频 | 全局:按 QQ 号生效,跨群跨私聊 | <QQ号> |
- 闭嘴状态字段为
group_silence_until(旧版是silence_until)。 - 麻麻自己的消息永远不受忽略与限频影响;闭嘴对所有人一律生效。
闭嘴 → 默认闭嘴 60 秒
闭嘴 30 → 闭嘴 30 秒
闭嘴 120 → 闭嘴 2 分钟
说话 → 提前解除闭嘴
触发后窝回一句确认,随后在当前会话内停止回复。闭嘴期间的 LLM 请求会在生成前被精准掐断,被动的 yield 回复也会被清空。
如果本来就没闭嘴,说话 会回复「窝本来就在说话呀~」。
忽略 12345678 → 忽略该 QQ,默认 60 秒
忽略 12345678 300 → 忽略该 QQ,300 秒
取消忽略 12345678 → 提前解除忽略
- 参数从文本中提取数字,所以
忽略 @某人 30这种写法也能用。 - 忽略的是「这个 QQ 号发的消息」,走到期时间自动失效,重启不丢。
- 取消一个本来没被忽略的号,会回复「本来就没被忽略哦」。
限频 12345678 5 → 该用户每分钟最多 5 条
限频 12345678 3 → 该用户每分钟最多 3 条
限频 12345678 0 → 每分钟最多 0 条 = 完全屏蔽该用户
取消限频 12345678 → 移除该用户的限频
限频列表 → 打印当前所有限频
- 采用滑动窗口:只统计过去 60 秒内的消息条数,超限即拦截,不需要等到整分钟重置。
限频列表会自动派生(<限频指令>+列表),如果它和取消指令重名则不会派生。- 设置限频时会清空该用户的历史计数,避免旧时间戳把新规则直接触发。
- 次数必须是大于 0 的整数,否则会提示格式错误。
- 被限频拦下的消息不会到达 LLM,也不会有任何提示。
配置是嵌套结构,修改后需要重载插件生效。
| 配置 | 类型 | 默认值 | 说明 |
|---|---|---|---|
mama_ids |
list | ["2594036384", "1732147236"] |
麻麻 QQ 号列表(唯一有权控制的身份) |
require_admin |
bool | false |
为 true 时,麻麻还必须具备 bot 管理员权限 |
priority |
int | 10000 |
| 配置 | 类型 | 默认值 |
|---|---|---|
shutup_commands |
list | ["闭嘴"] |
default_duration |
int | 60(秒) |
shutup_reply |
string | 呜…窝闭嘴 {duration} 秒…(´;ω;` ) |
| 配置 | 类型 | 默认值 |
|---|---|---|
unshutup_commands |
list | ["说话"] |
unshutup_reply |
string | 好耶~窝复活啦!ヽ(●´∀`●)ノ |
| 配置 | 类型 | 默认值 |
|---|---|---|
ignore_commands |
list | ["忽略"] |
default_duration |
int | 60(秒,与闭嘴时长独立) |
ignore_reply |
string | 遵命麻麻~已忽略用户 {target} {duration} 秒!(`・ω・´)✧ |
| 配置 | 类型 | 默认值 |
|---|---|---|
unignore_commands |
list | ["取消忽略"] |
unignore_reply |
string | 好呐~已取消忽略用户 {target}!(๑¯◡¯๑)✧ |
| 配置 | 类型 | 默认值 |
|---|---|---|
ratelimit_commands |
list | ["限频"] |
ratelimit_reply |
string | 好呐~已设置 {target} 每分钟最多 {limit} 条!(๑¯◡¯๑)✧ |
| 配置 | 类型 | 默认值 |
|---|---|---|
unratelimit_commands |
list | ["取消限频"] |
unratelimit_reply |
string | 好呐~已取消 {target} 的限频!(๑¯◡¯๑)✧ |
💡 回复模板支持的占位符:
{duration}(已格式化为「1 分 30 秒」这类友好文本)、{target}、{limit}。模板写错不会报错,会原样输出。
消息进入
│
▼
┌──────────────────────────────────────┐
│ @filter.event_message_type (ALL) │ ← 指令总入口,priority=10001
│ 仅 mama_ids 可继续,按长度优先匹配 │
│ 闭嘴/说话/忽略/取消忽略/限频/取消/列表 │
└──────────────────────────────────────┘
│
├────────── LLM 路径 ──────────┐
│ │
▼ │
┌──────────────────────────┐ │
│ on_llm_request 拦截 │ │
│ 会话闭嘴中? │ │
│ → should_call_llm(False) │ │
│ + req.contexts.clear() │ │
│ │ │
│ 用户被忽略(非麻麻)? │ │
│ → 同上 │ │
│ │ │
│ 触发限频(非麻麻)? │ │
│ → 同上,且在此处计数 │ │
└──────────────────────────┘ │
│ │
├──────── yield 路径 ─────────┤
│ │
▼ │
┌──────────────────────────┐ │
│ on_decorating_result 拦截 │ ←────┘
│ 会话闭嘴中?→ chain = [] │
│ 被忽略(非麻麻)?→ 清空 │
│ 触发限频?→ 只判断不计数 │
└──────────────────────────┘
- 指令层:不再用
@filter.command,改为单一入口手动分发,避免多指令抢匹配、别名带空格失效、/前缀识别不到等问题。 - LLM 侧拦截:
should_call_llm(False)阻止调用 +req.contexts.clear()清空上下文,避免闭嘴期间对话历史被污染。 - 结果侧拦截:
result.chain = []清空结果链,堵住yield event.plain_result(...)这类被动回复的漏洞。 - 计数只做一次:限频在
on_llm_request计数,on_decorating_result只判断,避免一条消息被算两条。
状态文件:data/plugin_data/astrbot_plugin_chat_limit/control_state.json
{
"group_silence_until": {"group:1083658927": 1760000000.0},
"ignored": {"12345678": 1760000000.0},
"rate_limits": {"12345678": 5}
}- 写入时机:任何状态变更后立即落盘;过期条目在写入时顺带清理。
- 读取失败只打 warning,不会让插件崩掉。
- ✅ 数据目录使用当前插件名
astrbot_plugin_chat_limit;启动时若新目录无状态文件,会自动回退读取旧注册名目录astrbot_plugin_control的历史状态,并写回新目录完成迁移。 ⚠️ 限频的时间戳_msg_ts只在内存中,重载插件后计数归零。
无额外依赖。 只用 AstrBot 内置 API:
| 模块 | 用途 |
|---|---|
astrbot.api.event |
事件与过滤器 |
astrbot.api.provider |
LLM 请求拦截 |
astrbot.api.star |
插件注册、数据目录 |
astrbot.api.logger |
日志输出 |
开箱即用,无需 pip install。
astrbot_plugin_chat_limit/ # 目录名
├── main.py # 插件主代码(单文件)
├── metadata.yaml # 插件元信息
├── _conf_schema.json # WebUI 配置模式
├── logo.png # 插件图标
└── README.md # 本文件
- 🗂️ 持久化目录整改:数据目录由旧注册名
astrbot_plugin_control改为当前插件名astrbot_plugin_chat_limit,符合 AstrBot 上架规范 - 🔁 自动迁移:启动时若新目录无
control_state.json,自动回退读取旧目录并写回新目录,迁移完成即用新路径 - 🧹 清理冗余:移除历史遗留的备份文件与缓存目录,目录结构与
metadata.yaml对齐 - 📝 README 同步:状态文件路径、迁移说明、版本号与更新日志
- 🐞 修复限频完全失效:原实现把时间戳追加到临时列表,从未写回
_msg_ts,导致永远不触发拦截 - 🐞 修复限频重复计数:
on_llm_request计数、on_decorating_result只判断不计数,避免一条消息算两次 - 🐞 修复指令参数解析:
限频 12345 5之前按空格取参,指令别名带空格或/前缀时失效;现改为统一文本匹配 + 数字提取 - ⚙️ 配置真正生效:指令名、默认时长、回复模板全部从
command_settings读取,支持别名与占位符 - 🔧 指令分发合并:改由单一
event_message_type入口按「长指令优先」匹配,修复取消限频被限频抢先匹配的问题 - ✨ 新增
限频列表自动派生(<限频指令>列表),并补充_fmt_duration时长友好显示 - 🐞 限频窗口统一为 60 秒,与 README 和配置描述一致(旧代码是 300 秒)
- 📝 README 重写:修正插件名与版本号、按实际嵌套结构重写配置表、补充作用范围与状态文件说明
- 🪪 标识对齐:
@register名由astrbot_plugin_control改为astrbot_plugin_chat_limit,与目录名、metadata.yaml一致;数据目录仍沿用旧名以免丢状态
- ⏱️ 新增限频功能:自定义 QQ 号每分钟对话次数上限,超限自动拦截
- 🛡️ 三路拦截:闭嘴 + 忽略 + 限频,全部走
on_llm_request+on_decorating_result双路 - ⚙️
_conf_schema.json新增限频/取消限频配置组 - 📝 README 更新:新增限频指令详解 + 原理图 + 配置表
- 🔧 新增
on_decorating_result双路拦截:补全@filter.commandyield 被动回复的拦截漏洞 - 📋 双路保险机制:
- LLM 路径:
on_llm_request→should_call_llm(False)+ clear contexts - yield 路径:
on_decorating_result→result.chain = []
- LLM 路径:
- 📝 README 更新:实现原理图增加 yield 拦截分支
- 🎉 初始版本
- 🤐 闭嘴 / 说话 指令,LLM 请求层精准拦截
- 🚫 忽略 / 取消忽略 指定 QQ 用户
- 💾 状态持久化到文件,重启不丢失
- ⚙️ WebUI 完整配置支持
- 📦 零额外依赖,开箱即用