动态 AI 人格切换
做几个按钮,点一下就能切换 AI 的人格、说话风格或语言。用「告诉 AI」和「停止告诉 AI」动态改变 AI 的系统提示词——不需要重新开会话,对话中途就能无缝切换。
你要做的东西
一个嵌入在聊天里的人格切换器:
- 三种模式——普通叙述者、喜剧模式、恐怖模式
- 一键切换——点按钮就能切换 AI 的说话风格,立刻生效
- 视觉反馈——当前激活的模式按钮高亮显示,玩家一眼就知道现在是什么模式
- 无缝过渡——切换时不会中断对话,AI 的下一段回复就会用新风格
原理
Yumina 的行为系统有两个强大的动作:「告诉 AI」和「停止告诉 AI」。
- 告诉 AI(
inject-directive)—— 往 AI 的系统提示词里注入一段指令。只要这段指令还在,AI 每次回复时都会看到它、遵守它。你可以指定它出现在提示词的哪个位置、是否永久保留、多少回合后自动消失。 - 停止告诉 AI(
remove-directive)—— 通过指令 ID 把之前注入的指令移除。一旦移除,AI 就不再看到那段指令了。
用这两个动作配合,我们可以做到:
玩家点击「喜剧模式」按钮
→ 行为触发:先移除旧的人格指令(如果有)
→ 再注入新的喜剧风格指令
→ AI 的系统提示词里多了一段:"用幽默搞笑的口吻叙述..."
→ 下一次 AI 回复就会变成搞笑风格和知识条目的区别是什么? 知识条目(启用知识条目/禁用知识条目)适合大段的世界观设定。而「告诉 AI」注入的指令更轻量、更灵活——它不是条目,而是直接插在系统提示词里的一小段文字。适合短小的风格指令、临时规则、一次性提示。两者可以配合使用。
一步步来
第 1 步:创建变量
我们需要一个变量来追踪当前激活的模式。消息渲染器会读它来决定哪个按钮高亮。
编辑器 → 左侧边栏 → 变量 标签页 → 点击「添加变量」
| 字段 | 填什么 | 为什么这样填 |
|---|---|---|
| 显示名称 | 当前模式 | 给你自己看的,方便识别 |
| ID | current_mode | 行为和消息渲染器用这个 ID 来读写 |
| 类型 | 字符串 | 因为值是文字("normal"、"comedy"、"horror") |
| 默认值 | normal | 新会话从普通模式开始 |
| 分类 | 自定义 | 人格系统专用分类 |
| 行为规则 | 不要修改这个变量。它由玩家的 UI 按钮控制。 | 告诉 AI 不要自己改这个变量——只有玩家按钮能改 |
第 2 步:创建行为
我们需要 3 条行为——每种模式一条。每条行为的逻辑是:先移除旧指令 → 注入新指令 → 更新变量 → 通知玩家。
编辑器 → 行为 标签页 → 逐个添加行为
行为 1:切换到喜剧模式
WHEN(什么时候触发):
| 字段 | 填什么 | 为什么这样填 |
|---|---|---|
| 触发器类型 | 动作 | 当代码调用 executeAction("mode-comedy") 时触发 |
| 动作 ID | mode-comedy | 消息渲染器里的按钮会调用这个 ID |
DO(做什么):
按顺序添加以下动作:
| # | 动作类型 | 设置 | 作用 |
|---|---|---|---|
| 1 | 停止告诉 AI | 指令 ID:personality-override | 先移除之前注入的人格指令(如果有的话)。如果没有,什么也不会发生,不会报错 |
| 2 | 告诉 AI | 指令 ID:personality-override,内容见下方,位置:角色之后 | 注入喜剧风格指令 |
| 3 | 修改变量 | current_mode 设为 comedy | 更新变量,让渲染器知道当前模式 |
| 4 | 显示通知 | 消息:已切换到喜剧模式,样式:info | 给玩家一个视觉反馈 |
「告诉 AI」的指令内容:
[叙述风格:喜剧模式]
从现在开始,用幽默搞笑的口吻叙述一切。你可以:
- 加入夸张的比喻和荒诞的类比
- 偶尔打破第四面墙,对读者说悄悄话
- 让NPC说出不合时宜但好笑的台词
- 用轻松的语气描述严肃的场景,制造反差幽默
保持故事推进,不要只是讲笑话。幽默应该融入叙述,而不是取代叙述。为什么先「停止告诉 AI」再「告诉 AI」? 因为两条指令用的是同一个 ID(
personality-override)。如果玩家从恐怖模式切换到喜剧模式,不先移除旧指令的话,injectDirective虽然会自动替换同 ID 的旧指令,但显式地先移除再注入是个好习惯——逻辑更清晰,也避免了在某些边界情况下的潜在问题。
行为 2:切换到恐怖模式
WHEN:
| 字段 | 填什么 |
|---|---|
| 触发器类型 | 动作 |
| 动作 ID | mode-horror |
DO:
| # | 动作类型 | 设置 | 作用 |
|---|---|---|---|
| 1 | 停止告诉 AI | 指令 ID:personality-override | 移除旧的人格指令 |
| 2 | 告诉 AI | 指令 ID:personality-override,内容见下方,位置:角色之后 | 注入恐怖风格指令 |
| 3 | 修改变量 | current_mode 设为 horror | 更新变量 |
| 4 | 显示通知 | 消息:已切换到恐怖模式,样式:danger | 用 danger 样式的通知,红色更有恐怖感 |
「告诉 AI」的指令内容:
[叙述风格:恐怖模式]
从现在开始,用阴暗不安的氛围叙述一切。你应该:
- 用缓慢、压迫性的节奏描写场景,注重感官细节(声音、气味、触感)
- 暗示有什么东西在暗处注视着角色,但不要直接揭露
- 让环境本身散发出不对劲的感觉——门自己关上、影子移动的方向不对、镜子里的倒影慢了半拍
- NPC的对话带着微妙的违和感,好像他们知道什么不该知道的事
- 偶尔用第二人称直接描写角色的生理反应(后颈汗毛竖起、心跳加速、瞳孔放大)
营造持续的紧张感,但不要每段都跳出怪物。真正的恐怖在于未知。行为 3:切换回普通模式
WHEN:
| 字段 | 填什么 |
|---|---|
| 触发器类型 | 动作 |
| 动作 ID | mode-normal |
DO:
| # | 动作类型 | 设置 | 作用 |
|---|---|---|---|
| 1 | 停止告诉 AI | 指令 ID:personality-override | 移除自定义人格指令。移除后 AI 的提示词里不再有风格覆盖,回到默认叙述风格 |
| 2 | 修改变量 | current_mode 设为 normal | 更新变量 |
| 3 | 显示通知 | 消息:已恢复普通模式,样式:info | 反馈 |
注意: 普通模式不需要注入任何指令。只需要移除之前的覆盖指令,AI 就会回到你在角色条目和系统指令里定义的默认风格。
第 3 步:理解指令位置和持久性
在配置「告诉 AI」动作时,你会看到两个重要的设置:位置和持久性/持续回合数。这里详细解释一下。
指令位置
位置决定了注入的指令出现在系统提示词的哪个部分。
| 位置 | 中文标签 | 说明 | 适合什么场景 |
|---|---|---|---|
auto | 自动 | 引擎自动选择最佳位置(通常放在角色设定之后) | 大多数情况下用这个就够了 |
top | 顶部 | 放在系统提示词的最开头,优先级最高 | 紧急的全局规则(如"从现在开始只用英语回复") |
before_char | 角色之前 | 放在角色设定之前 | 影响 AI 如何理解角色的全局设定 |
after_char | 角色之后 | 放在角色设定之后 | 风格指令、语气调整(本配方使用这个) |
bottom | 底部 | 放在系统提示词的最末尾 | 最后关头的提醒、"jailbreak"式指令 |
depth | 深度 | 按深度插入(在最近的第 N 条消息之前) | 需要出现在对话中间而非系统提示词里的指令 |
本配方为什么用「角色之后」? 因为人格切换指令是对叙述风格的覆盖。放在角色设定之后,AI 会先读到"我是谁"(角色设定),然后读到"我该怎么说话"(风格指令)。顺序自然,效果最好。
持久性 vs 临时指令
| 设置 | 说明 | 用法 |
|---|---|---|
| 持久(默认) | 指令一直保留在系统提示词里,直到被「停止告诉 AI」显式移除 | 本配方用这个——模式切换后一直生效,直到玩家再次切换 |
| 临时(设置持续回合数) | 指令在指定回合数后自动消失 | 适合一次性的效果,比如"接下来 3 回合里,角色处于醉酒状态,说话含糊不清" |
举例: 如果你在「告诉 AI」里设置持续回合数为 3,那这段指令会在注入后的第 3 个回合结束时自动消失,不需要手动移除。
第 4 步:做模式切换消息渲染器
在聊天界面最后一条消息下方显示三个模式按钮,当前激活的模式按钮高亮。
编辑器 → 消息渲染器 标签页 → 选「自定义 TSX」→ 粘贴以下代码:
export default function Renderer({ content, renderMarkdown, messageIndex }) {
const api = useYumina();
// ---- 读取当前模式 ----
const currentMode = String(api.variables.current_mode || "normal");
// ---- 三种模式的配置 ----
const modes = [
{
id: "normal",
label: "普通叙述",
actionId: "mode-normal",
color: "#94a3b8",
activeColor: "#e2e8f0",
activeBg: "rgba(148,163,184,0.2)",
border: "#475569",
activeBorder: "#94a3b8",
},
{
id: "comedy",
label: "喜剧模式",
actionId: "mode-comedy",
color: "#fbbf24",
activeColor: "#fef3c7",
activeBg: "rgba(251,191,36,0.2)",
border: "#a16207",
activeBorder: "#fbbf24",
},
{
id: "horror",
label: "恐怖模式",
actionId: "mode-horror",
color: "#f87171",
activeColor: "#fecaca",
activeBg: "rgba(248,113,113,0.2)",
border: "#991b1b",
activeBorder: "#f87171",
},
];
// ---- 判断是否是最后一条消息 ----
const msgs = api.messages || [];
const isLastMsg = messageIndex === msgs.length - 1;
return (
<div>
{/* 正常渲染消息文字 */}
<div
style={{ color: "#e2e8f0", lineHeight: 1.7 }}
dangerouslySetInnerHTML={{ __html: renderMarkdown(content) }}
/>
{/* 模式切换按钮——只在最后一条消息上显示 */}
{isLastMsg && (
<div style={{
display: "flex",
gap: "8px",
marginTop: "16px",
flexWrap: "wrap",
}}>
{modes.map((mode) => {
const isActive = currentMode === mode.id;
return (
<button
key={mode.id}
onClick={() => {
if (!isActive) {
api.executeAction(mode.actionId);
}
}}
style={{
padding: "8px 16px",
background: isActive ? mode.activeBg : "transparent",
border: `2px solid ${isActive ? mode.activeBorder : mode.border}`,
borderRadius: "8px",
color: isActive ? mode.activeColor : mode.color,
fontSize: "13px",
fontWeight: isActive ? "700" : "500",
cursor: isActive ? "default" : "pointer",
opacity: isActive ? 1 : 0.7,
transition: "all 0.2s ease",
}}
>
{isActive ? "● " : ""}{mode.label}
</button>
);
})}
</div>
)}
</div>
);
}代码逐行解释:
api.variables.current_mode— 读取当前模式变量的值modes— 一个数组,定义了三种模式的 ID、显示标签、对应的行为动作 ID、以及各种颜色配置isActive— 判断当前模式是否和按钮的模式匹配。如果匹配,按钮高亮;如果不匹配,按钮灰色半透明api.executeAction(mode.actionId)— 触发我们第 2 步创建的行为。注意只有当!isActive时才触发——如果已经是这个模式了,点了也不会重复触发"● "— 激活状态的按钮前面有个小圆点,作为视觉指示器transition: "all 0.2s ease"— 让按钮状态变化有平滑过渡动画
不想自己写代码?用工作室 AI
编辑器顶部 → 点击「进入工作室」→ AI 助手面板 → 用中文描述你想要什么,AI 会帮你生成代码。
第 5 步:保存并测试
- 点击编辑器顶部的「保存」
- 点击「开始游戏」或回到首页开一个新会话
- 正常和 AI 对话几回合,此时是普通叙述模式
- 点击「喜剧模式」按钮——按钮高亮变为金色,弹出通知「已切换到喜剧模式」
- 发一条消息——AI 的回复应该变得幽默、夸张、可能会打破第四面墙
- 点击「恐怖模式」按钮——按钮变为红色高亮
- 再发一条消息——AI 的回复变得阴暗、紧张、充满不安的暗示
- 点击「普通叙述」按钮——回到默认风格
- 再发一条消息——确认 AI 恢复了正常的叙述风格
如果遇到问题:
| 现象 | 可能的原因 | 解决方法 |
|---|---|---|
| 看不到模式按钮 | 消息渲染器代码没保存或有语法错误 | 检查消息渲染器底部的编译状态,应该显示绿色「OK」 |
| 点按钮没反应 | 行为的动作 ID 和代码里的不匹配 | 确认行为的动作 ID 是 mode-comedy、mode-horror、mode-normal,和代码中 executeAction() 的参数一致 |
| 按钮状态不变化 | 变量没有被行为正确修改 | 检查每条行为的「修改变量」动作是否正确设置了 current_mode 的值 |
| 切换后 AI 风格没变 | 指令内容为空或位置不对 | 检查「告诉 AI」动作的指令内容是否填写了,位置建议选「角色之后」 |
| 切回普通模式后风格还是之前的 | 「停止告诉 AI」的指令 ID 不匹配 | 确认三条行为里的指令 ID 都是同一个:personality-override |
进阶用法
添加更多模式
想加一个「诗意模式」?只需要:
- 在
modes数组里加一项(ID、标签、颜色) - 创建一条新行为,动作 ID 是
mode-poetic,动作和喜剧/恐怖模式一样(移除旧指令 → 注入新指令 → 改变量 → 通知) - 完成。按钮会自动出现在渲染器里
用临时指令做"一次性人格爆发"
假设你想做一个「醉酒按钮」——点击后 AI 用醉酒的方式说话 3 回合,然后自动恢复:
在「告诉 AI」动作里,把持续回合数设为 3。3 回合后指令自动消失,不需要玩家再点一次按钮来取消。
语言切换
同样的模式可以用来切换 AI 的回复语言。指令内容改成"从现在开始全部用英语回复"或"从现在开始用日语回复",就能做出一个语言切换器。
速查表
| 你想做的事 | 怎么做 |
|---|---|
| 动态修改 AI 的系统提示词 | 行为动作用「告诉 AI」(inject-directive),填指令 ID、内容和位置 |
| 移除之前注入的指令 | 行为动作用「停止告诉 AI」(remove-directive),填要移除的指令 ID |
| 让指令在 N 回合后自动消失 | 「告诉 AI」里设置持续回合数 |
| 让指令永久保留(直到手动移除) | 「告诉 AI」里不设置持续回合数(默认行为) |
| 风格指令放在角色设定之后 | 位置选「角色之后」(after_char) |
| 紧急规则覆盖放在最前面 | 位置选「顶部」(top) |
| 最后一刻提醒放在最后面 | 位置选「底部」(bottom) |
| 切换前移除旧指令 | 用同一个指令 ID,先「停止告诉 AI」再「告诉 AI」 |
| 按钮高亮显示当前状态 | 消息渲染器里读变量,用条件样式(isActive)控制高亮 |
直接试试——可导入的示例世界
下载这个 JSON 文件,导入即可体验完整效果:
导入方法:
- 进入 Yumina → 我的世界 → 创建新世界
- 在编辑器顶部点「更多操作」→「导入包」
- 选择下载的
.json文件 - 世界会被创建,所有变量、行为和渲染器都已预配置好
- 开一个新会话试试看
包含内容:
- 1 个变量(
current_mode追踪当前人格模式) - 3 条行为(切换喜剧模式 / 切换恐怖模式 / 恢复普通模式)
- 一个消息渲染器(三个模式切换按钮,带高亮指示)
这是实战配方 #11
这个配方展示了「告诉 AI」/「停止告诉 AI」的核心用法——动态注入和移除系统提示词里的指令。同样的模式可以用来做语言切换、难度调节、叙事视角切换(第一人称/第三人称)、甚至"AI 性格渐变"(每隔几回合自动注入不同强度的指令)。
