宏是一种动态占位符,会在文本处理时被替换为实际值。SillyTavern 在提示词、角色卡、世界书、快捷回复等处广泛使用宏。

查找可用宏

SillyTavern 为所有可用宏提供了内置文档:

  • 斜杠命令:在聊天输入栏中输入 /? macros 可显示所有已注册宏及其说明的列表。
  • 自动补全:有关输入时获取建议的详情,参见下方的宏自动补全

宏自动补全

宏自动补全会在你输入时为可用宏提供建议。它在 SillyTavern 中所有支持宏的文本字段均可工作。

输入 {{ 即可开始宏的自动补全,会显示可用宏及其参数、可能的宏标志变量简写等。

默认出现自动补全的位置:

  • 聊天用户输入框
  • 展开的编辑器(全屏文本编辑,通过文本字段旁边的“展开”按钮打开)
  • 提示词管理器编辑器

在其他字段中触发自动补全:

  • 在任意支持宏的文本字段中按 Ctrl+Space 可打开自动补全弹窗
  • 启用设置 → 自动补全设置 → 在所有宏字段中显示,可让自动补全在所有宏字段中自动出现

基础语法

宏用双花括号包裹:

{{macroName}}

宏名称不区分大小写{{User}}{{USER}}{{user}} 都解析为同一个宏。

示例:

{{user}}        // Returns the current user/persona name
{{char}}        // Returns the current character name
{{time}}        // Returns the current time
{{date}}        // Returns the current date

参数

许多宏可接受参数以自定义其行为。

空格分隔符

对于只有单个参数的宏,可用空格将宏名与参数分隔:

{{macroName argument}}

示例:

{{getvar myVariable}}
{{roll 1d20}}
{{reverse Hello World}}

双冒号分隔符

使用 :: 分隔多个参数:

{{macroName::arg1::arg2::arg3}}

示例:

{{setvar::myVariable::Hello World}}
{{random::red::green::blue}}
{{roll::2d6+3}}

空格与 :: 都是宏参数的推荐语法。

单冒号分隔符(旧版)

单个 : 也可用于引入参数,但此语法被视为旧版语法,不建议用于新内容:

{{macroName:argument}}

示例:

{{roll:1d20}}

宏定义中的空白

宏名、分隔符和参数之间的空白会被忽略,因此可以进行更具可读性的格式编排:

{{ macroName :: arg1 :: arg2 }}
{{ setvar :: myVariable :: some value }}
{{ if :: condition }}

以上写法都等价于不带额外空格的紧凑形式。

嵌套宏

宏可以嵌套在其他宏内部,内层宏会先被解析:

{{getvar::{{char}}_mood}}

此例会先解析 {{char}}(例如解析为“Alice”),再解析 {{getvar::Alice_mood}}

更多示例:

{{setvar::greeting::Hello, {{user}}!}}

设置一个内容中包含用户名的变量。

{{if {{getvar::showDetails}}}}Details here{{/if}}

此处的条件本身就是一个用于获取变量值的宏。

作用域宏

任何至少接受一个参数的宏都支持作用域语法。开始标签与结束标签之间的内容会成为该宏的最后一个参数

作用域语法

不必将最后一个参数写在行内,而是可以放在开始标签与结束标签之间:

{{macroName argument}}
  scoped content here
{{/macroName}}

结束标签在宏名前使用 / 标志:{{/macroName}}

它等价于:

{{macroName::argument::scoped content here}}

示例

用多行内容设置变量:

{{ setvar backstory }}
  This character was born in a small village
  and grew up to become a renowned scholar.
{{ /setvar }}

对作用域内容使用 reverse

{{ reverse }}
  Hello World
{{ /reverse }}

该写法返回“dlroW olleH”。

内容修剪

默认情况下,作用域内容会自动修剪:

  • 去除首尾空白
  • 去除一致的缩进(从所有行中移除首个非空行的缩进)

这样可以获得干净的格式编排:

{{ if condition }}
    # Heading
    Some content here
{{ /if }}

产出 # Heading\nSome content here(不含前导空格)。

若要保留所有空白(包括首尾换行符),请使用 # 标志。详情参见宏标志

条件宏

{{if}} 宏会根据某个值为真值或假值来条件性地渲染内容。

简单条件

{{ if description }}
  # Character Description
  {{ description }}
{{ /if }}

仅当 description 返回非空值时,才会显示标题和描述。

条件可以是:

  • 一个宏名(在无需参数时自动解析)
  • 任何来自嵌套宏的值,如 {{getvar::flag}}
  • 一个变量简写,如 .myFlag$globalFlag(参见变量简写
  • 任意你想要的文本(会根据其内容隐式判定为真值或假值)

假值:空字符串、false0offno

在条件中使用变量简写

变量简写提供了一种在条件中检查变量值的简洁方式:

{{ if .isEnabled }}
  Feature is enabled.
{{ /if }}

{{ if !$globalDisabled }}
  Not globally disabled.
{{ /if }}

有关简写记法的更多详情,参见变量简写

反向条件

在条件前加 ! 可将其取反:

{{ if !personality }}
  No personality defined for this character.
{{ /if }}

If/Else 分支

{{if}} 块内使用 {{else}} 可定义备选分支:

{{ if personality }}
  {{ personality }}
{{ else }}
  No personality defined.
{{ /if }}

另一个示例:

{{ if {{getvar::details-block}} }}
  # Details Block
  {{ getvar::details-block }}
{{ else }}
  No details currently exist.
{{ /if }}

宏标志

标志是放在开始花括号与宏名之间的特殊符号字符,用于修改宏的行为。

语法

{{!macroName}}
{{#macroName}}

标志可以组合使用:

{{!?macroName}}

标志与宏名之间允许空白:

{{ / macroName }}
{{ # macroName }}

已实现的标志

标志 名称 说明
/ 闭合块 标记作用域宏的结束标签。示例:{{/if}}
# 保留空白 阻止对作用域内容的自动修剪。

计划中的标志(尚未实现)

标志 名称 说明
! 立即 在同一段文本的其他宏之前解析此宏。
? 延迟 在同一段文本的其他宏之后解析此宏。
~ 重新求值 标记此宏以进行重新求值。
> 过滤 为此宏启用基于管道的输出过滤器。

类标志前缀运算符

变量简写语法使用前缀运算符(.$),其行为类似标志,但本身并不是标志。 详情参见变量简写一节。

保留空白标志

当需要在作用域内容中保留所有空白(包括首尾换行和缩进)时,使用 # 标志:

{{ # setvar code }}
    function hello() {
        return "world";
    }
{{ /setvar }}

如果不加 #,内容会被修剪并去除缩进。加上 # 后,所有空白都会原样保留——包括开始标签之后和结束标签之前的换行符。

注释

使用注释宏可添加不会出现在输出中的备注:

{{// This is a comment and will be removed}}

对于多行注释,使用作用域语法:

{{ // }}
  This entire block is a comment.
  It can span multiple lines.
{{ /// }}

转义宏

若要原样显示花括号而不进行宏解析,可使用反斜杠转义:

\{\{notAMacro\}\}

这会原样输出 {{notAMacro}} 作为纯文本。

变量简写

变量简写为常见变量操作提供了简洁的语法。使用 . 表示局部变量,使用 $ 表示全局变量。

变量简写前缀

前缀 名称 说明
. 局部变量 局部变量操作的简写。示例:{{.myvar}}
$ 全局变量 全局变量操作的简写。示例:{{$myvar}}

这些前缀运算符必须放在变量名紧前、任意可选出现的宏标志之后。它们不被视为宏标志,而更多是“正在插入一个变量简写(而非按名调用宏)”的指示符。前缀运算符本身不是变量名的一部分,而是修改变量访问方式的修饰符。

变量名

变量名遵循与宏标识符相同的规则:以字母开头,后跟字母、数字、下划线或连字符。最后一个字符不允许是下划线或连字符。

{{.my-var}}       // Valid
{{.my_var}}       // Valid
{{.myVar123}}     // Valid

如果你的变量具有不符合标准规则的标识符,则必须使用完整的变量宏语法(如 {{getvar::my§var----}}),或者重命名/迁移你的变量值。

值中的嵌套宏

变量值中可以包含嵌套宏:

{{.greeting = Hello, {{user}}!}}

解析为一个内部保存了 Hello, User! 的变量。(假设 {{user}} 名为“User”)

空白处理

运算符两侧允许空白:

{{ .myvar = spaced value }}
{{ .counter ++ }}

变量简写运算符

以下运算符可与变量简写配合使用。每个运算符遵循 {{.varName operator value}}{{$varName operator value}} 的形式。

运算符 名称 示例 说明
(无) 获取 {{.myvar}} 返回变量值
= 设置 {{.myvar = value}} 将变量设置为某个值,不返回任何内容
++ 自增 {{.counter++}} 加 1,返回新值
-- 自减 {{.counter--}} 减 1,返回新值
+= {{.score += 10}} 向变量加上某值(数值或字符串拼接),不返回任何内容
-= {{.health -= 5}} 从变量中减去某值(仅数值),不返回任何内容
|| 逻辑或 {{.name || Guest}} 当变量为假值时返回回退值
?? 空值合并 {{.name ?? Guest}} 仅当变量未定义时返回回退值
||= 逻辑或赋值 {{.name ||= Guest}} 当变量为假值时设置该值,返回新值
??= 空值合并赋值 {{.name ??= Guest}} 仅当变量未定义时设置该值,返回新值
== 相等 {{.status == active}} 比较值,返回 "true""false"
!= 不相等 {{.status != active}} 比较值,不相等时返回 "true"
> 大于 {{.score > 50}} 变量大于指定值时返回 "true"
>= 大于或等于 {{.level >= 10}} 变量大于或等于指定值时返回 "true"
< 小于 {{.health < 20}} 变量小于指定值时返回 "true"
<= 小于或等于 {{.health <= 0}} 变量小于或等于指定值时返回 "true"

获取变量

使用简单前缀获取变量值:

{{.myvar}}       // Get local variable "myvar"
{{$myvar}}       // Get global variable "myvar"

等价于 {{getvar::myvar}}{{getglobalvar::myvar}}

设置变量

使用 = 运算符设置变量值:

{{ .myvar = Hello World }}     // Set local variable
{{ $myvar = Some value }}      // Set global variable

等价于 {{setvar::myvar::Hello World}}{{setglobalvar::myvar::Hello World}}。返回空字符串。

自增

使用 ++ 将数值变量加 1:

{{.counter++}}    // Increment local variable, returns new value
{{$counter++}}    // Increment global variable, returns new value

等价于 {{incvar counter}}{{incglobalvar counter}}。返回自增后的新值。

自减

使用 -- 将数值变量减 1:

{{.counter--}}    // Decrement local variable, returns new value
{{$counter--}}    // Decrement global variable, returns new value

等价于 {{decvar counter}}{{decglobalvar counter}}。返回自减后的新值。

使用 += 向变量加上一个数值:

{{.score += 10}}     // Add 10 to local variable
{{$total += 5}}      // Add 5 to global variable

等价于 {{addvar::score::10}}{{addglobalvar::total::5}}。返回空字符串。

加运算符还支持在两者都不是数字时,将字符串追加到现有字符串变量:

{{.myvar += {{noop}} | Second block}}   // Resolves to "Content | Second block" when the variable before was "Content".
                                        // Use `{{noop}}` to be able to add whitespaces, that otherwise would be trimmed automatically.

使用 -= 从变量中减去一个数值:

{{.health -= 10}}    // Subtract 10 from local variable
{{$points -= 5}}     // Subtract 5 from global variable

等价于 {{addvar::score::10}}{{addglobalvar::total::5}},但使用取负/取反后的数字。返回空字符串。 如果该值不是有效数字,会记录一条警告,变量保持不变。

逻辑或

使用 || 在变量为假值(空字符串、0false)时提供回退值:

{{.name || Anonymous}}     // Returns "Anonymous" if .name is empty or falsy
{{$setting || default}}    // Returns "default" if $setting is falsy

变量为真值时返回变量值,否则返回回退值。回退值仅在需要时才会求值(惰性求值)。

空值合并

使用 ?? 仅在变量不存在时提供回退值:

{{.name ?? Guest}}         // Returns "Guest" only if .name is not defined
{{$config ?? default}}     // Returns "default" only if $config doesn't exist

|| 不同,只要变量存在,即使其为假值(空字符串、0false),也会返回变量值。回退值仅在需要时才会求值(惰性求值)。

逻辑或赋值

使用 ||= 仅在变量当前为假值时,将其设置为某个值:

{{.name ||= Anonymous}}    // Sets and returns "Anonymous" if .name is falsy
{{$count ||= 0}}           // Sets and returns "0" if $count is falsy

如果变量已为真值,则原样返回当前值而不作修改。返回最终值(既有的或新设置的)。

空值合并赋值

使用 ??= 仅在变量不存在时,将其设置为某个值:

{{.name ??= Guest}}        // Sets and returns "Guest" only if .name is undefined
{{$config ??= default}}    // Sets and returns "default" only if $config doesn't exist

||= 不同,如果变量已存在,这会保留假值(空字符串、0false)。返回最终值(既有的或新设置的)。

相等

使用 == 将变量值与另一个值进行比较:

{{.status == active}}      // Returns "true" if .status equals "active", otherwise "false"
{{$mode == dark}}          // Returns "true" if $mode equals "dark", otherwise "false"

执行字符串比较,返回字面字符串 "true""false"。 将不存在的变量、null 变量和空变量视为相同。

适用于 {{if}} 条件:

{{if {{.status == active}} }}Active mode{{/if}}

不相等

使用 != 比较变量值与另一个值是否不相等:

{{.status != inactive}}    // Returns "true" if .status is NOT "inactive", otherwise "false"
{{$mode != light}}         // Returns "true" if $mode is NOT "light", otherwise "false"

执行字符串比较,值不同时返回 "true",相等时返回 "false"。 将不存在的变量、null 变量和空变量视为相同。

适用于 {{if}} 条件:

{{if {{.status != disabled}} }}Feature enabled{{/if}}

大于

使用 > 检查变量的数值是否大于另一个值:

{{.score > 50}}        // Returns "true" if .score is greater than 50
{{$level > 5}}         // Returns "true" if $level is greater than 5

执行数值比较,返回字面字符串 "true""false"

适用于 {{if}} 条件:

{{if {{.score > 100}} }}High score!{{/if}}

大于或等于

使用 >= 检查变量的数值是否大于或等于另一个值:

{{.level >= 10}}       // Returns "true" if .level is at least 10
{{$points >= 100}}     // Returns "true" if $points is 100 or more

执行数值比较,返回字面字符串 "true""false"

适用于 {{if}} 条件:

{{if {{$level >= 10}} }}Unlocked advanced features{{/if}}

小于

使用 < 检查变量的数值是否小于另一个值:

{{.health < 20}}       // Returns "true" if .health is below 20
{{$timer < 0}}         // Returns "true" if $timer is negative

执行数值比较,返回字面字符串 "true""false"

适用于 {{if}} 条件:

{{if {{.health < 20}} }}Low health warning!{{/if}}

小于或等于

使用 <= 检查变量的数值是否小于或等于另一个值:

{{.health <= 0}}       // Returns "true" if .health is 0 or below
{{$attempts <= 3}}     // Returns "true" if $attempts is 3 or fewer

执行数值比较,返回字面字符串 "true""false"

适用于 {{if}} 条件:

{{if {{.health <= 0}} }}Game over{{/if}}

旧版语法

出于向后兼容,尖括号标记仍然受支持:

旧版 等价宏
<USER> {{user}}
<BOT> {{char}}
<CHAR> {{char}}
<GROUP> {{group}}
<CHARIFNOTGROUP> {{charIfNotGroup}}

这些会在处理过程中自动转换为对应的宏等价形式。

注意: 不推荐使用旧版语法。对于新内容,请改用等价的 {{macro}} 语法。

按类别划分的常用宏

名称与参与者

说明
{{user}} 当前用户/人格名称
{{char}} 当前角色名称
{{group}} 以逗号分隔的群组成员名称列表(含被禁言成员),或在单聊中为角色名称
{{groupNotMuted}} 以逗号分隔的群组成员名称列表,不含被禁言的成员
{{charIfNotGroup}} 角色名称(在群组中为空)
{{notChar}} 除当前发言者外所有参与者、以逗号分隔的列表

角色卡与人格字段

说明
{{description}} 角色描述
{{personality}} 角色人格
{{scenario}} 角色场景
{{persona}} 用户人格描述
{{charPrompt}} 角色的主提示词覆盖
{{charInstruction}} 角色的历史后指令覆盖
{{charDepthPrompt}} 角色的 @ 深度备注
{{charCreatorNotes}} 来自角色卡的创作者备注
{{charVersion}} 角色的版本号
{{mesExamples}} 角色的对话示例,已为指令模式格式化
{{mesExamplesRaw}} 来自角色卡的未格式化对话示例
{{charFirstMessage}} 角色的开场白。接受用于备选开场白的可选索引,例如 {{charFirstMessage::1}}
{{original}} 用于角色提示词覆盖中替换的原始消息内容

聊天历史与消息

说明
{{lastMessage}} 对话中的最后一条消息
{{lastMessageId}} 对话中最后一条消息的索引
{{lastUserMessage}} 对话中的最后一条用户消息
{{lastCharMessage}} 对话中的最后一条角色/机器人消息
{{firstIncludedMessageId}} 当前上下文中包含的首条消息的索引
{{firstDisplayedMessageId}} 对话中显示的首条消息的索引
{{lastSwipeId}} 最后一条消息最后一次滚动的 1 基索引
{{currentSwipeId}} 当前滚动的 1 基索引
{{allChatRange}} 提供整段对话的范围(例如 0-{{lastMessageId}}),适用于接受消息范围的命令
{{summary}} 来自“摘要”扩展的最新对话摘要(可用时)

时间与日期

说明
{{time}} 当前本地时间
{{time::UTC±(offset)}} 带 UTC 偏移量的时间
{{date}} 当前本地日期(短格式)
{{weekday}} 当前星期几
{{isotime}} 当前时间,HH:mm 格式
{{isodate}} 当前日期,YYYY-MM-DD 格式
{{datetimeformat::format}} 自定义格式化的日期/时间(例如 YYYY-MM-DD HH:mm:ss
{{idleDuration}} 距离上一条用户消息的人读化时长
{{timeDiff::left::right}} 两个时间之间的人读化差值

变量

说明
{{getvar::name}} 获取局部变量值
{{setvar::name::value}} 设置局部变量
{{addvar::name::value}} 向局部变量增加值(数值或字符串追加)
{{incvar::name}} 局部变量加 1 并返回新值
{{decvar::name}} 局部变量减 1 并返回新值
{{hasvar::name}} 检查局部变量是否存在(返回“true”或“false”)
{{deletevar::name}} 删除局部变量
{{getglobalvar::name}} 获取全局变量值
{{setglobalvar::name::value}} 设置全局变量
{{addglobalvar::name::value}} 向全局变量增加值(数值或字符串追加)
{{incglobalvar::name}} 全局变量加 1 并返回新值
{{decglobalvar::name}} 全局变量减 1 并返回新值
{{hasglobalvar::name}} 检查全局变量是否存在(返回“true”或“false”)
{{deleteglobalvar::name}} 删除全局变量

随机化

说明
{{random::a::b::c}} 随机选择(每次都重新抽取)
{{pick::a::b::c}} 稳定的随机选择(在同一对话和位置上一致)。可使用 /reroll-pick 命令重新抽取
{{roll::1d20}} 使用 droll 语法的掷骰子

运行时状态

说明
{{maxPrompt}} 最大提示词上下文大小(提示词 token = 上下文 token - 回复 token)
{{maxContextTokens}} 当前生成设置下的最大上下文 token 数
{{maxResponseTokens}} 当前生成设置下的最大回复 token 数
{{model}} 当前所选 API 的模型名称
{{isMobile}} 在移动环境中运行时为“true”,否则为“false”
{{lastGenerationType}} 上一次排队的生成请求的类型(例如“normal”、“impersonate”、“regenerate”、“quiet”、“swipe”、“continue”)
{{hasExtension::name}} 检查某扩展是否处于活动状态(返回“true”或“false”)。按扩展名匹配,不区分大小写

提示词模板

说明
{{systemPrompt}} 活动的系统提示词文本(可被角色覆盖)
{{defaultSystemPrompt}} 默认系统提示词
{{authorsNote}} 作者备注的内容
{{charAuthorsNote}} 角色作者备注的内容
{{defaultAuthorsNote}} 默认作者备注的内容
{{instructStoryStringPrefix}} 指令故事字符串前缀
{{instructStoryStringSuffix}} 指令故事字符串后缀
{{instructUserPrefix}} 指令输入/用户前缀序列
{{instructUserSuffix}} 指令输入/用户后缀序列
{{instructAssistantPrefix}} 指令输出/助手前缀序列
{{instructAssistantSuffix}} 指令输出/助手后缀序列
{{instructSeparator}} 指令分隔符序列
{{instructSystemPrefix}} 指令系统前缀序列
{{instructSystemSuffix}} 指令系统后缀序列
{{instructFirstAssistantPrefix}} 指令首个助手/输出前缀序列
{{instructLastAssistantPrefix}} 指令末个助手/输出前缀序列
{{instructFirstUserPrefix}} 指令首个用户/输入前缀序列
{{instructLastUserPrefix}} 指令末个用户/输入前缀序列
{{instructStop}} 指令停止序列
{{instructUserFiller}} 指令用户对齐填充
{{instructSystemInstructionPrefix}} 指令系统指令前缀序列
{{chatSeparator}} 文本补全提示词中对话示例块之间的分隔符
{{chatStart}} 文本补全提示词中的对话起始标记
{{reasoningPrefix}} 用于推理区块之前的字符串前缀
{{reasoningSuffix}} 用于推理区块之后的字符串后缀
{{reasoningSeparator}} 内容与回复之间的分隔符
{{charPrefix}} 角色的正向图像生成提示词前缀
{{charNegativePrefix}} 角色的负向图像生成提示词前缀

实用工具

说明
{{newline}} 插入换行符
{{newline::count}} 插入多个换行符
{{space}} 插入空格字符
{{space::count}} 插入多个空格
{{noop}} 不执行任何操作,产出空字符串
{{trim}} 移除周围的换行符
{{reverse::text}} 反转字符串
{{input}} 当前聊天输入栏的内容
{{banned::word}} 为文本补全后端禁用某个词
{{outlet::key}} 返回给定出口键对应的世界书出口提示词