QQ Bot / AstrBot:从一个 QQ 机器人开始,折腾自己的自动化平台
本文最后更新于12 天前,其中的信息可能已经过时,如有错误请发送邮件到 sunrisetsn@gmail.com

——QQ Bot、AstrBot、NapCat、OneBot 11、Docker,以及一堆越做越离谱的插件。

〇 前言

最开始做这个项目的时候,我其实没有想那么多。

就是单纯觉得:

能不能自己搞一个 QQ Bot?

最好它不只是会聊天,而是真的能帮我做点事情。

比如自动发图片、播放音乐、定时执行任务,甚至通过 QQ 远程控制服务器上的一些程序。

于是就开始折腾 AstrBot。

本来以为就是装个机器人,然后写几个插件。

结果真正做起来以后才发现,这东西比想象中有意思得多。

从最开始研究 NapCat、OneBot 11,到后来开始写自己的插件,再到定时任务、图片获取、音乐功能、远程控制……

做到最后,我突然发现:

我好像已经不太是在做一个 QQ Bot 了。

更像是在慢慢搭一个属于自己的自动化平台。

所以这篇就记录一下这个项目是怎么一步一步折腾出来的。

一、先从 QQ Bot 开始

1. 为什么想做 QQ Bot?

其实原因很简单。

平时经常会有一些重复性的事情。

比如:

  • 想让机器人自动发一些图片
  • 想定时推送一些内容
  • 想通过 QQ 控制服务器上的任务
  • 想调用 AI
  • 想把自己写的一些小工具接进来

这些东西单独做都不算特别难。

但如果每一个功能都单独做一个程序,就会变得很麻烦。

所以一开始的想法就是:

能不能让 QQ 变成一个统一的操作入口?

比如我在 QQ 里输入:

/xxx

机器人就执行某个功能。

或者每天晚上固定时间,它自己完成某项任务。

这样平时甚至不需要登录服务器。

二、AstrBot、NapCat 和 OneBot 11

真正开始做之后,第一件事就是先搞清楚这几个东西到底是怎么连接起来的。

最后大概形成了这样的结构:

QQ
 │
 ▼
NapCat
 │
 ▼
OneBot 11
 │
 ▼
AstrBot
 │
 ├── AI
 ├── 插件
 ├── 定时任务
 ├── 图片
 ├── 音乐
 └── 远程控制

简单理解的话:

NapCat 负责让 QQ 能够被程序控制。

OneBot 11 负责规定机器人和 QQ 之间怎么通信。

AstrBot 则负责处理机器人本身的逻辑,以及插件。

这样分开以后,整个系统就比较清楚了。

三、为什么最后选择 Docker

我的服务器本身就是 Ubuntu,所以最开始也考虑过直接把所有东西装到系统里。

但想了一下还是 Docker 更舒服。

最后服务器大概变成:

Ubuntu
 │
 └── Docker
      ├── NapCat
      ├── AstrBot
      └── 其他服务

这样以后如果某个服务出了问题,直接看对应容器就行。

而且迁移服务器的时候也方便很多。

当然,Docker 也没有想象中那么省心。

四、第一次踩坑:容器启动到底为什么这么难

第一次真正部署的时候,我遇到了不少奇奇怪怪的问题。

有些日志一眼看过去非常吓人。

比如:

Failed to connect to the bus:
 /run/dbus/system_bus_socket missing

还有 GPU、EGL 之类的报错。

以及:

usermod: invalid user ID 'napcat'
groupmod: invalid group ID

刚开始看到这些东西的时候,第一反应基本就是:

完了,程序炸了。

后来慢慢排查才发现,有些错误只是运行环境的问题,并不一定会导致 Bot 核心功能无法工作。

这也是这次项目让我比较有感触的一点:

日志里出现 ERROR,不代表整个程序就一定不能用。

还是得看它到底影响了什么。

五、OneBot:终于让 QQ 和程序连起来

容器跑起来之后,下一步就是测试 OneBot。

理论上只要通信正常,就应该可以通过接口获取 QQ 登录信息。

于是开始测试:

/get_login_info

结果:

连接不上。

当时还以为是 NapCat 出问题。

后来一路排查:

QQ
 ↓
NapCat
 ↓
OneBot
 ↓
HTTP / WebSocket
 ↓
端口
 ↓
AstrBot

中间任何一层没有配置好都不行。

尤其是 Docker 环境下,端口映射和容器内部端口很容易搞混。

这也是第一次比较完整地意识到:

一个“机器人收消息”的功能,实际上背后有好几个服务在互相通信。

六、插件化:不要把所有东西塞进一个文件

等 AstrBot 正常工作之后,就开始真正写功能。

最开始其实很容易写成这样:

bot.py
 ├── 音乐
 ├── 图片
 ├── AI
 ├── 定时任务
 ├── 网络请求
 └── 远程控制

一开始功能少的时候没什么问题。

但我很快意识到一个问题:

以后功能肯定还会继续增加。

