从零构建无真人AIGC短剧:角色一致性、视频合成与工程化实践

📅 2026/8/27 7:11:35
从零构建无真人AIGC短剧:角色一致性、视频合成与工程化实践
最近总能看到类似“一个真人都没有的爽剧正在让老外疯狂上头”这样的内容刷屏。第一次看到时很多人会把它当成短视频平台上的营销故事但真正做技术的人会发现这类爆款背后并不是什么玄学而是一套非常标准的 AIGC 内容生产链路。整部剧没有真人演员、没有实景拍摄角色由 AI 生成剧情由脚本驱动画面、配音、字幕全部可以批量产出制作成本被压得很低产能却可以拉得很高。这篇文章不打算分析爽剧的剧情套路和传播逻辑而是聚焦更核心的问题这种“一个真人演员都没有的短剧”到底是怎么做出来的作为开发者我们应该怎么把这条链路跑通我会从概念、环境、核心步骤、可运行代码、常见问题和工程化建议几个方面完整拆解一套最小可落地的“无真人短剧”生产方案。适合准备进入 AIGC 视频方向的同学也适合已经在做数字人、虚拟 IP、批量短视频素材的工程团队参考。1. 背景与核心概念1.1 无真人短剧是什么无真人短剧也叫 AIGC 短剧、虚拟短剧是指不使用真人演员、不搭实景而是通过 AI 生成角色形象、画面背景、配音和剧情片段的连续视频内容。观众看到的角色可能是虚拟都市女性、赛博侦探、古风侠客但这些角色在现实世界里并不存在完全是模型根据提示词和角色资产生成的。这类内容之所以能在海外内容平台上迅速走红本质上是因为它解决了传统短剧的两个痛点第一是拍摄成本高传统短剧需要演员、场地、灯光、道具制作周期以周甚至月计算第二是产能受限一部短剧动辄几十集真人拍摄很难做到“日更”。而 AIGC 短剧把内容生产变成了流水线剧本定下来之后分镜、关键帧、配音、字幕都可以通过工具链批量完成团队规模可以很小但产出速度非常快。需要明确的是这类内容之所以看起来“上头”核心不是因为技术本身有多炫酷而是因为内容组织方式已经完全工业化了。开发者如果只关注某一个 AI 画图工具很难理解整条链路。我们要做的是把从剧本到成片的每一个环节都拆开看看它们分别对应哪些技术、哪些工具、哪些可复用的代码。1.2 核心制作链路一条无真人短剧的生产链路可以拆成以下六个环节剧本与分镜先有剧情脚本再把剧情拆成一个个场景和镜头每个镜头包含角色、地点、动作、台词、时长。角色资产保证同一个角色在不同镜头中长得一致这是无真人短剧最容易翻车的地方。画面生成根据分镜生成关键帧再把静态关键帧变成动态视频片段。配音与音效为每个场景生成对应语言的配音并整理背景音乐或环境音。字幕与合成把每一句台词做成字幕文件叠加到对应时间轴上。剪辑成片将多个视频片段、配音、字幕合并成最终视频文件。这个链路里最核心的技术包括 Stable Diffusion 或类似扩散模型负责画面生成LoRA、IP-Adapter 负责角色一致性ControlNet 负责构图控制TTS 负责配音FFmpeg 负责剪辑合成。初学者不需要一次性掌握全部内容可以先把“静态关键帧 配音 字幕 FFmpeg 合成为一条短视频”这条最简链路跑通再逐步加入视频生成模型和角色一致性方案。1.3 为什么开发者适合切入这个方向无真人短剧的制作不仅适合内容创作者也非常适合开发者参与。原因在于整条链路里的绝大多数环节都可以通过 API、命令行工具和脚本自动化。传统视频制作依赖剪辑师手动操作而 AIGC 短剧生产可以做到“改一个 JSON 配置文件重新生成一条新剧情”。开发者切入这个方向天然有优势。我们可以用 Python 脚本批量调用模型接口可以用 FFmpeg 完成视频合成可以用 JSON 管理分镜数据可以用 SQLite 做素材资产库甚至可以把整条流水线封装成一个后台服务。对后端开发者来说这是一次把 AI 能力落地到具体业务场景的很好实践对于个人创作者来说掌握这套链路也能极大提升内容生产效率。2. 环境准备与版本说明2.1 硬件与运行环境在开始之前先明确运行环境。无真人短剧生产涉及图像生成模型建议使用带有 NVIDIA GPU 的机器显存至少 8GB。显存太小的话生成 720x1280 分辨率的关键帧会比较吃力通常需要把分辨率降下来或者使用 CPU 推理但速度会慢很多。操作系统方面Windows、Linux、macOS 都可以但本文中的命令以 Linux 和 macOS 风格为主Windows 用户需要把路径分隔符和 FFmpeg 命令做少量调整。Python 版本建议使用 3.10 或更高版本FFmpeg 需要提前安装并加入系统 PATH。不同机器环境差异较大版本需要根据实际项目调整本文重点演示配置思路。2.2 基础软件安装先检查本机环境# 检查 Python 版本 python --version # 检查 FFmpeg 是否可用 ffmpeg -version # 如果没有安装 FFmpeg在 Debian/Ubuntu 下可以使用 # sudo apt-get update sudo apt-get install ffmpeg接着创建项目目录并安装 Python 依赖。本文示例代码主要用到requests和标准库依赖不复杂mkdir ai_drama_demo cd ai_drama_demo python -m venv venv source venv/bin/activate pip install requests这里创建虚拟环境是推荐习惯避免把依赖装到全局环境里。后面如果需要接入其他 AI 服务再根据实际使用的工具补充依赖。2.3 项目目录结构为了后续工程化扩展建议按照下面的结构组织项目ai_drama_demo/ ├── scenes.json ├── generate_frames.py ├── generate_voice.py ├── generate_subtitle.py ├── build_clip.sh ├── output/ │ ├── frames/ │ ├── voice/ │ └── clips/ └── subtitle.srt目录拆分的目的是让每个环节独立。修改剧本时只要改scenes.json重新执行生成脚本就能得到新的成片。输出目录单独隔离方便清理和备份。3. 核心链路拆解3.1 剧本与分镜结构化无真人短剧的第一步是把自然语言写成的剧本变成机器可读的分镜数据。推荐使用 JSON 格式每个场景作为一个对象包含角色、地点、动作、台词、时长等字段。这样做的好处是后续程序可以通过循环遍历场景批量生成关键帧、配音和字幕。一个最小分镜可以设计成这样{ project: ai_drama_demo, fps: 30, resolution: [720, 1280], scenes: [ { id: 1, character: cyber_city_girl, location: neon_street, action: walking_towards_camera, line: I never expected to see you here., duration: 4 }, { id: 2, character: cyber_city_girl, location: rooftop, action: looking_at_city, line: This city belongs to us now., duration: 4 } ] }在这个 JSON 里fps表示目标视频帧率resolution表示输出分辨率scenes是场景数组。每个场景的duration是预计时长单位秒它会同时决定视频片段长度和字幕时间轴。实际项目中角色和地点字段可以对应更复杂的资产配置比如某个角色使用哪个 LoRA 模型、哪个种子值、哪张参考图。3.2 角色一致性的关键无真人短剧最常见的翻车点就是角色在不同镜头里长得不一样。上一秒还是金色长发下一秒就变成了黑色短发观众瞬间出戏。要解决这个问题不能只靠提示词里写一个名字而是需要建立角色资产。常见的角色一致性方案有几种。第一种是固定种子值相同提示词和相同种子下模型生成的面部特征会比较接近但很难做到完全一致。第二种是训练角色 LoRA 模型用十几张同一角色的图片微调出一个专属模型这是目前效果最稳定的方案。第三种是使用 IP-Adapter 或参考图控制在生成每一帧时传入角色参考图让模型模仿参考图的面部特征。对于个人创作者来说最推荐的做法是先固定种子值同时把角色的外貌描述写得很具体比如发色、发型、眼睛颜色、服装风格然后生成同一角色在不同场景下的关键帧。如果团队有工程能力再逐步训练 LoRA。不要指望单靠随机生成就能做出连贯剧情角色一致性是必须投入时间和资源的环节。3.3 从静态关键帧到动态视频生成静态关键帧只是第一步短剧需要的是动态画面。最简单的动态化方式是让关键帧在视频中保持静止然后通过 FFmpeg 添加缩放、平移等镜头运动制造出画面在动的错觉。这种方式成本最低适合对话场景和情绪镜头。更接近真实短剧效果的方式是把关键帧交给视频生成模型比如本地部署的 AnimateDiff或者其他商用视频生成工具生成一段 2 到 4 秒的短视频片段。这里需要注意视频生成模型对显存要求更高生成结果也更不稳定通常需要在关键帧之后再进行一次筛选把效果不好的片段重新生成。本文的实战 Demo 先用 FFmpeg 实现镜头运动因为它的可控性最强也最容易复现。等整套链路跑通之后再替换成 AI 视频生成模型不会影响其他环节。3.4 配音、口型与字幕配音方面目前可选方案很多常见做法是部署本地 TTS 服务或者使用云端 TTS API。无论用哪种方案都要确保生成音频的采样率和编码格式能被 FFmpeg 正常处理推荐输出 44.1kHz、MP3 或 WAV 格式。字幕方面可以直接用分镜 JSON 里的台词生成 SRT 字幕文件不需要经过语音识别因为台词是我们自己写的天然就是准确的。SRT 文件的时间轴与分镜时长对应一个场景对应一条字幕。口型同步是更复杂的问题。如果角色只是画外音或者远景可以不处理口型。如果是近景对话需要额外使用 Wav2Lip 一类的口型生成工具根据配音音频驱动角色嘴巴动作。口型同步是整条链路里成本较高的环节建议在基础流程跑通之后再接入。4. 实战用本地工具生成一条 8 秒短剧片段下面我们完整跑一个最小闭环生成一条 8 秒的无真人短剧片段。这条片段包含两个场景每个场景 4 秒使用本地 Stable Diffusion WebUI 生成关键帧使用本地 TTS 服务生成配音最后用 FFmpeg 合成字幕和视频。4.1 准备分镜 JSON在项目根目录创建scenes.json内容就是上一节给出的 JSON。把输出分辨率设置为 720x1280这样更接近竖屏短剧的格式。每个场景的duration都是 4 秒。4.2 调用本地绘图服务生成关键帧假设你本地已经启动了一个 Stable Diffusion WebUI并且启动参数中开启了 API。启动命令可以参考./webui.sh --api --listen --port 7860如果 WebUI 没有开启 API 参数后面调用接口时会直接失败。启动完成后编写generate_frames.pyimport base64 import json import pathlib import requests SD_URL http://127.0.0.1:7860/sdapi/v1/txt2img def load_scene_config(pathscenes.json): with open(path, r, encodingutf-8) as f: return json.load(f) def generate_frames(config): output_dir pathlib.Path(output/frames) output_dir.mkdir(parentsTrue, exist_okTrue) for scene in config[scenes]: # 把角色、地点、动作组成提示词模板 prompt ( fmasterpiece, best quality, {scene[character]}, f{scene[location]}, {scene[action]}, cinematic lighting, detailed face, short drama style ) negative_prompt blurry, low quality, watermark, text, bad hands payload { prompt: prompt, negative_prompt: negative_prompt, width: config[resolution][0], height: config[resolution][1], steps: 25, cfg_scale: 7.0, seed: 42, batch_size: 1, } resp requests.post(SD_URL, jsonpayload, timeout120) resp.raise_for_status() # 接口返回的 images 字段是 base64 字符串列表 image_data base64.b64decode(resp.json()[images][0]) output_path output_dir / fscene_{scene[id]:02d}_keyframe.png output_path.write_bytes(image_data) print(fsaved: {output_path}) if __name__ __main__: cfg load_scene_config() generate_frames(cfg)这段代码里关键点是payload中的参数。steps是采样步数越大细节越多但速度越慢cfg_scale是提示词引导强度通常在 7 到 9 之间seed固定为 42这样可以保证对同一提示词生成结果可复现。实际项目中seed可以配置在scenes.json里每个角色使用不同种子。运行脚本python generate_frames.py正常情况下output/frames目录下会生成两张关键帧图片scene_01_keyframe.png和scene_02_keyframe.png。4.3 生成配音与字幕配音阶段我提供一段通用的封装代码。你的本地 TTS 服务可能是 GPT-SoVITS、CosyVoice也可能是其他工具请求格式会不同只需要把TTS_URL和请求参数改成实际工具对应的格式即可。import json import pathlib import requests # 替换成你本地部署的 TTS 服务地址和请求格式 TTS_URL http://127.0.0.1:9880/tts def generate_voice(config): output_dir pathlib.Path(output/voice) output_dir.mkdir(parentsTrue, exist_okTrue) for scene in config[scenes]: params { text: scene[line], speaker: default, } resp requests.get(TTS_URL, paramsparams, timeout60) resp.raise_for_status() output_path output_dir / fvoice_{scene[id]:02d}.mp3 output_path.write_bytes(resp.content) print(fsaved voice: {output_path}) if __name__ __main__: with open(scenes.json, r, encodingutf-8) as f: cfg json.load(f) generate_voice(cfg)字幕文件不需要识别语音直接从分镜 JSON 里的台词生成。创建generate_subtitle.pyimport json def scenes_to_srt(scenes, srt_pathsubtitle.srt): lines [] index 1 cursor 1 for scene in scenes: start cursor end cursor scene[duration] lines.append(str(index)) lines.append(f{format_time(start)} -- {format_time(end)}) lines.append(scene[line]) lines.append() index 1 cursor end with open(srt_path, w, encodingutf-8) as f: f.write(\n.join(lines)) def format_time(seconds: int) - str: h seconds // 3600 m (seconds % 3600) // 60 s seconds % 60 return f{h:02d}:{m:02d}:{s:02d},000 if __name__ __main__: with open(scenes.json, r, encodingutf-8) as f: cfg json.load(f) scenes_to_srt(cfg[scenes])运行python generate_subtitle.py后项目根目录会出现subtitle.srt。这个字幕文件的时间轴是从第 1 秒开始每个场景 4 秒所以两个场景分别对应 1 到 5 秒、5 到 9 秒。4.4 用 FFmpeg 合成最终视频现在我们把两张关键帧、两段配音和字幕合成一段竖屏视频。创建build_clip.sh#!/usr/bin/env bash set -euo pipefail # 1. 将每个关键帧扩展为 4 秒视频片段 ffmpeg -y -loop 1 -framerate 30 -i output/frames/scene_01_keyframe.png -t 4 -vf scale720:1280 -c:v libx264 -pix_fmt yuv420p output/scene_01.mp4 ffmpeg -y -loop 1 -framerate 30 -i output/frames/scene_02_keyframe.png -t 4 -vf scale720:1280 -c:v libx264 -pix_fmt yuv420p output/scene_02.mp4 # 2. 拼接视频片段 ffmpeg -y -i output/scene_01.mp4 -i output/scene_02.mp4 -filter_complex [0:v][1:v]concatn2:v1:a0[v] -map [v] -c:v libx264 -pix_fmt yuv420p output/concat_no_audio.mp4 # 3. 合并两个场景的配音 ffmpeg -y -i output/voice_01.mp3 -i output/voice_02.mp3 -filter_complex [0:a][1:a]concatn2:v0:a1[a] -map [a] -c:a aac output/voice_full.m4a # 4. 添加配音与字幕输出最终视频 ffmpeg -y -i output/concat_no_audio.mp4 -i output/voice_full.m4a -vf subtitlessubtitle.srt -c:v libx264 -c:a aac -shortest -pix_fmt yuv420p output/drama_clip.mp4给脚本添加可执行权限并运行chmod x build_clip.sh ./build_clip.sh如果 FFmpeg 提示subtitlesfilter 不可用说明当前 FFmpeg 构建没有包含 libass可以改用drawtext绘制字幕或者重新安装一个完整版 FFmpeg。4.5 运行与验证全部命令执行成功后output/drama_clip.mp4就是最终成片。播放这个文件你应该能看到前 4 秒是一个赛博朋克风格的女性角色在霓虹街道上行走画面下方有第一句英文字幕。第 4 秒到第 8 秒切换到屋顶场景角色看向城市第二句字幕出现。配音与字幕时间轴基本对应画面比例是 720x1280 的竖屏。到这里一条最简单的无真人短剧片段已经跑通了。虽然画面还很静态但整条生产链路是完整的后续每一步优化都可以在这个基础上迭代。5. 常见问题与排查思路问题现象常见原因解决思路角色在不同镜头中长相不一致没有使用固定 seed、LoRA 或参考图统一角色描述固定 seed使用 IP-Adapter 或训练 LoRA视频画面闪烁严重静态图直接生成动态片段模型不稳定减少镜头运动幅度固定关键帧加入筛选和重生成流程口型与配音不同步没有使用口型驱动模型近景对话场景接入 Wav2Lip远景可不处理FFmpeg 提示 subtitle 滤镜无效当前 FFmpeg 缺少 libass 支持换用 drawtext 滤镜或重新安装完整版 FFmpeg音频与视频时长不一致配音时长超过场景预设时长在分镜数据中加入音频时长字段动态计算字幕时间轴显存不足导致出图失败分辨率或批量大小设置过高降低分辨率减少 batch_size开启 xformers 或换更大显存5.1 角色脸部不一致这个问题主要出现在没有做角色资产的情况下。解决步骤是先为角色写一份固定的外貌描述放入提示词模板然后固定 seed确保相同描述生成的面部特征稳定如果还是不理想选择几张满意图片训练 LoRA或者使用 IP-Adapter 传入角色参考图。注意不要在一次生成中频繁改变描述描述越稳定角色越一致。5.2 画面动态不够或者闪烁本文 Demo 使用的是静态关键帧加 FFmpeg 缩放所以不会有闪烁问题。如果替换成 AnimateDiff 等视频生成模型闪烁通常来自帧间颜色和纹理不稳定。排查时可以先检查关键帧是否清晰再降低生成视频的帧数和运动幅度最后在后期用调色滤镜统一色调。人工筛选仍然是当前视频生成流程中不可缺少的一环。5.3 字幕播放乱码或位置不对SRT 文件使用 UTF-8 编码但在 Windows 上FFmpeg 默认可能使用系统编码读取。如果你遇到中文乱码可以先把 SRT 文件转为 UTF-8 without BOM或通过subtitlesfilter 的force_style参数指定字体ffmpeg -i input.mp4 -vf subtitlessubtitle.srt:force_styleFontNameNoto Sans CJK SC output.mp4字体名称需要和系统已安装字体一致否则仍然会回退为默认字体。6. 工程化与内容合规建议6.1 把提示词当成配置文件管理实战示例中提示词是拼在 Python 代码里的。项目变大后建议把提示词模板独立成配置文件每个角色一个 Prompt 片段每个场景只写差异化内容。比如在scenes.json中增加prompt_extra字段或者单独维护characters/目录每个角色包含设定图、描述词、LoRA 路径、seed 等字段。这样团队协作时角色资产可以复用不需要每个镜头重新设计。6.2 建立素材筛选与版本管理AI 生成不是每次都能成功尤其是加入视频生成模型后废片率会明显上升。工程化时需要在流水线中增加人工审核步骤对关键帧和视频片段进行抽帧检查。建议为每个生成任务记录参数哈希、时间戳、模型版本、seed、提示词方便追溯和重新生成。素材库可以使用普通文件目录加 SQLite 元数据不必一开始就引入复杂系统。6.3 版权与 AI 内容标识生成式 AI 内容在生产和使用中需要特别注意版权与合规风险。不能使用真实人物肖像、知名品牌标志、受版权保护的角色形象作为生成目标。发布到任何内容平台之前需要确认目标平台对 AI 生成内容的标识要求。很多平台要求创作者主动标记 AI 生成内容这既是对观众的尊重也是降低账号风险的手段。即使内容本身是虚构的也要避免生成涉及暴力、歧视、虚假信息等违规内容。6.4 自动化与监控当整个流程跑通后可以把generate_frames.py、generate_voice.py、generate_subtitle.py、build_clip.sh串成一个 Python 调度的流水线甚至封装成 HTTP 服务。每次只需要提交一个剧本 JSON就能批量生成多条视频素材。生产环境中需要监控每一步的成功率比如图片生成失败、TTS 服务超时、FFmpeg 编码报错都需要有日志记录和异常告警。可以先从最简单的时间戳日志开始后续再接入消息队列和任务队列。7. 总结与下一步从这篇文章的实战示例可以看到做出一条“没有真人演员”的竖屏短剧片段技术上并不复杂。核心流程是分镜 JSON 驱动 → 本地绘图模型生成关键帧 → TTS 生成配音 → 从 JSON 生成字幕 → FFmpeg 合成视频。只要把这条链路跑通你已经有能力批量制作基础版 AI 短剧素材了。下一步可以继续深入的方向包括用 LoRA 训练专属角色模型把静态关键帧替换为 AnimateDiff 动态视频片段接入 Wav2Lip 实现口型同步把整条链路封装成服务端任务系统。相比提升单个环节的画质更值得优先投入的是角色一致性和流程自动化这两点直接决定内容的可看性和生产效率。如果你也想自己做一条 AI 短剧建议从今天的 8 秒 Demo 开始先跑通链路再逐步替换和优化每个环节。