skip to content
tlj 的工程笔记
← 项目

Screenwright:小说转剧本工作台

比赛

把一部小说自动转成结构化剧本(YAML),还能行级溯源回原文、按媒介(电影/剧集/短剧)重渲染、把内心戏外化成镜头语言。技术含量不在调 API,在四个工程取舍。

时间
2026-06
角色
独立开发(schema / 管线 / 前端 / 部署)
成果
行级双向溯源(LLM 抄 marker、代码定位)+ 有序判别联合 schema + story_bible 单一事实源;103 单测、32 PR

七牛云实训营的题目三:把一部小说(3 章以上)自动转成可机读、可手改、可溯源、可重渲染的结构化剧本(主格式 YAML,另出 Fountain / PDF)。定位是”编剧工作台”,不是”切块丢给大模型的转换器”。

选这道题本身是个判断:纯文本、零实时,评委现场试用最稳(演示分占 20%,上一个项目录语音 demo 时在实时性上踩过坑);token 优势只在这种离线批处理任务上才变现;而且赛题硬要求交一份 YAML Schema 文档,题三的核心产物本就是结构化数据,Schema 文档等于白送的架构分。FAQ 也写明评审主要看产品价值、其次技术难度——所以技术含量我放在”换皮组会跳过的硬骨头”上,而不是卷算法(所有原子能力都是 LLM API,自训模型不在评分轴上)。

四个工程取舍(这才是技术含量)

一、剧本元素用”有序带类型的序列”,不按类型分桶。 剧本本质是时间序列,顺序本身承载叙事。如果把 action / dialogue 按类型分桶存,就抹掉了相对顺序,恢复时还得加全局序号、手改插一行就要重排。用 pydantic 的判别联合(Field(discriminator="type"))按 type 直接选子模型——错误精确、解析快、扩展只加子模型不动旧数据。

二、story_bible 是跨章的”单一事实源”,但用分章抽取 + 代码合并,不整本丢 LLM。 整本丢进去模型中间会遗忘。所以每章抽人物/地点/时间线,再把”合并、归一、分配 id”这步剥成纯 Python——确定性、可单测、省 token、增量友好。人物归一用 别名→char_id 表,中文名转拼音 slug、冲突追加序号。

三、行级溯源:让 LLM 抄 marker,由代码定位(最关键的一个取舍)。 每个动作/台词要能点击跳回原文精确高亮。但 LLM 按 token 预测,对”第几个字符”没有可靠的内部表示,中文长文里让它报字符偏移会偏上百字符,溯源地基直接塌。解法是责任倒置:LLM 只回逐字的首尾 marker(10-20 字,本质是抄写它擅长),代码用 chapter.text.find(marker) 精确定位,找不到就用”连续接续”兜底保证首尾相接、覆盖整章。而且偏移一律相对章内而非全文,这样章节增删不影响其他章。

四、schema 即契约 + 校验自修复环。 validate_and_repair(raw, llm, max_retries=2):先 json.loads 再退 yaml.safe_loadmodel_validate,失败就把”校验错误文本 + 原始内容”回喂给 LLM 自修复、重试上限内闭环。用 YAML 而非 JSON,因为缩进即结构、能写注释、中文免转义——都服务于”可手改”。

管线:Pass0 到 Pass5

离线多轮管线,每个 Pass 推 SSE 进度:Pass0 分章分块(滚动摘要扛长上下文)→ Pass1 抽 story_bible → Pass2 按时空切场景 + 场级溯源 → Pass3 逐场生成(注入本场原文+bible切片+上场尾+目标媒介)→ Pass4 pydantic 校验 + YAML 自修复 + 连贯性回填 → Pass5 纯统计看板 + 导出。其中媒介可控(film/series/short_drama 一处声明全局生效,短剧版强金句强钩子),内心戏外化(把 interior_monologue 外化成 action/subtext/voiceover,用 adaptation 标记记录”从什么→用什么手法”),连贯性检查纯规则不调 LLM(跨场时间线/认知冲突,分 info/warn/error 三级)。

真实踩坑(现象→根因→解法)

量化(真实端到端跑 3 章中文小说)

12 个场景、58 行内容(action 35 / dialogue 23)、内心戏外化 15 处;行级溯源覆盖率 70.7%(分母排除转场,剩约 30% 是纯外化新增台词,溯源诚实留 None 不硬凑);原文覆盖率 86.3%;英文样例(《傲慢与偏见》3 章)行级溯源 66.3%(证明不是对中文过拟合);Schema 往返合法、连贯性 0 error;全流程约 64 秒。

工程纪律

103 个后端单测(全程脱网 mock);32 个 PR 全走 feature 分支 + merge commit、commit 分散在开发窗口(赛题要求不能最后一天一次性导入);做了一轮安全自审,2 高 2 中全修复并线上复验——【高·DoS】文本加 max_length + Caddy 请求体限大小(线上实测 21 万字符返回 422)、【高·隐私】API 路径关 LLM 缓存让原文不落盘、【中·限流】防 X-Forwarded-For 伪造。演示样本也讲版权:英文用公有领域的《傲慢与偏见》(Project Gutenberg),中文用专门为项目原创授权的短篇,零版权风险。

小结

这个项目最能说明问题的是那四个取舍——尤其”LLM 抄 marker、代码定位”那个:它承认了”LLM 不会数字符”这个事实,把溯源的可靠性从概率模型手里夺回到确定性代码里。技术含量从来不在”调通 API”,在这些”换皮组会跳过、但决定产品可信度”的硬骨头上。