Skip to content

戏剧工坊:从 AI Town 与 MiroFish 到角色自主演戏 ​

一个工程案例:先运行 AI Town 和 MiroFish,再把两者有用的部分拆出来,重组为面向剧本生产的角色演化系统。文中的角色一律用占位名,不绑定具体剧本。

1. 我们没有直接复制任何一个项目 ​

三个项目解决的是不同问题:

项目基本单位产出我们吸收的部分
AI Town世界 tick、移动、双人对话一个持续活动的世界持续状态、角色记忆、服务端事实
MiroFish发帖、评论、点赞、舆论群体预测报告图谱事件、角色信息边界、长期记忆
戏剧工坊一集、多段交锋、旁白剧本和分镜导演调度、角色表演、动态场次

我们没有把社交平台模拟硬改成剧场,也没有把 2D 小镇硬改成剧本。


2. 戏剧工坊的基本循环 ​

一次「集」的结构是:

text
开场旁白:时间 / 地点 / 前情
        ↓
段 1:角色 A 出招,角色 B 接
        ↓
段 2:角色 B 反击,角色 A 接
        ↓
段 3:压力升级、秘密露一角或场景转移
        ↓
收尾旁白:留下下一集钩子

这解决了早期版本的两个问题:

  • 一拍只有一两句,像零散聊天;
  • 角色说完之后没有余波,剧情不向前走。

现在一集通常是 10-15 行台词,可以直接作为一集短剧的基础单元。


3. 两种使用方式 ​

自动剧 ​

text
用户给背景 + 角色
        ↓
导演自动推进
        ↓
角色按人设表演
        ↓
一集结束,进入下一集

互动剧 ​

text
用户选择一个角色
        ↓
用户输入台词
        ↓
其他角色按自己的记忆和目的回应
        ↓
导演继续安排下一步

系统会拦截一种典型错位:玩家刚说完,又被安排替对方回答。实现上是一个 exclude 护栏,把刚发言的角色排除出下一次焦点候选。


4. 场次不是一开始写死的 ​

早期的 YAML 模式仍然保留,适合明确排好的剧本:

yaml
scenes:
  scene1:
    characters: [角色A, 角色B, 角色C]
  scene2:
    characters: [角色A, 角色B]

但自由演化模式不要求预先列出全部场次:

text
导演每集决定:
  continue      继续当前冲突
  new_arc       开一个新单元
  new_scene     换地点或换人
  close_arc     收掉一条支线
  finale        进入收尾

主线 + 单元线 ​

text
主线:一件贯穿全剧、迟迟没有答案的事
  ├─ 单元 A:某个物件引出的支线
  ├─ 单元 B:某个职业角色手上的流程
  ├─ 单元 C:某个外人带来的噪音
  ├─ 单元 D:某段关系里的旧账
  └─ 单元 E:某个被忽略的细节
  • related=true:给主线一块拼图;
  • related=false:人物塑造、节奏喘息或干扰;
  • 单元可以并行,导演决定何时重新打开或收掉。

5. 图谱记忆:把「谁知道什么」单独建模 ​

戏剧工坊没有把完整真相塞进每个角色的 prompt,而是按事件建立见证关系:

text
(Char)-[:WITNESSED]->(Beat)
(Char)-[:SAID]->(Beat)
(Char)-[:KNOWS]->(Fact)
(SceneSummary)

角色看到的内容 ​

角色生成台词前,记忆由三块组成:

text
短期记忆:最近几条
    +
场景摘要:过去一段戏发生了什么
    +
事实权限:这个角色自己见过、听过或被告知什么

隐私隔离的关键 ​

text
scene.characters = [角色A, 角色B]
        ↓
本场产生的事实只发给角色A和角色B
        ↓
不在场的角色,事实查询拿不到这场内容

判定依据不是「他能不能猜到」,而是「他有没有见证边」。

角色事实数能看到的场次
一直在场的角色80全部
只参与两场的角色50现场 + 单独问话
只出现一场的角色35现场

这个设计来自 MiroFish 的图谱思路,但比「向量相似检索」多了一条明确的权限边界:不在场,就没有见证边。


6. 旁白不是第四个演员 ​

旁白层单独存在,不占用人物身份:

旁白职责触发方式
开场每集必有:时间、地点、前情
中段只有换地点、时间跳跃或镜头外发生事时才出现
摘要每隔若干行压缩已发生事实
收尾每集必有:一个下一集钩子
裁决可选:检查角色是否说出了不可能知道的事

例如:

text
【开场】夜里的走廊,灯只亮了一半。

角色对话……

【收尾】门外的那个人,一直没有走。

如果每句台词都加旁白,戏会被切碎。因此中段旁白是事件驱动,不是固定频率插入。


7. 运行中遇到的真实问题 ​

问题表现处理方式
角色连续盯同一个人连续多集都在问同一个人引擎级焦点轮换
单元线不增长导演重复返回旧 arc id强制生成新 id
一拍太短只有一两句台词焦点出招 + 反应者接招
台词重复后一段复述上一段传入本集 prior + 相似度过滤
所有人都知道秘密场景里信息污染WITNESSED / KNOWS 过滤
思考模型返回空 JSON旁白、事实抽取静默失败工具调用换非思考模型 + 重试
长戏容易忘最近窗口被截断Beat + Summary + Fact 三层记忆
主线过早到顶进度很快 100%按产出行数调节增量

这些问题说明:自由演化不能只靠提示词,必须有引擎级状态和护栏。


8. 导出到短剧产线 ​

戏剧工坊输出两种文件:

text
screenplay.md
  场次
  开场旁白
  动作
  台词
  收尾钩子

storyboard.csv
  镜号
  场景
  说话人
  对象
  动作
  台词
  建议景别
  建议时长

示例:

csv
S001,第一场,角色A,,走到门口停下,你先说,我听着。,近景,4.0

后续可以把 storyboard.csv 接到已有短剧产线,继续生成:

text
分镜 → 首帧 → 视频 → 配音 → 口型 → BGM → 成片

戏剧工坊负责的是剧情和角色行为层,不替代下游图像、视频和音频引擎。


9. 这套系统真正有什么用 ​

它不是为了替人「一键写完一部剧」,而是提供一个可反复运行的剧情实验场:

  • 测试一个角色在压力下会不会说漏秘密;
  • 看一条线索先会撞到谁;
  • 发现人工大纲里没想到的支线;
  • 比较不同角色组合会产生什么冲突;
  • 先拿到一版活的剧本,再人工剪辑成正式结构;
  • 把角色行为和镜头素材产线连接起来。

10. 一句话总结 ​

戏剧工坊不是让模型替作者写一篇故事,而是给角色一个世界、给每个人一份不完整的记忆,再让导演、演员和记忆账本一起把故事推出来。

这篇里有不清楚的地方,或者想聊类似的东西?私信我 →