ArcLoop 生成漫剧大纲后,角色关系会随着剧情推进不断改变。回填太早,后面的单集冲突可能把关系推翻;回填太晚,Agent 续写时读到的还是过期关系,角色说话和行动就会对不上。较稳的顺序是:先把大纲拆成每集一行、可逐集检查的单集冲突,再按集标记结尾的关系变化,最后只把变化项写回角色设定区,并用相邻两集做一次衔接检查。
关系回填的时机,建议放在单集冲突拆分之后、逐集生成之前,而不是大纲生成完就整段改写角色设定。操作上每条关系只记录信任、敌对、隐瞒、合作四类状态的变化项,保留初始 baseline,让 Agent 读取时按集覆盖。验证方式很简单:核对上一集结尾状态是否等于下一集起始状态。边界是未标记的关系对默认沿用上一集,不要靠脚本推断隐含变化。
从生成大纲里抽出每集单集冲突
长大纲是一段连续叙事,直接交给 Agent 续写,很难判断某一集到底有没有推进。建议先切成「每集一行」的检查单元:集数、核心冲突、结尾变化。核心冲突写这一集里没有退路的那个决定;结尾变化写这一集结束时,局势或信息状态相比开头改变了什么。拆分结果可以和大纲放在同一目录,作为后续回填的依据。
| 集数 | 核心冲突 | 结尾变化 |
|---|---|---|
| ep01 | 主角必须在公开场合否认自己掌握的证据 | 证据被对手拿走,主角失去主动权 |
| ep02 | 主角向搭档求助,但只能说出部分信息 | 搭档答应帮忙,同时开始怀疑主角隐瞒 |
表格内容是占位示例,替换成自己的大纲即可。拆分可以交给 Agent 做,但提示词要限定输出结构与粒度。下面是一段可替换的提示词骨架,把 EXISTING_OUTLINE 换成自己的大纲文本。
你负责把漫剧大纲拆成单集冲突表。
输入:<EXISTING_OUTLINE>
输出:每集一行,字段为 episode、conflict、end_change。
约束:
1. 每集只写一个核心冲突,写成“谁必须做什么、否则会失去什么”。
2. end_change 只写这一集结束时相比开头改变的事实,不写情绪形容。
3. 不新增角色,不改变大纲里已经发生的事件。
验证方式:遮住大纲正文,只看「结尾变化」这一列,能否判断下一集的冲突从哪里接上。如果同一场戏被拆成两集,说明粒度偏细,会明显加大关系回填的工作量;具体每集放多少信息,需要结合剧集总时长和单集节奏确认。
标记每集结束后的角色关系变化
用关系状态字段记录:信任、敌对、隐瞒、合作。每集只写发生变化的关系对,没变的不写,但要在条目里保留 changed: false 这类标记,避免后续检查时分不清「没变」和「漏填」。
- episode: ep01
relations:
- pair: 主角-搭档
trust: mid
hostility: none
concealment: high
cooperation: mid
changed: true
reason: 主角拿到证据但没有告诉搭档
- pair: 主角-对手
changed: false
状态取值建议用 none / low / mid / high 这类有序枚举,不要用自由文本,否则相邻两集比较时无法直接判断相等。隐瞒和信任是两条线:角色对某人隐瞒加深,不一定等于信任立刻下降,分开记更稳,也方便后续单集单独生成时只读取需要的那一维。
回到角色设定区补充关系变化后的状态
角色设定区保留初始设定,只追加变化项。可以把结构分成两层:relations_baseline 写角色出场时的关系,relations_timeline 按集追加覆盖。Agent 生成第 N 集时,先读 baseline,再依次套用 ep01 到 ep(N-1) 的变化项,读取顺序要固定下来。
character: 主角
relations_baseline:
- target: 搭档
trust: mid
hostility: none
concealment: none
cooperation: mid
relations_timeline:
- episode: ep01
target: 搭档
concealment: high
reason: 主角开始隐瞒证据来源
验证方式:改完设定区后,重新让 Agent 生成某一集的角色对话,看称呼、语气和让步程度是否符合该集之前累积的关系状态。注意不要直接改 baseline 字段,否则回头重生成前几集时,初始关系会跟着变,前后集数容易互相矛盾。
用相邻两集做关系连续性检查
核对上一集结尾状态是否等于下一集起始状态。可以在每集条目里同时保留 relations_start 与 relations_end,然后做一次线性扫描,输出所有不相等的关系对。
for prev, nxt in pairs(episodes):
for pair, end_state in prev.relations_end.items():
start_state = nxt.relations_start.get(pair, end_state)
if start_state != end_state:
report(prev.episode, nxt.episode, pair, end_state, start_state)
发现跳变时通常有两种处理:如果变化确实发生在这一集里,把它补进该集的关系变化项;如果剧情里没有任何交代,就回看这一集的单集冲突是否需要调整,或者在前一集结尾补一个转折。检查只覆盖被标记过的关系对,未标记的默认沿用上一集状态,不要指望脚本推断隐含变化。