2.1 LLM 剧本生成


2.1 LLM 剧本生成

本节摘要:本节做脚本段:把一句想法变成合法的剧本 JSON。第一件事是约束先行:题材、时长、风格三类约束全部写进提示词模板,时长换算成场景数建议,风格作为基调字段下传全片;同时把「原创、不出现真实人物与品牌」写进禁忌行,这是版权侧的第一道闸。第二件事是结构化输出:模板里直接给出目标 JSON 的形状,配合供应商的结构化输出能力,把「模型自由发挥」压成「模型填表」。第三件事是策略分界:60 秒以内的片子一次生成,更长的内容先出场景纲要、人确认后再逐场展开——单次输出越长,走形的概率越大。最后实现「生成、校验、修复」循环,处理 JSON 解析失败与字段缺失两类高频故障。

学习目标

  • 写出含题材、时长、风格、禁忌四类约束的提示词模板,说明各约束的用途。
  • 解释结构化输出约束为什么能把剧本生成从「自由作文」变成「填表」。
  • 按时长选择一次生成或分段生成策略,并说出分界理由。
  • 实现生成、校验、修复循环,处理两类高频输出故障。

一、约束先行:提示词模板

剧本质量的上限在提示词里就定了。模板四类约束各有职责:题材定内容方向,时长定规模(并换算成场景数建议),风格定基调并作为字段下传(后续每段的画面、配音都要读它),禁忌行守住版权与内容边界。

# script_prompt.py —— 剧本生成的提示词模板(结构化输出约束,写法示意) PROMPT = """你是短视频编剧。按以下约束写一个原创剧本: 题材:{genre} 时长:约 {duration} 秒,建议 {scene_count} 场 风格:{style} 禁忌:不出现真实人物与真实品牌,不模仿现有作品 只输出一个 JSON 对象,结构如下(不要输出其他文字): {{ "title": "片名", "scenes": [ {{"scene_id": 1, "location": "场景地点", "action": "场内动作描述", "lines": ["台词一"]}} ] }}""" def build_prompt(genre, duration, style): scene_count = max(2, round(duration / 15)) return PROMPT.format(genre=genre, duration=duration, style=style, scene_count=scene_count) ​

两个细节。其一,场景数由时长换算(经验值约 15 秒一场,示意口径)写进提示词,比让模型自己估可靠得多——模型对「60 秒能讲几场戏」的直觉极不稳定。其二,JSON 形状直接嵌在模板里并要求只输出 JSON:配合供应商的结构化输出参数(各家叫法不同,以官方文档为准),非法输出的比例能从「偶尔崩」压到「几乎不崩」。

拿 0.1 节的示例片把这个模板跑一遍。输入:题材「科普」、时长 60 秒、风格「温和的科普口吻,克制的幽默」。提示词里的场景数建议按公式算出 4 场,模型交回的成品是 3 场——建议值是软约束,模型按内容密度自行收敛属于正常现象,人审时以「每场有没有独立任务」为验收标准,不死抠场数:

# script_v1_preview.json —— 彩虹片剧本首版(示意,对应 0.1 节的镜头表) { "title": "六十秒看懂:彩虹为什么是弧形", "style": "温和的科普口吻,克制的幽默", "scenes": [ {"scene_id": 1, "location": "雨后街道", "action": "雨刚停,阳光从云缝里回来,行人抬头看天", "lines": ["雨停了,阳光回来", "天边挂出一道弧"]}, {"scene_id": 2, "location": "阳光与水滴的示意空间", "action": "一束阳光射进一颗水滴,光在内部折射、分色后再反射出来", "lines": ["你看到的弧,起点是一亿五千万公里外的阳光", "阳光进水滴时折一次,出来时再折一次", "不同颜色的光,偏折角不同"]}, {"scene_id": 3, "location": "观察者视角的天空", "action": "观察者背对太阳,视线抬起约 42 度,锥面上的水滴连成一个圆,地面挡住下半截", "lines": ["和视线成约 42 度角的水滴,颜色叠得最浓", "把这些点连起来是个圆", "地面挡住了下半截,你看到的就是弧"]} ] } ​

对着 0.1 节的镜头表回看这份剧本:镜头表的每一行都能在某个场里找到出处,每一场再按画面任务切成带号的镜头——第 2.2 节做的就是这一刀。另注意 action 的写法全部「看得见」:折射、分色、抬起视线、连成圆,没有一个「它很神奇」式的情绪词——这正是下一部分要盯的第三件事。

二、剧本的形状与生成侧要点

剧本 schema 在 1.2 节已定义:title、target_duration、style 加 scenes 列表,每场含 scene_id、location、action、lines。生成侧要额外盯三件事。场号连续:从 1 起不间断,这是后续「改一场不改全片」的定位键。台词短句化:一句台词别超过二十个字——这不是文学趣味,是字幕排版与 TTS 停顿的工程约束(第 6、7 章后半本会回来解释)。动作具象化:action 要写得「看得见」——「他很难过」是情绪,「他把镊子放下,盯着那枚齿轮」是画面;分镜段的原料是画面,不是情绪。

三、一次生成与分段生成

