特殊功能#

让 AI 帮你修改#

既然世界书/预设条目已经被脚本映射为本地文件, 你显然可以让 AI 直接帮你修改世界书/预设, 你可以使用Cursor、Augment、RooCode、Cline、Claude Code、Gemini CLi 等各种 AI 编程助手.

为了让 AI 更理解配置文件的结构, 你可以前往 StageDog/tavern_sync 的 schema 和 type 文件夹下载对应的类型定义.

警告

为了破除 AI 对 NSFW 内容的道歉, 你可能需要在 AI 编程助手对应的规则提示词中添加破限. 但请注意:

  • 不要将破限发给会收集聊天信息的 AI 渠道, 避免破限被标记 (例如 claude 曾搞过破限挑战赛这样的 "钓鱼活动", 而有人真的将预设发过去了😨)

  • 检查预设有无授权问题!

内嵌提示词或外链提示词#

同步脚本对于预设或世界书条目的提示词, 支持内嵌提示词内容或外链提示词文件, 分别用内容文件字段来指定.

例如, 世界书条目===角色详情开始===只是你用来分隔其他条目的伪条目, 则完全没必要为它设置一个文件单独存放提示词, 可以将它的提示词内容直接写在配置文件中:

条目:
  - 名称: 条目 A
    ...
    文件: ./某个文件.yaml

  - 名称: ===角色详情开始===
    启用: false
    ...
    内容: ''  # 内容为空, 这个条目只是用来分隔其他条目的

  - 名称: 条目 B
    ...
    文件: ./某个文件夹/某个文件.yaml

你也许想在配置文件里写一些小条目, 但它们显然不止一行提示词, 该怎么写方便呢? 使用 |-:

条目:
  - 名称: 某个条目
    启用: false
    ...
    内容: |-  # 以下内容是原封不动的提示词内容
      第一行前面没有任何空格
      第二行
        第三行前面有 2 个空格
      第四行

也许你的提示词每行都需要开头空两格:

条目:
  - 名称: 某个条目
    启用: false
    ...
    内容: |2-
      第一行前面有 2 个空格
      第二行
        第三行前面有 4 个空格
      第四行

node tavern_sync.js pull 即默认将新条目的提示词拆分为外链提示词文件, 而 node tavern_sync.js pull --inline 则将新条目的提示词内嵌在配置文件中.
你可以通过 node tavern_sync.js pull -h 来了解更多.

外链提示词的文件位置是任意的#

外链提示词的文件位置是任意的, 你没必要拘泥于首次提取时脚本所给的文件结构.

例如, 你完全可以新建几个子文件夹, 将不同类型的提示词分类处理:

日记络络
├── 变量/
│   ├── [initvar]勿启用.yaml
│   ├── 变量更新.yaml
│   └── 变量更新强调.yaml
├── 角色/
│   ├── ...
│   └── 角色详情.yaml
├── 可选项/
├── 事件系统/
├── 特殊界面/
├── 选择框/
└── 语法规则.yaml

我们只需要在配置文件里条目的文件字段指定好对应的路径即可:

条目:
  - 名称: 变量更新
    ...
    文件: 日记络络/变量/变量更新.yaml

  - 名称: 变量更新强调
    ...
    文件: 日记络络/变量/变量更新强调.yaml

  - 名称: 角色详情
    ...
    文件: 日记络络/角色/角色详情.yaml

合集文件: 在一个文件里编写多个条目的提示词#

我们可能遇到多个条目才构成一个完整提示词结构的情况. 例如,

  • 预设中的思维链部分可能有很多选项, 而我们可能不想每个选项都存放为单独的提示词文件.

  • 世界书中的好感度阶段可能会有 "开头"、"阶段 1"、"阶段 2"、……、"结尾" 等条目, 而所有条目才构成一个完整的 YAML/JSON 结构. 为了避免格式不正确干扰 AI 的判断, 我们会想利用 Cursor 提供的 YAML/JSON 语法检查来确保格式正确. 为此它们需要存放在同一文件中.

脚本为此制作了合集文件功能, 文件名中带有合集collection的文件都被视为合集文件.

在合集文件中, 我们可以用一行 # ^条目名 指定之后部分提示词属于哪个条目:

# ^===角色阶段开始===
---
角色阶段:
  白娅:
    # ^角色阶段1
    消极自毁:
      行为指导:
        - 故意站在<user>能看到的地方,但不与<user>有任何交流或对视
        - 在课间休息时独自待在天台,用疼痛感缓解内心空虚与自责
        - 会在公共场合做些危险的举动来试探<user>的反应,如故意在楼梯上踉跄
        - 刻意以最糟糕的形象示人,不修边幅、营养不良
        - 对其他同学冷漠疏离,即使有人主动示好也保持距离
      变化倾向:
        - 在<user>注视时会不自觉地整理仪容
        - 偷偷收集<user>的照片和物品,但很快就会因愧疚而毁掉
    # ^角色阶段2
    角色阶段2的内容...
    # ^角色阶段3
    角色阶段3的内容...
# ^===角色阶段结束===
rule:
  - 角色阶段描述的是角色成长得到的当前人设,因此角色阶段中的要求必须优先于作为背景的`角色关键信息`和`角色详情`

而我们只需在配置文件对应条目的文件中让它们用这个合集文件即可:

 1条目:
 2  - 名称: ===角色阶段开始===
 3    ...
 4    文件: 呕吐内心的少女/角色阶段合集.yaml
 5
 6  - 名称: 角色阶段1
 7    ...
 8    文件: 呕吐内心的少女/角色阶段合集.yaml
 9
10  - 名称: 角色阶段2
11    ...
12    文件: 呕吐内心的少女/角色阶段合集.yaml
13
14  - 名称: 角色阶段3
15    ...
16    文件: 呕吐内心的少女/角色阶段合集.yaml
17
18  - 名称: ===角色阶段结束===
19    ...
20    文件: 呕吐内心的少女/角色阶段合集.yaml

原始文本: 在 YAML 中使用宏和提示词模板#

我们可能在 YAML/JSON 使用宏和提示词模板 EJS 语法来动态发送提示词:

 1# ^===角色阶段开始===
 2---
 3角色阶段:
 4  白娅:
 5    # ^角色阶段1
 6    <%_ if (_.inRange(getvar('stat_data.白娅.依存度'), 0, 20)) { _%>
 7    消极自毁:
 8      行为指导:
 9        - ...
10      变化倾向:
11        - ...
12    <%_ } _%>
13    # ^角色阶段2
14    <%_ if (_.inRange(getvar('stat_data.白娅.依存度'), 20, 40)) { _%>
15    渴求注视:
16      行为指导:
17        - ...
18      变化倾向:
19        - ...
20    <%_ } _%>

但这又会引起语法检查错误:

../../../../_images/ejs%E5%BC%95%E8%B5%B7%E9%94%99%E8%AF%AF.png

脚本为此制作了原始文本功能, 本地文本中所有 # :文本 在同步时都会被原封不动地转换为 文本:

 1# ^===角色阶段开始===
 2---
 3角色阶段:
 4  白娅:
 5    # ^角色阶段1
 6    # :<%_ if (_.inRange(getvar('stat_data.白娅.依存度'), 0, 20)) { _%>
 7    消极自毁:
 8      行为指导:
 9        - ...
10      变化倾向:
11        - ...
12    # :<%_ } _%>
13    # ^角色阶段2
14    # :<%_ if (_.inRange(getvar('stat_data.白娅.依存度'), 20, 40)) { _%>
15    渴求注视:
16      行为指导:
17        - ...
18      变化倾向:
19        - ...
20    # :<%_ } _%>