那这个文件最后大概率会变成一个巨大的垃圾场。

所以后来开始把功能拆成插件:

AstrBot
│
├── music
├── image
├── scheduler
├── network
├── remote
└── ...

每个插件只负责自己的事情。

例如图片插件只处理:

获取图片
 ↓
处理图片
 ↓
发送

定时任务插件则负责:

判断时间
 ↓
执行任务
 ↓
记录状态

这样以后想删掉一个功能,直接把插件关掉就行。

七、自动发图:这个项目真正开始变得有意思

我最开始比较想做的功能之一,就是:

让机器人每天自动发一些东方相关图片。

理想情况下应该是:

每天 21:00
    ↓
获取当天内容
    ↓
筛选
    ↓
下载图片
    ↓
发送到 QQ
    ↓
删除临时文件

听起来很简单。

然后我就开始研究图片来源。

八、Pixiv:想法很好,网络不太配合

最开始自然想到的是 Pixiv。

毕竟如果是二次元图片,Pixiv 的内容确实非常丰富。

于是最开始的设想就是:

Pixiv
 ↓
获取图片
 ↓
机器人发送

但是实际部署到服务器之后,问题就来了。

服务器的网络环境并不适合直接访问 Pixiv。

于是开始考虑:

换数据源。

后来把目标转向了 THBWiki 以及其他东方相关网站。

整个过程大概就是:

Pixiv
 ↓
网络访问不稳定
 ↓
寻找替代方案
 ↓
THBWiki
 ↓
继续实现自动发送

这其实是开发过程中很常见的一种情况。

很多时候不是你的代码有问题。

而是:

你依赖的东西不一定愿意配合你。

九、定时发送

图片获取的问题解决之后,又出现了一个非常现实的问题:

总不能每天自己输入命令吧。

于是开始做定时任务。

最开始:

/发送图片

需要手动执行。

后来:

每天 21:00
 ↓
自动执行
 ↓
获取内容
 ↓
发送

这时候机器人终于有了一点“自动化”的感觉。

十、每天 21:00 到第二天 21:00

后来又进一步调整了任务逻辑。

不是简单地判断“今天是哪一天”,而是希望把:

昨天晚上 21:00 ~ 今天晚上 21:00

作为一个完整周期。

也就是说:

昨天 21:00
    │
    │    一个完整任务周期
    │
    ▼
今天 21:00

这样处理一些每日推荐、每日统计之类的任务会更加自然。

也让我开始意识到:

定时任务并不只是一个 Timer。

它其实还涉及:

  • 周期
  • 状态
  • 任务是否执行
  • 执行结果
  • 重复执行
  • 服务重启
  • 错过执行时间

十一、然后我忘记开 AstrBot 了

这个事情其实挺蠢的。

有一天到了晚上 21:00。

理论上应该:

21:00
 ↓
自动执行

实际上:

21:00
 ↓
……

因为我根本没开 AstrBot。

于是问题来了:

错过的任务怎么办?

如果只是单纯使用:

if 当前时间 == 21:00:
    执行任务

那错过就是错过了。

所以后面就开始考虑任务恢复机制。

例如:

服务启动
 ↓
检查当前时间
 ↓
检查任务周期
 ↓
判断本次任务是否已经执行
 ↓
如果没有
 ↓
补执行

这件事情看起来很小,但实际上非常重要。

因为一个真正的自动化系统,不能只考虑:

“一切正常的时候怎么办?”

还要考虑:

“如果程序没启动、服务器重启、网络断了怎么办?”

十二、发送完图片之后,删掉

还有一个很实际的问题:

服务器空间。

如果每天都下载几十张图片,然后全部保存下来:

Day 1 → 100 MB
Day 2 → 100 MB
Day 3 → 100 MB
...

时间长了肯定会越来越大。

但实际上这些图片只是作为发送过程中的临时文件。

所以没必要永久保存。

于是任务流程变成:

获取图片
 ↓
保存临时文件
 ↓
发送 QQ
 ↓
确认发送
 ↓
删除临时文件

这也是我比较喜欢的一种设计:

能不存,就不存。

服务器空间留给真正需要保存的东西。

十三、音乐功能

除了自动发图之外,后来又开始折腾音乐。

希望机器人可以:

搜索歌曲
 ↓
获取歌曲信息
 ↓
获取音频
 ↓
发送

然后又开始往里面塞一些东西:

  • 歌曲封面
  • 歌词
  • 歌曲信息
  • 当前播放歌曲

做到这里之后,我突然发现一个很有意思的变化。

原本 QQ Bot 是:

有人说话
 ↓
机器人回复

现在已经变成:

QQ
 ↓
AstrBot
 ↓
调用不同服务
 ↓
完成不同任务

QQ 慢慢变成了一个“控制面板”。

十四、远程控制服务器

既然都已经能通过 QQ 控制机器人了,那能不能顺便控制服务器?

于是又开始折腾远程任务。

理想状态:

QQ
 ↓
机器人
 ↓
服务器
 ↓
执行任务
 ↓
返回结果

例如一些固定的:

查看服务状态
查看 Docker
执行某个任务
重启某个服务

这样平时即使不在电脑前,也可以通过 QQ 做一些简单的服务器管理。

不过这里有个非常重要的问题:

安全。

绝对不能把 QQ 用户发送的文字直接丢给 Shell。

比如这种东西:

os.system(user_message)

基本等于:

给服务器开了个 QQ Shell。

所以正确的思路应该是:

QQ 消息
   ↓
身份 / 权限检查
   ↓
命令白名单
   ↓
参数验证
   ↓
执行
   ↓
返回结果

目前这个方向还可以继续完善,比如权限等级、任务队列、日志记录等等。

十五、项目开始慢慢失控

做到这里,我发现这个项目已经和最开始想象的完全不一样了。

一开始:

“我想做一个 QQ Bot。”

后来:

“给它写几个插件。”

再后来:

“让它每天自动执行任务。”

然后:

“能不能让它控制服务器?”

最后变成:

“既然这些功能都能接进去,那为什么不能做成一个统一的软件?”

于是就出现了现在这个想法。

十六、QQ 其实只是入口

如果把现在的结构抽象一下:

             QQ
              │
              ▼
           AstrBot
              │
      ┌───────┼───────┐
      │       │       │
     AI      音乐     图片
      │       │       │
      ├───────┼───────┤
      │       │       │
    自动化   服务器   其他插件

那么 QQ 只是其中一个入口。

如果再往前一步:

                  Backend
                     │
       ┌─────────────┼─────────────┐
       │             │             │
      AI            Bot         Automation
       │             │             │
       └─────────────┼─────────────┘
                     │
                    API
                     │
             ┌───────┴───────┐
             │               │
          Desktop           Web

那么以后完全可以做一个自己的客户端。

打开软件以后,左边是:

  • 聊天
  • 音乐
  • 图片
  • AI
  • 自动化
  • 服务器
  • 文件
  • 工具

需要什么直接点什么。

十七、我真正想做的东西

所以现在回头看,这个项目的目标已经不是:

“做一个 QQ Bot。”

而更像是:

做一个属于自己的个人集成平台。

把平时会用到的各种东西全部塞进一个地方。

比如:

Personal Hub
聊天AI
音乐图片
自动化服务器
文件各种小工具

甚至以后我自己做的其他项目,也可以通过插件接进来。

这样以后写一个新工具,不一定需要单独做一个完整的软件。

只需要做一个模块,然后接进这个平台。

十八、目前的项目状态

目前大概可以整理成这样:

功能状态
QQ Bot
NapCat
OneBot 11
AstrBot
插件化
音乐功能
图片获取✅ / 持续优化
定时发送
临时文件清理
任务恢复🚧
远程任务🚧
独立客户端💡
Personal Hub💡

很多东西其实还没有做到真正完善。

但现在这个项目已经具备了一个比较完整的基础。

十九、踩坑总结

回头看,这个项目最让我印象比较深的几个坑大概是这些。

1. 网络环境

程序本身没问题,不代表它能访问目标网站。

尤其是服务器环境下,网络问题经常比代码问题更加麻烦。

2. Docker

容器化确实方便,但端口、权限、网络、挂载目录这些东西也需要慢慢搞清楚。

3. Bot 通信链

QQ → NapCat → OneBot → AstrBot。

任何一层出问题,最后表现出来都有可能是:

“机器人怎么没反应?”

4. 定时任务

定时任务真正麻烦的是异常情况。

正常执行很简单。

真正需要考虑的是:

  • 没启动怎么办?
  • 重启怎么办?
  • 重复执行怎么办?
  • 网络断了怎么办?
  • 任务执行失败怎么办?

5. 不要一开始就把东西写死

插件化虽然前期麻烦一点,但功能一多以后,它的优势就非常明显。

二十、最后

这个项目到现在其实还算不上一个完整的软件。

它甚至连一个正式的名字都还没有。

但从最开始的一句:

“能不能弄个 QQ Bot?”

到现在开始思考:

“能不能做一个把这些东西全部集成起来的软件?”

这个变化本身就挺有意思。

我以前做一些小项目的时候,往往都是:

想到一个东西
 ↓
做出来
 ↓
结束

而这次不太一样。

一个 QQ Bot 做出来以后,又自然产生了插件。

插件做多以后,又产生了自动化。

自动化做起来以后,又想接服务器。

最后又开始想着干脆做一个统一的软件。

所以现在看来:

QQ Bot 可能只是这个项目的第一步。

真正想做的,是一个可以不断往里面添加东西的个人工具平台。

以后不管是 AI、音乐、图片、自动化、服务器管理,还是我自己做出来的其他小工具,都可以慢慢接进来。

至于最后它会变成什么样……

现在还不知道。

不过这倒也挺好。

毕竟有些项目,本来就是一边做,一边长出来的。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