词库插件 DSL 语法使用手册
零基础也能上手的 QQ 机器人自动回复编写指南
开始
欢迎
欢迎!本手册将教你如何使用词库插件的 DSL(领域专用语言)来编写 QQ 机器人的自动回复功能。即使你没有编程经验,按照本手册的步骤也能轻松上手。
本手册基于 dicpro.ck 示例文件编写,建议你一边看手册一边对照 dicpro.ck 文件学习。
什么是 .ck 文件
每个 .ck 文件可以包含多条规则,每条规则定义了:当用户发送什么消息时,机器人应该做什么。
.ck 文件是词库插件的源文件。你只需要用记事本(或任何文本编辑器)创建一个以 .ck 结尾的文件,放入"词库文件"文件夹,机器人就会自动读取并生效。
文件的基本结构
一个 .ck 文件由多个"段落"组成,段落之间用空行(至少一个空行)分隔。
每个段落的结构是:
- 第一行:触发指令(匹配用户消息的规则)
- 后续行:要执行的代码(机器人收到匹配消息后执行的操作)
示例(最简单的你好机器人)
你好 $发送 你也好呀!$
上面这个例子表示:当有人在群里发送"你好"时,机器人会回复"你也好呀!"。
.ck 文件里可以写很多个段落,每段之间用空行隔开即可。基础语法
触发指令(词条匹配规则)
触发指令写在每个段落的第一行,用来匹配用户发送的消息。
1. 精确匹配
直接写文字,表示用户必须发送完全相同的文字才会触发:
你好 $发送 hi$
用户发"你好"触发,发"你好呀"不触发。
2. 正则表达式匹配
如果你懂正则表达式,可以使用括号来捕获用户消息中的部分内容,捕获的内容可以通过 %括号1%、%括号2% 等变量在后续代码中使用:
括号测试([\s\S]*) a = %括号1% $发送 你发送的内容是:%a%$
上面例子中,用户发送"括号测试xxxxx",xxxxx 会被捕获到 %括号1% 中。
如果需要匹配多个部分,用多个括号:
测试md([\s\S]*)#([\s\S]*) a = $直发按钮 %括号1% %括号2%$ $发送 ±md content=%a%±$
多个参数匹配可使用正则对指定字符内容屏蔽,或使用分割标识字符进行参数分割,该分割字符需加入指令,例如:测试mc你好#我不好。
关于正则的更多知识,可以搜索"正则表达式入门"来学习。最常用的两个:
([\s\S]*)—— 匹配任意内容(包括换行)(.*)—— 匹配任意内容(不包括换行)
3. 内部函数(不对外触发)
以 [内部] 开头的指令不会匹配用户消息,只能通过 $调用 函数名$ 和 $调用 函数名 #参数1#参数2$ 来使用:
[内部]你好 $发送 这是内部函数$ [内部]你好[参数1 参数2] 返回 参数1, 参数2
关于内部函数的详细用法,请参见"内部函数"。
变量与赋值
在 DSL 中,你可以使用变量来存储数据。变量名由字母、数字、下划线组成。
1. 赋值
使用等号 = 给变量赋值:
a = '你好' b = 123 c = '你好世界'
赋值语法和 python 基本相同,纯数字、函数、%变量名% 和 json 可不在外部加 "" 和 '',其他的则需要加。
变量名2 = f"$直接发送 xxx xxx$"
2. 使用变量
使用 %变量名% 来读取变量的值:
a = '世界' $发送 你好,%a%!$
输出结果:你好,世界!
输出消息($发送 xxx$)
$发送 xxx$ 是最常用的命令,用于让机器人发送消息到群里。
1. 基本用法
$发送 你好,欢迎你!$
2. 带变量的用法
name = 小明 $发送 你好,%name%,欢迎加入本群!$
3. 类型消息的用法
类型消息可以实现 @人、发图片、发 Markdown 等高级消息,详情见下一章。
$发送 ±at %QQ%± 你好呀!$
4. 拓展用法
发送消息到指定的群主或用户
$发送 群 群号 内容$ $发送 私 QQ 内容$
消息类型(±..±)
在 $发送$ 语句中,可以用 ±类型 参数± 的格式来插入特殊的消息元素。
格式:±类型 参数1=值1,参数2=值2±
旧:
±md content=你好±新:
±md 你好±1. 组合多种类型消息
可以在一行中组合多种类型消息:
$发送 ±md #你好±±at %QQ%±±kd %kd_data%±$
2. 发送纯文本
纯文本不需要用 ± 包裹,直接写在 $发送 里面即可:
$发送 这是纯文本$
3. @某人(at)
$发送 ±at %QQ%± 你好!$
%QQ% 是发送者的 QQ 号,所以上面会 @ 发送消息的那个人。
你也可以 @ 指定的人:
$发送 ±at 123456789± 你好!$
4. 发送 Markdown 消息(md)
content = 这是标题 $发送 ±md # %content%±$
拓展用法:$发送 ±md±你好$ 表示该消息以 md 为基础进行构造。
Markdown 内容里可以使用 \n 表示换行。
支持的 Markdown 语法:请见 QQ 官方文档
5. 发送图片(img)
pic_url = $html https://example.com$ $发送 ±img %pic_url%±$
图片可以是网络链接,也可以是本地文件路径。如果是使用在官机的md语法中组合不会生效,暂时不计划对网络路径支持,请使用QQ官机的md语法
6. 发送键盘/按钮(kd)
键盘是一种特殊的数据格式(JSON),用于在 QQ 官方机器人中显示按钮。
kd_data = {
"rows": [
{
"buttons": [
{
"id": "btn_1",
"render_data": {
"label": "点我",
"visited_label": "已点",
"style": 1
},
"action": {
"type": 1,
"data": "777888",
"permission": {"type": 2},
"reply": true,
"enter": true
}
}
]
}
]
}
$发送 ±kd %kd_data%±关于键盘格式的更多细节,请参考 QQ 官方机器人文档。或者也可以使用软件自带的按钮编辑器。
7. 语音消息
$发送 ±ptt 本地路径/网络连接±$
具体支持的语音格式文件有 silk、mp3、ogg,还有一个忘了。
条件判断(如果 / 另如果 / 否则)
条件判断用于根据不同的情况执行不同的操作。暂时未支持and并列判断语法,会在未来版本中支持
1. 基本语法
如果 变量 比较符 值 条件成立时执行 如果尾 另如果 变量 比较符 值 上一个条件不成立,但这个成立时执行 如果尾 否则 以上条件都不成立时执行
2. 支持的比较符
| 比较符 | 含义 |
|---|---|
| == | 等于 |
| != | 不等于 |
| > | 大于 |
| < | 小于 |
| >= | 大于等于 |
| <= | 小于等于 |
3. 完整示例
cs = '你好' 如果 cs == '你好' $发送 你也好!$ 如果尾 另如果 cs == '再见' $发送 拜拜!$ 如果尾 否则 $发送 我不太明白你的意思$
如果尾表示当前 if 块的结束(在不继承比较条件的情况下必须写!)
循环(循环...循环尾)
循环用于重复执行一段代码,直到条件不再满足。
1. 语法
循环(条件) 要重复执行的代码 循环尾
2. 示例:发送多次消息
i = 0 循环(%i% < 3) $发送 这是第 %i% 次$ i = %i% + 1 循环尾
上面的代码会发送 3 次消息(i 从 0 到 2)。
%变量名% 来引用,直接填入变量名即可。例如:i = 0 循环(i < 3) $发送 这是第 %i% 次$ i = %i% + 1 循环尾
3. 无限循环(慎用)
循环True $发送 我会一直发!$ 循环尾
break。数学计算($计算)
$计算 用于执行数学运算。计算表达式用方括号 [] 包裹。
1. 基本用法
result = $计算 [1 + 2]$ $发送 结果是 %result%$
2. 支持的运算
+加法-减法*乘法/除法
3. 使用括号
重要:在 $计算 中,所有的括号都要用方括号 [] 代替圆括号 ():
a1 = 2 a2 = 8 a3 = 10 a = $计算 [a3 * [a1 + a2 * a3]]$
上面的表达式相当于数学中的:10 * (2 + 8 * 10)
3. 变量参与计算
在计算中可以直接使用变量名(不需要 % 号):
x = 5 y = 3 z = $计算 [x * y + 10]$ $发送 z = %z%$
文件读写($读文件 / $写文件)
词库插件提供了简单的文件存储功能,在授权存储权限后,数据保存在 手机目录(一般为 emulated/0/....)/cikuapk/data 文件夹中。
当你传入路径时,一般默认为 /storage/emulated/0/cikuapk/data/ 路径参数下,即当你文件在该路径下时,/storage/emulated/0/cikuapk/data/user.txt 只需传入 user.txt 即可。
当然你也可以使用绝对路径 /storage/emulated/0/其他...,即传入 /storage/emulated/0/其他文件夹/user.txt。
1. 写入文件($写文件)
格式:$写 文件路径 键 值$
$写 用户数据 aaa %QQ%$
上面代码的含义:在"用户数据"文件中,以aaa为键,写入的值为用户的QQ号
文件会保存在 data/用户数据 这个路径下。文件内部格式是"键 = 值",每行一条。
不带键名的写法(直接覆盖整个文件):
$写 状态信息 在线$
2. 读取文件($读文件)
格式:$读 文件路径 键 默认值$
data = $读 用户数据 %QQ% 无$ $发送 你的数据是:%data%$
如果文件或键不存在,则返回你指定的默认值(此例中为"无")。
不带键名的写法(读取整个文件内容):
content = $读 状态信息 默认状态$
参数顺序说明:
- 第一个参数:文件路径(相对于 data 文件夹)
- 第二个参数:键名(可选,不写则读取整个文件)
- 第三个参数:默认值
文件转json
文件转json
本函数只适用于本软件使用的数据存储格式,即 xxx=xxxxxxx。
如何使用:res = $转json 路径$
返回示例——文件:
张三=1 李四=9 王五=6 六群=4 流萤=10
返回:
[{'张三': 1}, {'李四': 9}, {'王五': 6}, {'六群': 4}, {'流萤': 10}]网络请求($访问)
$访问 用于从互联网获取数据(发送 HTTP 请求)。
1. GET 请求
res = $访问 http://example.com/api/data get$ $发送 %res%$
2. POST 请求
res = $访问 http://example.com/api/data post$
3. 完整参数
res = $访问 http://example.com/api/data post headers数据 json数据$
参数依次为:网址、请求方法、请求头、请求体。
大多数情况下,你只需要用到前两个参数。
JSON 数据提取(@%变量%#路径)
当 $访问 返回 JSON 数据后,可以用 @%变量%#路径 来提取其中的字段。
1. 语法
@%变量名%#字段1#字段2#字段3...用 # 号逐级深入 JSON 对象的层级。
2. 示例
假设 $访问 返回的数据是:
{
"name": "小明",
"info": {
"age": 18,
"city": "北京"
}
}提取数据:
res = $访问 http://example.com/api/user get$ name = @%res%#name city = @%res%#info#city $发送 %name% 住在 %city%$
name 的值是"小明",city 的值是"北京"。
内部函数($调用 / [内部])
内部函数就像是可以重复使用的"代码积木"。定义一个函数后,可以在多处调用它。
1. 定义无参数的内部函数
[内部]打招呼 $发送 你好呀,很高兴见到你!$
[内部] 开头的段落不会匹配用户消息,只能被调用。2. 调用无参数函数
$调用 打招呼$
当用户触发某个词条时,可以通过 $调用 来执行内部函数。
3. 定义带参数的内部函数
[内部]计算加法[数字1 数字2] 返回 数字1, 数字2
参数写在函数名后面的方括号中,用空格分隔。
4. 调用带参数的函数
$调用 计算加法 #5#10$
参数通过 # 号传递,每个 # 后面跟一个参数值。
有等号的参数表示关键字参数:
$调用 你好 #测试#参数2=长沙市$
第一个参数是"测试"(位置参数),第二个参数 参数2 的值是"长沙市"(关键字参数)。
5. 返回值(返回)
在内部函数中,可以使用 返回 语句将结果传回给调用者:
[内部]加法[数字1 数字2] result = $计算 [数字1 + 数字2]$ 返回 result
调用:$调用 加法 #5#10$
关于接收返回值的用法和python一致,参数1,参数2,参数n... = $调用....$
6. 完整调用测试示例
调用测试词条:
调用测试 $调用 你好$ $调用 你好 #测试#参数2=长沙市$
被调用的内部函数:
[内部]你好 a = "你好世界" $发送 ±md #调用测试%a%±$
HTML 渲染($html)
$html 可以将网页或 HTML 代码渲染成图片。
1. 基本用法
a = $html 网页地址$ $发送 ±img %a%±$
不带宽高参数时,默认渲染为 800x600 的图片。
2. 指定宽高
a = $html 网页地址 1080 1080$ $发送 ±img %a%±$
3. 支持的输入类型
- 网络地址(如 https://example.com)
- 本地 HTML 文件路径(如 /网页/文件.html)
- HTML 代码文本(如
<h1>你好</h1>) - 纯文本(如"你好呀",会渲染为白底黑字)
4. 完整示例
网页图测试(.*) a = $html %括号1% 1080 1080$ $发送 ±img %a%±$
当用户发送"网页图测试https://example.com"时,机器人会将网页渲染成 1080x1080 的图片并发送。
直发按钮($直发按钮)
直发按钮是一种特殊的 Markdown 链接,用户点击后会直接在输入框填入指定内容并自动发送。这个功能是利用了QQ官机的md语法漏洞,随时失效且仅移动端能正常生效.
1. 语法
$直发按钮 显示的文字 点击后填入的内容$
2. 示例
a = $直发按钮 点我查看天气 天气查询$ $发送 ±md %a%±$
效果:在 Markdown 消息中显示"点我查看天气"按钮,用户点击后输入框会自动填入并发送"天气查询"。
3. 配合正则捕获使用
测试md([\s\S]*)#([\s\S]*) a = $直发按钮 %括号1% %括号2%$ $发送 ±md %a%±$
用户发送"测试md点我#天气查询",机器人会回复一个按钮。
流式回复($流式)
流式回复是 QQ 官机的私聊专属接口,主要服务于用户的 agent 对接,所以如果不在旧版开放平台配置私聊沙箱的话,只有机器人的实名主的 QQ 号能正常触发这个接口。
1. 语法
$流式 结束 替换 序号 stream_id 内容$
2. 示例
r1 = $流式 ±md #正在生成回答±$ sid = @%r1%#id await asyncio.sleep(1) 模拟的aiagent工作耗时 r2 = $流式 1 %sid% ...已过半$ await asyncio.sleep(1) r3 = $流式 结束 2 %sid% ..最终回答$
3. 参数说明
第一次请求默认序号为 0,后续则需要序号 +1。首次请求会返回一个 json,json 里面的 id 字段就是我们要的 stream_id。
一个指令事件只能创建一个流式集合体消息,无法创建不同的流式消息集合体多次回复同一个指令。
特别说明替换参数:在 QQ 用户端的观感上替换和默认不填(官方文档里面为 append,即添加)没啥区别,但在代码这里就有区别。上方例子则需要变成这样:
r1 = $流式 ±md #正在生成回答±$ sid = @%r1%#id await asyncio.sleep(1) 模拟的aiagent工作耗时 r2 = $流式 替换 1 %sid% #正在生成回答...已过半$ await asyncio.sleep(1) r3 = $流式 结束 2 %sid% #正在生成回答...已过半..最终回答$
就显得十分的没必要,跟个脱裤子放屁一样。
系统事件
1. 事件
和[内部]的写法一样,但目前对事件类型,即通用事件名称支持不全,所以建议使用全量事件的写法:
[事件] %event%
使用logger.debug(event)在日志中查看该事件的json数据
[事件]
logger.debug(event)bot实例
1. bot实例
获取成功连接的所有 bot 实例。
获取 bot 实例列表:bot_list = $BOT$
获取指定 bot 的实例:bot = $BOT appid/BOTQQ号$
如何使用:
测试日志 bot_list = $BOT$ bot1 = @%bot_list%#0#type bot2 = @%bot_list%#1#type bot1_u = @%bot_list%#0#bot 如果 bot1 == "ONEBOT_V11" and bot != bot1_u bot = @%bot_list%#0#bot $发送 群 907202438 7788$
bot 这个变量名赋值了 bot 实例,后面的代码就默认使用这个 bot 进行互动,单指令独立,如果需要换 bot 实例在代码调用前重新赋值就行了。例如:bot = @%bot_list%#0#bot $发送 群 907202438 7788$ bot = @%bot_list%#1#bot $发送 群 907202438 7788$
排序
排序
支持的数据结构:
- 纯列表:
[1,2,348,77,894] - 多同键字典:
[{"name": "Alice", "score": 85}, {"name": "Bob", "score": 92}, ...] - 异键字典:
[{'张三': 1}, {'李四': 9}, ...] - 嵌套字典:
[{"user": {"name": "Tom", "age": 30}}, ...]
使用示例:
$排序 %data1% 升序 None user.age \n {index}. 【{user.name}】 : {user.age}$
参数依次为:数据、排序方式(升序/降序)、取结果前几个、排序依据键、结果分割符、自定义结果。
其中分割符和自定义结果不填,即 $排序 %data1% 升序 None user.age$ 返回为原结构字典。
自定义结果中 index 代表序号,其他则为获取指定键的值。若传入的数据为异键字典,使用 key、value 作为占位符代表键值。item 为基本元素。
排序键依据用于多同键字典和嵌套字典。
若无复杂字典任务,即纯列表、异键字典,$排序 数据 序 几个$ 即可。
特殊变量一览
以下特殊变量可以在代码中直接使用(用 %变量名% 引用):
| 变量名 | 含义 |
|---|---|
| %QQ% | 发送消息的用户的 QQ 号 |
| %群号% | 当前群聊的群号 |
| %昵称% | 发送消息的用户在本群的昵称(群名片) |
| %括号1% | 正则表达式中第 1 个括号捕获的内容 |
| %括号2% | 正则表达式中第 2 个括号捕获的内容 |
| %括号N% | 以此类推,N 是括号的序号 |
| %时间+表达式% | 获取当前时间(%时间% 或 %时间%Y-%m-%d %H:%M:%S%) 无表达式则为整数时间戳 |
| %bot% | bot实例,为系统预留变量,不可随意赋值 |
| %event% | 事件数据,为系统预留变量,不可随意赋值 |
| %regex_group% | 正则匹配组,为系统预留变量,不可随意赋值 |
| %变量名% | 你自定义的任意变量 |
常见问题与注意事项
1. 多行文本赋值
当你需要给变量赋多行文本时,使用 Python 的三引号语法:
a = """第一行 第二行 第三行"""
附录
A附录A:类型速查表
±...± 支持的消息类型一览:
| 类型 | 写法 | 说明 |
|---|---|---|
| at | ±at QQ号± | @某个人 |
| md | ±md Markdown内容± | 发送 Markdown 消息 |
| img | ±img 图片地址± | 发送图片 |
| kd | ±kd 键盘JSON± | 发送键盘/按钮 |
| ptt | ±ptt 语音文件地址± | 发送语音消息 |