Skip to content

About

AstrBot 插件:改完代码自动热重载,并自证生效到哪一层,回执直接交给 AI

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

43 Commits

Folders and files

Repository files navigation

自主热重载

改完插件代码,你不用追一句「生效了吗」——重载是它自己做的,生效到哪一层也是它自己确认的,回执直接交到 AI 手上。

AstrBot 自带的插件重载只做一件事:清模块缓存,重新 import。剩下的事它不管。

有两类东西重载完照旧跑旧代码:

  1. 平台适配器型插件(QQ / Telegram 这类常驻连接)——旧实例还活着,缓存清了也没用
  2. 插件自己 create_task 起的后台任务(定时器、巡检、重试循环)——没有登记表,谁也不知道它们还在跑

于是就有那个熟悉的场景:回执说成功,行为没变。发条消息试试?还不一定试得出来。

这插件干的事,是每次重载给你一份自证回执,逐层说清到底生效到哪一层。该换血的地方,把旧实例和旧任务一并处理掉。

它是给谁用的

传统插件管理界面是给人类设计的:人改代码,人点重载,人看控制台。但维护插件的如果是 AI,这条链断在两处:

  1. AI 看不到控制台。重载成败、报错堆栈,它都拿不到,只能等人转述
  2. AI 没法确认生效。回执说成功、行为没变,它没有手段自查,只能反复来问

所以这插件把重载结果做成结构化文本,直接返回给 LLM:耗时、版本对比、模块缓存清理数、生效度结论,全在返回值里。AI 读回执就知道状态,不用人去翻日志。

它还给出「必须重启」的明确结论。AI 能自己判断该接着干活,还是该报告人类重启,而不是拿着一个模糊的「成功」猜。

两个场景

一、人不用碰控制台

装上之后对 bot 说人话就行:

「重载一下 memobird 插件」 「把图床插件重载一遍,刚才改了配置」

AI 收到就自己调 hot_reload_plugin,把回执直接答给你。不用记命令格式,不用开 WebUI。

二、AI 修完自己重载

传统流程里 AI 帮你改完代码,事情会断在这儿——还得有人去控制台手动重载一遍。装上这插件,AI 改完代码自己重载、自己读回执、自己判断:

✓ 完全生效 → 接着干活 ⚠️ → 报告需要重启

怎么让 AI 用上

  1. 装上即用:插件加载后 hot_reload_plugin、plugin_list 等 LLM 工具自动注册。只要你的 agent 有函数调用能力(默认有),一句自然语言就能让它自主重载
  2. 权限:管理类 LLM 工具默认仅 ADMIN 可用。要放行指定用户,配 owner_uids
  3. 用子代理的话:update_subagent / subagent_health / subagent_snapshot / subagent_test 一并注册。不用就关 enable_subagent_tools
  4. 人类随时接管:/plugin 系列指令和 LLM 工具并存,聊天里能做同样的事

这插件的第一位用户是作者自己部署的 AI 主代理,每天都在用。真机上撞出来的问题,比设计时想出来的多。

核心能力

生效度评分

每次重载的回执自带结论:

✅ 已重载 · <插件名>
0.24s|1.4.3 → 1.4.4|已加载|清模块 2
绑定无孤儿|换血 6/6|长活无陈旧|生效 ✅ 完全

成功路径就是这三行:结论、事实、体检。只有出现 ⚠️ / 🚨 / ❌ 才展开——假绿会把判据、未换代对象清单和「需手动重启」一并给出来,core 里有没进内存的改动单列一行。

四种结论:生效 ✅ 完全 / ◐ 部分生效(长活链路仍持旧代码)/ ⚠️ 插件已换血,但 core 有改动没进内存 / ❌ 未生效(重载本身失败)。

还有第五种,也是最有用的那种:🚨 假绿——硬判据发现对象没换代时直接点破,附判据与未换代清单,而不是给一句「成功」。

换血:重载当场,不等下一轮

