返回文章列表

叙光:一个可自部署的 AI 漫剧分镜生成工具,以及角色一致性的三板斧

2026年8月28日9 分钟读完

叙光:一个可自部署的 AI 漫剧分镜生成工具,以及角色一致性的三板斧

这是我在「赵强的AI产品实践」里记录的一个真实项目——叙光 (Xuguang)。它不是又一款"输入文字直接出视频"的黑盒玩具,而是一个让创作者可控的漫剧分镜生产工具。

项目定位:不做黑盒,做可控的生产线

市面上的 AI 视频工具(即梦、可灵、各类 OpenMontage 类)大多是"全自动视频生成":你丢一个故事进去,它吐一段视频出来,中间发生了什么你完全干预不了。这对"玩一下"很爽,对"认真做内容"很难用——你没法保证主角的脸每一帧都一样,也没法在故事中途改一句台词重新生成那一帧。

叙光的设计取舍正好相反,核心定位是"创作者可控的分镜工具"

对比维度同类工具(即梦/可灵)叙光
核心定位全自动视频生成创作者可控的分镜工具
分镜控制黑盒生成,无法干预分镜可查看、可编辑、可重新生成
角色一致性依赖模型,难以保证角色设定卡 + 固定 Seed + 角色参考图三层锁定
叙事性画面机械对应文字每帧 Prompt 含镜头语言、情绪氛围、叙事节拍
输出灵活性直接出视频分镜图、配音、字幕可单独导出
技术门槛闭源 SaaS开源 / 可自部署

一句话总结产品哲学:把"确定性可控"留给创作者,"不可控的创造力"交给模型。

技术栈与架构

  • 后端:PHP 8.2 + ThinkPHP 8
  • 存储:MySQL(项目/分镜数据)+ Redis(队列与缓存)
  • AI 能力:统一走硅基流动 API,按场景切模型:
    • 文本/分镜脚本:Qwen/Qwen2.5-7B-Instruct
    • 生图:Kwai-Kolors/Kolors(hd/fast 模式)
    • 一致模式指令式编辑:Qwen/Qwen-Image-Edit-2509
    • 视频生成:Wan-AI/Wan2.1-I2V-14B-720P-Turbo
    • 配音 TTS:FunAudioLLM/CosyVoice2-0.5B

核心数据实体只有两个:projects(一个故事项目)和 scripts(该项目下的每一帧分镜)。围绕它们组织出一组服务层模块:

app/common/
├── PromptBuilder.php      # 叙事化分镜 Prompt 组装
├── CharacterManager.php   # 角色一致性三板斧
├── AiHelper.php           # 文本/生图统一调用封装
├── AudioHelper.php        # 配音 TTS
└── VideoHelper.php        # 图生视频

角色一致性的三板斧

做 AI 漫剧最致命的问题就是**"主角脸在飘"**——第一帧是黑长直,第三帧变成金卷发。叙光用三层机制把角色锁死:

第一斧:角色外观卡片

提交故事后,先用大模型从文本里抽取结构化角色设定(名字/物种/外貌/服装/特征),写入 projects.character_card,然后注入到每一帧的 Prompt 中。这样模型每画一帧都"记得"角色长什么样。

第二斧:固定 Seed

同一角色派生出同一个随机种子,保证全片画面的风格稳定(在 hd/fast 模式下生效)。这是成本最低、收益最高的一招。

第三斧:角色立绘参考图(Qwen-Image-Edit)

先为角色生成一张标准立绘 projects.character_sheet_url,后续每一帧都携带这张图做指令式编辑,从图像层面(而非仅靠文字)锁定角色外观。

代码里 CharacterManager 就是这个机制的实现:extractCard() 抽设定 → deriveSeed() 定种子 → generateSheet() 出立绘 → 后续帧用立绘做 localToDataUri() 注入编辑。

叙事化 Prompt:让画面服务故事

光角色一致还不够,如果每一帧只是"把文字翻译成画",故事就会很机械。叙光的 PromptBuilder 把每帧 Prompt 严格按权重顺序组装(build() 方法里一目了然):

1. 画风硬约束(权重最高,必须放最前)
2. 角色锁定(第二权重,简洁但强硬)
3. 场景内容 / 动作(叙事主体)
4. 表情
5. 镜头语言(景别 → 构图)
6. 情绪氛围(情绪 → 光影色调)
7. 角色设定重复强调(尾部再锚定一次)
8. 叙事节拍(第 N 帧 / 故事阶段)

这里有个反直觉但很关键的点:SD 系模型对 Prompt 前面的词权重更高,所以"画风硬约束"和"角色锁定"被放在最前面,从根源上压住画风漂移和角色走形;同时在 Prompt 尾部再用一句"再次确认角色外貌完全一致"做双重锚定。

buildEditPrompt()(一致模式)和 buildChainPrompt()(链式生成)共用这套叙事段,区别是:一致模式强调"严格保持参考图角色 + 重建场景",链式生成(第 N 帧拿第 N-1 帧当参考图)强调"与上一帧连续"。

一个真实的坑:硅基流动的 img2img 不认 strength

这是项目里最值的记录的一个技术踩坑。

我最初计划用 Kolors / Z-Image 的 img2img + 低 strength(比如 0.3)来"小幅改动角色立绘",保持角色外观、只换场景。结果实测发现硅基流动平台的 img2img 根本不接收 strength 参数——同一张图、0.3 和 0.95 出来的结果完全一样。更糟的是,参考图会"锁死"角色的姿势,导致所有帧里的角色都保持立绘那个站姿,"没有动作"。

解决方案是:一致模式改用 Qwen-Image-Edit-2509 做指令式编辑AI_IMAGE_EDIT_MODEL 可配)。这个模型会读取参考图里的角色形象,同时按文字指令重建场景、动作、表情——既锁住了脸,又放开了动作。一行配置切换,效果天差地别。

三种生图模式与工程化细节

生图接口 POST /script/batchGenerateImages 提供三种模式,本质是"质量—成本"的三角权衡:

模式说明成本
consistent(默认推荐)先生成角色立绘参考图,每帧用 Qwen-Image-Edit 指令式编辑最高
hd1024px,角色卡片 + 固定 seed + 完整叙事 Prompt(无参考图)
fast512px,角色卡片 + 固定 seed + 完整叙事 Prompt

工程化上值得一提的两点:

  • 零迁移数据库projects 表新增 character_card / character_sheet_urlscripts 表新增 character_desc / emotion / prompt,首次调用生图接口时自动补齐字段,无需手工跑迁移脚本(DB_CHARSET 需为 utf8mb4)。
  • 完整后台 RBACadmin 路由组下包含用户、角色、权限、项目管理、发布管理和系统配置,前后端分离式鉴权(AdminAuth 中间件)。

写在最后

叙光让我验证了一件事:在大模型能力还远不完美的当下,"可控性"比"全自动"更有产品价值。 用户要的不是被 AI 惊艳一次,而是能稳定、可迭代地做出自己想要的东西。角色一致性三板斧、叙事化 Prompt 的权重设计、以及对"strength 参数失效"这类平台特性的硬核排查,都是为了让"可控"真正成立。

项目已在 Gitee 开源(kuaoo/xuguang),支持 composer install 后自部署。如果你也在做 AI 内容生成方向,欢迎交流踩坑经验。

注:文中模型名称、接口路径均来自项目实际源码与公开 README,可对照仓库验证。