云崽bot基础搭建过程记录
云崽bot基础搭建过程记录
突发奇想想要搭建一个qqbot玩玩,经同学推荐,准备从最简单的yunzai框架入手。
安装
环境准备:Windows/Linux/MacOS/Android Node.js(>=v21), Redis, Git
redis安装
下载地址redis,密码:114514
解压后启动redis-server.exe这个文件。
将redis-server.exe所在的目录添加进环境变量,这样yunzai启动时会自动找到redis并启动
nodejs安装
- windows操作系统的话直接下64位msi文件一键安装就行了
- linux的话下下来是一个
.tar.xz
文件,tar -xvf xxx.tar.xz
就能够解压出来,然后把./bin/
目录放到环境变量里去就行,export PATH=/path/to/node-v20.18.0-linux-x64/bin:$PATH
,不想每次都重新设置环境变量就直接在~/.bashrc
中加这一行命令
git安装
- windows:https://git-scm.com/downloads/win
- linux:
sudo apt update | sudo apt install git
yunzai本体安装
有了如上几个必选项后
1 | git clone --depth 1 https://gitee.com/TimeRainStarSky/Yunzai |
启动
在yunzai目录下启动:
1 | node . |

启动协议端
“协议端” 是指实现 QQ 通信协议的服务组件。不同的协议端提供了不同的功能和适配方式,例如:
- OneBot v11:支持标准化的 OneBot 协议,可以与多种第三方服务交互。
- ComWeChat:通过仿 QQ 客户端的方式实现通信。
- GSUIDCore 和 OPQBot:各自提供不同的兼容特性和扩展。
这些协议端负责处理与 QQ 的连接(包括登录、消息收发等),为机器人提供基础的通信能力。
启动协议端的目的是:
- 连接到 QQ 服务器并登录指定的 QQ 账号。
- 监听来自 QQ 的消息(例如群聊消息、私聊消息等)。
- 转发消息到 Yunzai-Bot 的核心逻辑,进行处理。
- 将 Yunzai-Bot 处理后的响应结果(如回复消息)发送回 QQ。
账号绑定
协议端绑定
我们选用OneBotv11作为协议端,下载并运行Lagrange.OneBot
后改配置,这里实际上是配置了一个反向
WebSocket
连接,而在yunzai/config/config/bot.yaml
中实际有指定服务器开放的端口为2536,所以我们要在协议端开放2536端口。