策略 做法 适用 风险
一次生成 全剧本一次请求产出 60 秒以内、三五场戏 长输出后半段质量下滑、场间重复
分段生成 先出场景纲要(每场一句话),人确认后逐场展开 分钟级以上、场次多 多轮请求、需要拼装与场间一致性看护

分界线的依据是经验观察(示意口径):单次生成超过千余字,模型开始重复句式、丢场号、台词趋同。分段生成的纲要轮是廉价的:一次小请求列出全场梗概,人花一分钟扫一眼节奏——烂纲要在这一步拦下,成本几乎为零;放到分镜之后再发现,重做的是整段。

四、生成、校验、修复循环

两类高频故障:JSON 解析失败(模型输出带上了废话或截断)、字段缺失(lines 空缺、scene_id 跳号)。对策是三步循环:

# script_gen.py —— 生成、校验、修复的三步循环(写法示意,client 以你的 SDK 为准) import json def generate_script(client, prompt): reply = client.chat(prompt, response_format="json") try: data = json.loads(reply) except json.JSONDecodeError: fixed = client.chat("以下内容不是合法 JSON,请修正后只输出 JSON:\n" + reply) data = json.loads(fixed) data.setdefault("schema_version", 1) known_ids = [] for scene in data.get("scenes", []): scene.setdefault("lines", []) scene["scene_id"] = scene.get("scene_id") or (known_ids[-1] + 1 if known_ids else 1) known_ids.append(scene["scene_id"]) return data ​

修复的原则:能机械修的机械修,机械修不了的退回模型。缺 lines 补空列表是机械修;scene_id 缺失按前值递增是机械修;情节逻辑崩了只能退回模型重写。修复循环最多两轮——两轮还不过,问题基本出在提示词而非运气,该改的是模板。产出落盘为 build/01_script/script.v1.json,进入 2.2 节的分镜转换。

三步循环里的「校验」也可以机械化为一个纯标准库函数,让修复只在真正需要时启动:

# validate_script.py —— 剧本 JSON 的机械校验(纯标准库,红线阈值为示意值) import json MAX_LINE = 20 # 台词字数红线(工程口径) MOOD_WORDS = ("难过", "开心", "神奇", "震撼") # 情绪词黑名单(示例) def validate(path): data = json.load(open(path, encoding="utf-8")) problems = [] if not data.get("title"): problems.append("缺 title") scenes = data.get("scenes", []) if not scenes: problems.append("scenes 为空") for expect, scene in enumerate(scenes, start=1): sid = scene.get("scene_id") if sid != expect: problems.append("场号不连续:期望 %d,实际 %s" % (expect, sid)) if not scene.get("action"): problems.append("场 %s 缺 action" % sid) for i, line in enumerate(scene.get("lines", []), start=1): if len(line) > MAX_LINE: problems.append("场 %s 第 %d 句超 %d 字" % (sid, i, MAX_LINE)) if any(word in line for word in MOOD_WORDS): problems.append("场 %s 第 %d 句是情绪不是画面" % (sid, i)) return problems if __name__ == "__main__": for p in validate("build/01_script/script.v1.json"): print("待修:%s" % p) print("校验完成") ​

校验报告分两类处置:场号、缺字段这类结构问题走机械修复,回到上面的循环;台词超长、情绪词这类内容问题退回提示词层——在模板里把约束再写狠一格(例如把「台词短句化」升格为「每句不超过二十字,超出的场视为不合格」),比逐句手工改省。校验器与修复循环的关系是上下游:校验发现问题、归类问题,修复只处理归类为「机械」的那部分。

五、常见问题与排查

剧本段的故障绝大多数落在五张老脸上:

症状 根因 处置
JSON 外面裹着说明文字或代码围栏 未开结构化输出,或「只输出 JSON」措辞不够硬 开结构化输出参数;修复轮剥壳后重解析
场号跳号或重复 长输出后半段注意力下滑 机械修复按前值递增;仍乱则改分段生成
台词书面化、一句三十字 模板没写短句约束,或模型忽视它 红线写进模板,校验器兜底
出现真实品牌或真实人物 禁忌行缺失或被其他要求稀释 禁忌行固定不删,人审第一项就查它
两版剧本风格明显不同 风格只写在提示词里,没进产物 style 作为字段落进 JSON 并下传(第 1.2 节)

最后一条最隐蔽:风格若只存在于提示词里,后续每一段都无从对齐——把它变成 JSON 字段,是「约束先行」从生成时刻延伸到全片时刻的关键一步。

本节要点回顾

  • 提示词四约束:题材、时长(换算场景数)、风格(下传全片)、禁忌(版权第一道闸)。
  • 结构化输出加内嵌 JSON 形状,把生成从自由作文压成填表。
  • 60 秒一次成,更长先纲要后展开;烂纲要要在廉价环节拦下。
  • 修复循环两轮封顶,机械修优先,修不好改模板而不是改运气。

剧本有了,下一节把它切成镜头——分镜 schema 的七个字段与三道校验关,是整条流水线信息密度最高的一张表。

作者与出处
原作者:灏天文库
整理人: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U