工具 handler 在对话轮开头被收集成快照——同一个 loop 里攥着的那批对象,重载多少次都不换。早先挂过 on_llm_request 钩子,等下一次 LLM 请求到来时才补换;现在不用等了,重载当场就换。

流程:重载前,按 handler_module_path 从工具表(llm_tools 源表)里把属于本插件的 tool 对象抓在手里;重载后,把每个对象的 .handler 就地指向新模块的函数——对象本身不动,持有者指的还是它,但它指着的代码已经翻新。所以本轮 loop 里的下一次工具调用,跑的就是新代码。

难点在「同一个 loop 里重载了第二次,上哪儿找第一次那批对象」。第一次换完它们就不在工具表里了,每次现抓抓不到。所以在抓到时就登记,登记表挂在 core 的 llm_tools 单例上——插件模块重载会整个换掉,挂在自己这儿存不住。这份台账跨重载活着,每次把里面所有还活着的对象刷一遍。

判据两头都不吃快照:换完当场比对新旧 handler 的底层函数对象身份,只有真指向新代码才算数,不靠被重载的代码自报家门。

一句话收口:handler 那层当场就换;但工具描述与参数 schema 是注册时存在 tool 对象上的,本轮 loop 开头那份快照还是旧的——要让「完全」落到眼前,让用户再说一句话开新 loop 最稳。

工具下线时别误读回执

台账跨重载累积,会残留「工具已被删或改名」的历史代对象——在当前工具表里找不到同名新对象,属于正常下线,会被跳过。早先的计数把这类也算进分母,回执就成了 72/73,看着像有一个没换成功,其实是假红。现在分母只算有对应新对象的,下线的单独报:

🫀 就地换血:84/84 个工具 handler 已就地指向新代码|另有 1 个历史对象对应的工具已下线,跳过

N/N 是全换成功,N<M 才是真有问题。

为什么不做快路径

早期版本给单插件重载配过一条「定向快路径」:不 terminate、只重导目标插件,图个不断线。删了。

原因实测得出:core 单插件重载 0.28s 换净 17 个模块,快路径没快到哪里去。代价倒是明确——每轮往内存里留一批旧实例(连跑几轮,活实例换代 数字 40 → 50 只涨不落,最后落到 ×64),全靠一套「活实例换代」机制在后面擦屁股,而那套机制自己又依赖实例换代后的临时状态判断生效度,判据跟着跑偏。

core 的 reload(name) 做 terminate → unbind → load 三件事,旧实例真正销毁,压根不存在「活实例还挂在旧类上」这种局面。一个天生就没欠债的路径,没必要在旁边再养一条欠债的。

必须重启清单

自动检测 astrbot/core 下「源文件比 .pyc 新」的模块——改动在进程导入之后才落盘,内存里没有,任何插件重载都救不了。回执直接点名让你重启,不让你白忙。

判据不依赖系统时钟。有些环境 /proc/uptime 不可信,误报比不报更坏。

平台实例换手(默认关)

针对第一类问题。开启后:重载完成 → 停旧实例(连它的任务一起收走)→ 按新代码重挂 → 自检确认。真机实测断线重连约 1 秒(0.99s)。

三道安全闸:拿不到配置跳过、enable=false 跳过、别家实例零动作。

陈旧任务回收(默认关)

针对第二类。只取消「归属本插件且仍持旧模块代码」的任务——新任务、别家插件、当前调用者自身一律不碰(零误杀验证过)。吞掉 CancelledError 的顽固任务只记录,不强杀。

子代理三件套

在 AstrBot 子代理编排里,这三个工具把「改完人格不知道改没改上」变成能验证的事:

  • subagent_health 四层体检:编制表(config)↔ 运行时实例(handoffs)↔ 人格源(persona DB)↔ provider 可用性。专治在编未挂载、人格缺失导致的串台回落、改完人格没重载、provider 失效
  • subagent_snapshot 编制快照:save 备份 orchestrator 配置段和全部相关人格;list 列历史;rollback 一键恢复(人格不存在就跳过并说明,不做半恢复)。存在 data/plugin_data/astrbot_plugin_auto_reload/subagent_snapshots/,纯本地
  • subagent_test 试音台:用子代理的人格和 provider 直接发一条测试消息,拿回原始回复,不转发给用户。调人格时改一段试一段,session 隔离,60s 超时

