Appearance
7. 进阶:变量、变量模式、消息规则与表达式
引
首先,什么是变量?
变量可以看作一个占位符,可以存在于各种提示词中、消息规则的替换部分,在具体运行时会将这个占位符替换为变量的值。
什么是表达式?
表达式包括条件判断和条件触发两种,分别用于 “检测某个条件是否满足,满足时替换为A,不满足时替换为B”(判断) 和 “当某个条件变成被满足时,替换为A”(触发) 两种情况。
什么是消息规则?
消息规则就是按照一定的规则(正则表达式)将消息原文在展示之前进行查找和替换的工具。
注意:用
{{}}包围的是变量/表达式,因此正常提示词请不要包含这种大括号模式。
1. 提示词
1.1. 提示词中的变量
在旧版中,大家可能就用过 {{User}} 这样的变量,用来代表当前身份的名称。
例如,你的当前使用身份名称是 透明酱,那么提示词里(摘自丰川祥子(同桌的你))
便利店的白炽灯光从玻璃门里渗出来,把她的影子拉得很长。她看了一眼手机,{{user}}的消息就亮在锁屏上。就会被替换为:
便利店的白炽灯光从玻璃门里渗出来,把她的影子拉得很长。她看了一眼手机,透明酱的消息就亮在锁屏上。那对于新版,变量包括:
| 变量 | 含义 |
|---|---|
{{User}} | 当前身份名称 |
{{Target}} | 当前对话目标;私聊里是用户身份名称,群聊里是其它所有成员名称 |
{{DateTime}} | 当前日期时间 |
{{DayOfWeek}} | 当前星期 |
{{Language}} | 当前语言 |
{{HasLongTermMemory}} | 当前会话是否已有长期记忆 |
{{HasKnowledge}} | 是否有知识库 |
{{KnowledgeBaseCount}} | 知识库数量 |
{{KnowledgeEntryTitles}} | 知识库标题列表 |
自定义变量 {{...}} | 你自己在变量模式中定义的变量 |
这些变量可用于:人格提示词、群聊提示词、群聊 System AI 提示词
但注意,群聊 System AI 提示词 不支持 {{HasKnowledge}}, {{KnowledgeBaseCount}}, {{KnowledgeEntryTitles}} 这三个变量,因此具体运行时会认为 {{HasKnowledge}} = false, {{KnowledgeBaseCount}} = 0, {{KnowledgeEntryTitles}} = (空)
1.2. 提示词中的表达式
有了变量,我们就能实现一些更加高级的功能。
例子
举个栗子,以软件自带的人格 透明酱(软件助手) 为例:
{{if HasKnowledge}}
注意:询问软件相关问题时,请 **必须先调用search_knowledge工具** 再回答问题!
知识库中含有的条目有:
{{KnowledgeEntryTitles}}
{{else}}
注意:你现在无法调用工具查询文档,在用户询问软件相关问题时,请告诉用户将“软件内置帮助”这个知识库挂载给你,这样你才能根据帮助文档回答用户的问题!
{{end}}这一段提示词表示,当透明酱挂载了知识库时,这段提示词会变成:
注意:询问软件相关问题时,请 **必须先调用search_knowledge工具** 再回答问题!
知识库中含有的条目有:
- 条目 A
- 条目 B
- ...(省略)而如果你将知识库从人格设置里删除后,提示词会变成:
注意:你现在无法调用工具查询文档,在用户询问软件相关问题时,请告诉用户将“软件内置帮助”这个知识库挂载给你,这样你才能根据帮助文档回答用户的问题!这样我们就通过 条件判断 语句,实现了动态的提示词。
语法
那上面是什么原理呢,需要注意 {{if ...}}/{{elseif ...}}/{{else}}/{{end}} 这些并不是变量而是条件表达式。
一个条件表达式必须以 {{if ...}} 开头,以 {{end}} 结尾,中间可以加入 {{elseif ...}}/{{else}} 表示更复杂的条件关系。
表达式里支持的运算符包括:
| 运算符 | 含义 |
|---|---|
! | 取反 |
&& | 逻辑与 |
|| | 逻辑或 |
== | 等于 |
!= | 不等于 |
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
() | 括号 |
| 值 | 含义 |
|---|---|
true | 布尔值:真 |
false | 布尔值:假 |
null | 空 |
例如:{{if affection==100}}当前好感度为100{{elseif affection>=50}}当前好感度大于等于50{{else}}当前好感度小于50{{end}} 实现了在不同好感度(affection)显示不同提示词。
并且表达式也支持嵌套,例如 {{if phase==1}}当前为阶段1{{else}}{{if affection==100}}当前为阶段2,好感度为100{{elseif affection>=50}}当前为阶段2,好感度大于等于50{{else}}当前为阶段2,好感度小于50{{end}}{{end}} 这样好感度只会在阶段2出现。
2. 消息规则
本节为进阶内容,可能较难
前置知识(理解消息规则需要掌握):正则表达式,需要先大致掌握这一知识后才能写出消息规则,可以自行搜索、阅读教程学习或者问AI学习
2.1 前言
在上面的例子中,都是直接动态改变提示词,但这其实是很不推荐的,因为第一,如果将好感度、阶段这些变量是随聊天发展动态改变的,放到会话历史中显得更合理,也方便LLM了解不同历史位置的具体值;
第二,如果每次提示词都改变的话将无法利用LLM的缓存(尤其是在提示词中加入当前时间这类永远变化的变量),换句话说每次都必须重新计算一遍前面的文本才能开始生成,并且缓存输入价格通常是无缓存输入的 1/10,改变提示词也会导致价格上升。
因此我们可以通过消息规则来改写原始消息,由此可以实现非常自由灵活的功能。
2.1.1 如何改变变量?
另外,前面我们提到的变量中有一栏是自定义变量,通过聊天设定中的变量功能,我们只是声明了一个变量,但我们总不能总是自己手动修改变量吧,那样太无趣了(当然一些变量例如布尔开关类型也是可以通过手动修改从而实现不同效果的)。
要动态地改变变量:
第一种方式,也是最简单的方式,就是使用群聊,然后打开
system AI 修改变量开关,在system AI的提示词中详细介绍每个变量的含义,以及教会AI应该怎么修改、在什么时候修改变量。这样在群聊中对话时,system AI在选人和输出旁白的同时还会根据你的提示词来动态改变变量。
当然缺点是私聊里用不了,并且你每次对话可能都要多一次AI请求,成本可能上升;同时system AI不会知道角色的设定,它只是阅读你们的聊天记录而没有角色的经历,这可以说公正,但你也可能会想是否system AI决定的好感值不一定能代表角色AI的感受?所以还有第二种可以在私聊中使用的方式就是使用消息规则,让一个AI在一次请求中输出一些特殊标记,例如
【好感+5】(就像我们之前提到过的【微笑】),让消息规则去搜索匹配这些标记,然后通过set语句触发变量的变化。
2.2. 消息来源和目标通道
消息来源(发送者)即指定这条规则会对哪个通道的消息进行处理:
- 用户消息:自己发送的消息
- 角色消息:AI角色发送的消息
- system 消息:群聊 system AI 发送的消息
消息通道(查看者)指这条消息在给谁看的时候用这条规则处理,可以让一条消息在不同地方里看起来不一样:
- 用户通道:给用户看的时候(即在界面上显示)
- 角色通道:给AI角色看的时候(即发送给LLM的文本)
- system 通道:给system AI看的时候(即发送给system AI的文本)
- 语音通道:执行语音生成时的文本(例如可以用于去除内心独白、去除特殊符号、将发音错误的词用其它词替换等)
2.3. 消息规则中的变量
| 变量 | 含义 |
|---|---|
{{MessageDateTime}} | 这条消息的日期时间 |
{{MessageDate}} | 这条消息的日期 |
{{MessageTime}} | 这条消息的时分 |
{{MessageDayOfWeek}} | 这条消息发送时对应的星期 |
{{SenderName}} | 这条消息的发送者名称 |
{{ReaderName}} | 当前读取这条消息的对象的名称 |
{{Random}} | 范围在 0~1 的伪随机值 |
{{Match0}}/$0 | 正则整段命中 |
{{Match1}}/$1 | 第 1 个捕获组 |
{{Match2}}/$2 | 第 2 个捕获组 |
自定义变量 {{...}} 等 | 这条消息创建时的该群聊变量值 |
{{Match?}}/$?的区别:{{Match?}}相当于一个变量,可以用在{{if SenderName==Match1}}等等这类地方,或者直接写{{Match1}}就相当于$1;而$?是正则的替换语法,可以直接被替换为捕获的内容。
其中有一个特殊的变量 ReaderName,代指当前阅读这条消息的角色的名称,这在一些群聊中构造信息差非常好用,例如我们可以用消息规则 {{if ReaderName==SenderName}}$0{{end}} 来限制消息的一部分只能被消息的发送者看见,例如使用消息规则限制括号或者斜体内的思考内容只有角色本人能看见,其它角色只能看见角色的发言,而看不见其心里活动,这在需要逻辑推理的群聊、或者一些刻意构造信息差的时候可能会有妙用。
或者当然也可以 {{if ReaderName=="千早爱音"}}...{{end}} 这样中间 ... 的部分只有名字为 千早爱音 的角色才能看见。同时,由于提示词注入中也有这个变量,我们可以利用这一原理设计部分提示词注入是只有 千早爱音 能看见的,或者反之只有 千早爱音 看不见,这样就形成了信息差。
2.4. 消息规则中的表达式
| 表达式 | 含义 |
|---|---|
floor(x) | 对数值 x 向下取整 |
ceil(x) | 对数值 x 向上取整 |
round(x) | 对数值 x 四舍五入 |
RandomInt(min, max) | 等于 floor(Random * (max - min + 1) + min),因此多次调用并非独立结果 |
2.5. 消息规则中的语句
if语句
{{if 表达式}}...{{end}}是在条件满足时触发的。
例如{{if affection >= 50}}...{{end}}代表只有在满足条件好感度(affection)>=50时才会对内部渲染和执行。when语句
{{when 表达式}}...{{end}}是在变量变化时触发的。
例如{{when affection}}...{{end}}代表只有在好感度(affection)变化时 才会对内部渲染和执行。expr语句
{{expr 表达式}}是代表渲染一个表达式的值。
我们通常{{affection}}这样是渲染一个变量的值,而{{affection * 2}}这是错误的语法,我们要渲染表达式必须使用expr语句,即{{expr affection * 2}}。set语句
{{set 变量=表达式}}是赋值语句,例如{{set affection=affection+5}}相当于把好感度增加了5,并且结合正则表达式的捕获组变量,我们可以用【好感度\+(\d+)】->{{set affection=affection+Match1}}这样由AI的消息内容决定好感度的增加值。command命令 只包含两种:
{{command stop}}打断AI请求,阻止AI继续输出{{command delete}}从数据库中完全删除当前消息(而不只是不可见)- 我们可以将两个命令结合起来
{{command stop}}{{command delete}}代表遇到某个条件时就停止输出,同时删除这条消息及其后续所有消息。
2.6. 消息规则:调试
在消息中可以对消息右键/左滑弹出菜单,点击 调试,即可查看这条消息在不同通道、不同读者眼中的文本
3. 例子
可能有些概念不是很好理解,那我们来举一些具体实用的例子:
- 在每条消息前加入发送时的现实时间,让AI能掌握现实时间
^ -> [{{MessageDateTime}}]
通道选择:角色通道
解析:
^代表消息的起始位置,相当于在消息起始处增加[2026-04-20 19:46]这样表示时间的文本
- 限制括号内思考只有发送者本身能看见(通常可用于猜疑推理之类的群聊):
([^)]*) -> {{if SenderName==ReaderName}}$0{{end}}
消息来源:角色消息
通道选择:角色通道
解析:
[^)]代表除了中文右括号以外的所有字符,*代表零个或多个,整体合起来就匹配中文括号以及内部的所有内容。
替换表达式限制了只有 发送者(SenderName) 等于(==) 查看者(ReaderName) 时,才显示这部分内容($0相当于我们匹配到的所有内容,替换回去相当于不变);对于其它角色而言由于条件不匹配这部分就会直接变成空字符串,相当于不可见。
- 增加自定义指令
/save([\s\S]*)$ ->
$1
system: 现在请直接输出当前会话的所有内容的完整详细总结消息来源:用户消息
通道选择:角色通道
解析:
([\s\S]*)代表匹配并捕获/save到消息结尾($)的所有任意字符,$1代表这个小括号捕获的内容,替换后相当于再原有消息的末尾增加了一条 system 消息要求执行总结。
- 将模型输出的括号消息转换为斜体
(?<!\*)((.*?))(?!\*) -> *$1*
消息来源:角色消息
通道选择:用户通道,角色通道(可选,选择角色通道将在下次请求中将斜体内容也返回给模型,可以使模型学会将括号内容变为斜体)
解析:
(?<!\*)代表前面不存在*,(?!\*)代表后面不存在*,((.*?))代表匹配并捕获中间的中文括号及其内部内容,*$1*代表将捕获的内容加上*包围(变为斜体),并再用空格包围(避免斜体失效)
- 将列表转换为对话选项
- (.+) -> - [$1](rengeguan://chat/send?text=$1)
消息来源:角色消息
通道选择:用户通道
并且在提示词中加入(不一定最好,可以自行优化):
【选项】
在每次输出最后**必须**额外增加一条选项消息,根据当前剧情发展给{{User}}接下来的动作语言等提供1~4个选项,人称必须使用{{User}}的角度(在选项部分中,用“我”代指{{User}},用“你”代指你的身份),可使用中文括号表动作,格式如下:
- 选项内容1
- 选项内容2解析:
[$1](rengeguan://chat/send?text=$1)是一种特殊的链接,在会话/嘎啦给木模式中会变成选项形式,点击后将直接发送对应消息
- 变量设置
【好感度上升】 -> $0{{set affection=affection+5}}【好感度下降】 -> $0{{set affection=affection-5}}
或者更复杂:【好感度上升】 -> $0{{if affection>=80}}{{set affection=affection+5}}{{else}}{{set affection=affection+10}}{{end}}(代表当好感度大于等于80时每次好感增加5,否则每次增加10)
或者加入随机数:【好感度上升】 -> $0{{set affection=affection+5*Random+5}}(代表随机增加好感度 5~10)
或者根据模型设置的值:【好感度=(\d+)】 -> $0{{set affection=Match1}}(指当遇到【好感度=10】时设置当前好感度为10)【好感度([+-])=(\d+)】 -> $0{{if Match1=="+"}}{{set affection=affection+Match2}}{{else}}{{set affection=affection-Match2}}(指当遇到【好感度+=5】这样的内容时将当前好感度增加5,遇到【好感度-=5】这样的内容时将当前好感度减少5)
消息来源:角色消息
通道选择:用户通道
解析:是否包含
$0取决于你是否希望这个设置好感度的文本显示出来给用户查看。
- 在每次发送消息后方显示好感度
$ ->
*当前好感度:{{affection}}*消息来源:用户消息
通道选择:用户通道, 角色通道(取决于是否在UI上展示,和是否每轮发送给AI提醒当前的好感度)
解析:选择
角色通道相当于在每次会话后插入一段提示词给AI提示当前状态的好感度,选择用户通道代表每次用户发送消息后会在后面以斜体显示当前好感度
- 随机事件
$ ->
{{if phase==2}}
{{if Random<0.3}}(触发事件1的提示词){{else}}(触发事件2的提示词){{end}}{{end}}消息来源:用户消息
通道选择:角色通道(取决于是否在UI上展示,和是否每轮发送给AI提醒当前的好感度)
解析:代表如果当前阶段(
phase)等于2时,有30%概率触发事件A,70%概率触发事件B,而触发事件相当于插入一段提示词
注意:为了保持稳定,同一条消息中
Random变量的值是相同且稳定的;它基于这条消息自己的 ID 计算,因此发送当下与之后重新读取历史时会保持一致。若需要整数随机,可用{{expr RandomInt(1, 6)}}或{{set dice=RandomInt(1, 6)}}。
- 好感度事件
需要至少两个消息规则,以及 affection(好感度,数值类型), affection_event(好感度事件1,布尔类型,默认为false)
$->{{if affection>=80}}{{set affection_event=true}}{{end}}消息来源:角色消息
通道选择:用户通道$->{{when affection_event==true}}\n\nsystem: 这里写一些好感度达到80时触发的提示词,例如特殊剧情特殊路线等等{{end}}消息来源:用户消息
通道选择:角色通道
解析:第一条规则是在好感度达到
80时将好感度事件设置为true第二条规则是在触发好感度事件时,在用户消息下方注入特殊的提示词,以触发对应事件 而when是条件触发语句,只有在affection_event变化时才会触发,后续即使好感度始终超过80,affection_event也会一直为true,这条提示词也只会触发一次。
- 语音处理
消息来源:角色通道
通道选择:语音通道
- 去除特殊符号:
[^a-zA-Z0-9\u4e00-\u9fff\u3000-\u303f\uff00-\uffef\s.,!?;:'"()\-/@]-> (空) - 去除括号的独白内容:
[((].*?[))]-> (空) - 去除斜体独白内容:
\*.*?\*-> (空) - 纠正一些特殊的词语的读音:例如(设置不区分大小写)
MyGO->my go,Tomorin->偷摸零等等