修改过后大概长这样:
1 | { |
其中Lagrange.OneBot
在配置改完后按任意键继续时,会出现一个二维码。这时我们拿自己的qq小号(bot)扫码就可以登录进去了。之后我们在yunzai的主程序中就看到了连接建立

但有时候登录时会显示需要Captcha认证,需要输入ticket
和token
,这时候我们需要到提供的网址处去手动验证,并抓包查看对应的ticket
和token
。


然后可以分别输入ticket和token。之后如果还是显示安全风险无法登录,可以在appsettings.json
中加入"SignServerUrl": "https://sign.lagrangecore.org/api/sign/25765"
这么一条配置,用来获取签名。


如果还是显示安全风险,可以到签名服务器文档中找一个别的签名服务器换上。实在不行,可以把当前目录下除了Lagrange.OneBot.exe
和appsettings.json
全部删除了重新启动。
设置主人
之后我们发现yunzai/plugins/example
中有个主动复读.js
文件,里面实现的内容就是匹配到#复读
就进行复读,可以用来进行测试。

然后就给bot私发#设置主人就能够获取权限。


当然也可以直接改yunzai/config/config/other.yaml
中的masterQQ以及master进行配置。其中master的格式是
bot qq:master qq
。

插件安装
插件里提供了各式不同类型的功能,在yunzai
bot运行时,会自动加载yunzai/plugins
目录下的各个插件目录。
新的插件可以自己进行编写,存在插件目录下,也可以github和gitee上找新插件下载,大体有以下几种方式进行安装。
自带指令
一般能装一些最常用的插件
1 | #安装TRSS-Plugin |
curl
可以方便下载gitee上一些插件
1 | curl -o "./plugins/example/定时群发.js" "https://gitee.com/batvbs/Miao-Yunzai-batvbs/raw/master/定时群发.js" |
基础功能测试及编写
以./plugin/example
目录下的主动复读.js
为例
1 | export class example2 extends plugin { |
首先是继承了plugin父类。各个参数的含义见注释。
1 | export default class plugin { |
然后会调用自定义实现的func函数,在setcontext之后,后续收到的消息会将程序执行流转到另一个自定义的函数doRep。最终bot实际发送消息是用this.reply
这个接口实现的,在父类中看,调用了e对象中的reply。
e对象结构
我们要想稍微深入一点理解执行过程,就首先得知道this.e
是个什么对象。我们可以加一个console.log来在日志中记录这个e的具体结构。加上之后给bot发#复读
看看结构。

1 | <ref *1> { |
核心信息
message_type
: 表示消息类型。"group"
: 群聊消息。"private"
: 私聊消息。
sub_type
: 子类型。- 对于群聊消息,常见值是
"normal"
,表示普通消息。
- 对于群聊消息,常见值是
message_id
: 消息 ID,可用于引用或撤回这条消息。group_id
: 群号,仅当消息类型是"group"
时存在。user_id
: 发送者的 QQ 号。message
: 消息的具体内容,数组形式,每个元素是一个对象,表示消息的组成部分。- 示例:
[ { text: '#复读', type: 'text' } ]
- 示例:
raw_message
: 消息的原始内容,字符串形式。- 示例:
"#复读"
- 示例:
sender
: 发送者信息,包含以下字段:user_id
: 发送者 QQ 号。nickname
: 昵称。card
: 群名片。sex
: 性别,值可能是"male"
、"female"
或"unknown"
。level
: 群等级。role
: 群内角色,可能是"owner"
(群主)、"admin"
(管理员)或"member"
(普通成员)。
扩展信息
self_id
: 机器人的 QQ 号。post_type
: 事件类型。"message"
: 消息事件。
time
: 发送时间的时间戳(Unix 时间)。isGroup
: 布尔值,表示消息是否来自群聊。isMaster
: 布尔值,表示发送者是否为插件配置的主人。
事件上下文管理
runtime
: 插件运行时信息。runtime.e
: 当前事件对象(即this.e
本身)。- 其他属性用于管理事件处理流程。
reply函数实现
同样的方式,用console.log(this.e.reply.toString());
,能动态查看这个reply函数的源码。然后再在vscode里搜索一下,最后在loader.js中找到了对应代码。
1 | e.reply = async (msg = "", quote = false, data = {}) => { |
函数参数
1 | async (msg = "", quote = false, data = {}) |
msg
: 要发送的消息,默认值是空字符串。quote
: 是否引用消息(通常用于回复特定消息),默认值为false
。data
: 一个对象,包含额外的选项,包括:recallMsg
: 是否自动撤回消息,单位是秒(默认值为0
,即不撤回)。at
: 是否 @ 某人。可以是用户 ID,也可以是true
(表示 @ 当前消息发送者)。
at
和
quote
功能的处理
@ 功能 (at
)
1 | if (at && e.isGroup) { |
如果传入了
at
且当前消息是群消息:- 如果
at === true
,则默认 @ 当前用户e.user_id
。 - 如果消息内容是数组,会在数组前添加
@
信息和换行符。 - 如果消息是普通文本,则将消息包装成一个数组并加上
@
信息。
- 如果
引用消息 (quote
)
1 | if (quote && e.message_id) { |
如果
quote
为true
且当前事件中有message_id
:- 在消息前添加一段引用内容(
segment.reply(e.message_id)
)。 - 类似
at
的逻辑,会将消息转换为数组格式。
- 在消息前添加一段引用内容(
消息发送与异常处理
1 | let res |
- 使用
reply(msg)
发送消息。 - 如果发送失败,会捕获异常,并通过
Bot.makeLog
记录错误日志。
自动撤回消息
1 | if (recallMsg > 0 && res?.message_id) { |
如果
recallMsg
大于 0 且成功发送了消息(res?.message_id
存在):- 如果消息是在群聊中发送,调用
e.group.recallMsg
撤回消息。 - 如果消息是在私聊中发送,调用
e.friend.recallMsg
撤回消息。 setTimeout
用来延迟recallMsg
秒后执行撤回操作。
- 如果消息是在群聊中发送,调用
统计与返回
1 | this.count(e, "send", msg) |
- 调用
this.count
方法统计消息发送(如记录发送次数)。 - 最后返回消息发送的结果
res
。
这样我们就可以尝试着手实现一个简单的功能改造了,这个自带的复读文件需要我们输入#复读
,然后bot回应后我们再输入内容,bot才会复读该内容。那么我们可以尝试将其改造成一个我们@bot后输入复读xxx,然后bot复读xxx的一个功能插件。
在更改的过程中发现了一个严峻的问题,就是其rule中reg的正则匹配只返回了true或false,但并不能捕获分组。这里我们可以在函数体内部再进行一次正则表达的匹配,然后进行输出。
在测试中也发现,我们@bot的这个前缀实际不会出现在e.msg中,只用匹配后面的内容就行。
最终更改结果:
1 | export class example2 extends plugin { |
- 标题: 云崽bot基础搭建过程记录
- 作者: collectcrop
- 创建于 : 2024-11-27 12:38:30
- 更新于 : 2024-11-27 12:53:51
- 链接: https://collectcrop.github.io/2024/11/27/云崽bot基础搭建过程记录/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。