写入安全(1.4.1–1.4.3 补的):persona_prompt 支持 file:<路径>,只认插件数据目录内的文件,绝对路径指向外部、.. 向上穿越、经符号链接跳出——三种都拒绝;新人格短于现值 60% 会被拒写,确认是有意精简才传 force=true;remove / upsert / 快照回滚三处「读-改-写-重载」整段入锁,可并发推送;返回值末尾附一行自检(内存=DB=传入|provider 未漂移|描述非空)。

不用子代理?把 enable_subagent_tools 关掉,四个工具(含 update_subagent)整体消失,不占工具列表。

聊天指令

指令 说明
/plugin help 查看帮助
/plugin list 查看所有插件(按启用/禁用/保留分组)
/plugin info <名称> 查看插件详情
/plugin enable <名称> 启用插件
/plugin disable <名称> 禁用插件
/plugin reload <名称> 重载插件
/plugin install <GitHub URL> 从仓库安装(需开启配置)
/plugin uninstall <名称> 卸载(需开启配置)
/plugin update <名称> 从仓库更新

另有 LLM 工具 hot_reload_plugin、plugin_list,以及上面的子代理四工具。

配置

在插件配置页找到「自主热重载」:

配置项 默认 说明
allow_install 关 允许聊天指令安装插件
allow_uninstall 关 允许聊天指令卸载插件
hot_reload_handover_default 关 每次重载自动做平台实例换手(工具传参可按次覆盖)
hot_reload_reclaim_default 关 每次重载自动回收陈旧后台任务(工具传参可按次覆盖)
enable_subagent_tools 开 启用子代理四个 LLM 工具
owner_uids 空 免 ADMIN 放行的用户 ID 列表

换手和回收默认都关着。先看回执 🧬 行报不报陈旧,确认需要换血再开——日常重载零代价。

安装

下载本插件文件夹放进 AstrBot 的 data/plugins/,重启。

或从 AstrBot 插件市场搜「自主热重载」一键装。

兼容性

适配 AstrBot 4.16+(metadata.yaml 声明 >=4.16,<5;本轮开发与实机的基线是 4.27.x)。

指令类功能(/plugin list 等)只依赖公开接口,兼容性最好。

深度热重载和子代理工具依赖 AstrBot 内部模块(astrbot.core.star.updater、astrbot.core.persona_mgr、astrbot.core.subagent_orchestrator 等)。这些内部 API 官方没承诺稳定,版本升级可能让相应功能失效。遇到问题先核对版本,附上回执和日志开 issue。

该重启就重启

热重载不是银弹。以下场景老实重启:

  • 改了 astrbot/core/**(回执会主动报 🚨)
  • 平台端口绑定 / webhook 路径变更
  • 全局 config.yaml 结构变更、数据库 schema 迁移

注意

  • 卸载插件会删掉插件目录,手别抖
  • install 会执行 pip install,确认仓库来源可信再开
  • 本插件无法卸载自身(防止把自己搞没)

更新记录

见 CHANGELOG.md。

作者与致谢

hypxtmc

插件管理的基础骨架(列表 / 启停 / 安装 / 卸载 / 更新的指令框架)来自 Neko Ai 的早期开源插件。热重载深度能力——生效度评分、必须重启清单、平台实例换手、陈旧任务回收、假绿防护——是在那个骨架之上完全重新设计的。

按 LICENSE(MIT),原作者的版权声明保留。

本插件为本地维护版本,不设远程更新源。/plugin update 会明确拒绝,防止误拉原作者仓库覆盖本地改动。

About

AstrBot 插件:改完代码自动热重载,并自证生效到哪一层,回执直接交给 AI

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages