一句话剧本进去,一集动态漫剧出来。这篇我把自己搭这套系统踩的坑、用的接口、跑通的链路,原原本本写给你。
写在前面
最近"AI 漫剧"特别火——就是那种由 AI 生成画面、配上运镜和配音的动态漫画短剧,一条几分钟,刷起来很上头。
很多人以为这玩意儿得一帧帧画。其实不是。真正的做法是把整条生产线拆成几个环节,每个环节交给一个专门的 Agent,再用一个中转 API 把背后的各种大模型统一接进来。 我这套系统跑下来,从"一句话主题"到"一集成片",人基本只需要在两三个关键点上点头确认。
这篇就带你把这个网站从零搭起来。我会把架构、每个环节怎么接、关键代码、以及中途接入 4sapi.com 这个中转 API的具体步骤都讲清楚。素材和接口都是我实际跑通的,你照着走就行。
一、先看清楚:漫剧到底是怎么"生产"出来的
动手写代码之前,得先把生产链路理顺。一集 AI 漫剧,本质上是这五个环节顺序跑下来的产物:
① 剧本生成 主题/梗概 → 分场景的剧本文本
↓
② 分镜拆解 剧本 → 一个个镜头(画面描述 + 运镜 + 台词)
↓
③ 文生图 每个镜头的画面描述 → 关键帧图片
↓
④ 图生视频 关键帧 → 带运镜/动效的视频片段
↓
⑤ 配音合成 台词 → 配音,再和视频片段剪辑成片
这五步里,①②靠大语言模型,③靠文生图模型,④靠图生视频模型,⑤靠语音合成(TTS)模型。
问题来了——这么多种模型,分散在不同厂商,每家的接口、鉴权、计费都不一样。如果挨个去对接官方 API,光是申请账号、管理一堆 Key 就够你头疼了。这正是我们中途要引入中转 API 的原因。
二、架构设计:五个 Agent + 一个中转网关
我把整个系统设计成"一个总调度 + 五个环节 Agent + 一个统一 API 网关"的结构:
┌─────────────────────────┐
用户输入主题 ──→ │ Orchestrator 总调度 │
└───────────┬─────────────┘
│ 按顺序派活
┌───────────┬──────────┼──────────┬───────────┐
↓ ↓ ↓ ↓ ↓
[剧本Agent] [分镜Agent] [文生图Agent] [视频Agent] [配音Agent]
└───────────┴──────────┼──────────┴───────────┘
↓
┌─────────────────────────┐
│ 统一 API 网关 (4sapi) │ ← 所有模型调用都走这里
└─────────────────────────┘
关键设计点在最下面那层:所有 Agent 不直接去调各家官方 API,而是统一走一个中转网关。 这样做的好处是实打实的:
- 一个 Key 调所有模型:文本、图像、视频、语音,全用同一套 OpenAI 兼容格式,不用为每个厂商单独管理凭证;
- 切换模型零成本:今天用这个文生图模型,明天想换一个,只改一个
model 参数;
- 计费集中:所有消耗在一个后台看,不用跨多个平台对账。
我选的中转网关是 4sapi.com,它兼容 OpenAI 格式,主流的文本/图像/视频/语音模型基本都能通过它调用,正好覆盖漫剧需要的全部环节。
三、中途接入 4sapi:三步把网关接通
这是全篇最关键的一节。前面的架构再漂亮,跑不通模型也是白搭。接入中转 API 其实就三步,我按顺序讲。
第一步:拿 Key、记住 BaseURL
注册 4sapi.com 后,在后台创建一个 API 令牌(也就是 API Key),形如 sk-xxxxxxxx。同时记下它的接口地址(BaseURL),通常是这种形式:
把这两样东西放进环境变量,千万别硬编码进代码——这是基本的安全习惯:
bash
# .env
FOURSAPI_BASE_URL=https://4sapi.com/v1
FOURSAPI_KEY=sk-你的令牌
第二步:封装一个统一客户端
因为 4sapi 兼容 OpenAI 格式,我们可以直接用 openai 这个 SDK,只要把 base_url 指过去就行。封装一个客户端,后面所有 Agent 都复用它:
python
# gateway.py —— 统一 API 网关客户端
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["FOURSAPI_KEY"],
base_url=os.environ["FOURSAPI_BASE_URL"], # 关键:指向中转网关
)
def chat(model, messages, **kwargs):
"""文本类调用:剧本、分镜都用它"""
resp = client.chat.completions.create(
model=model, messages=messages, **kwargs
)
return resp.choices[0].message.content
第三步:发一个请求验证连通
接完别急着写业务,先发个最小请求确认网关通了:
python
# 连通性自检
if __name__ == "__main__":
out = chat(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "回复两个字:通了"}],
)
print(out) # 正常应打印「通了」
能打印出结果,说明网关接通,后面五个 Agent 就都能复用这个客户端了。整个接入过程,本质就是「改一个 base_url + 配一个 Key」这么简单。
四、逐个环节实现:五个 Agent 怎么写
网关通了,接下来是把五个环节填上。我挑关键代码讲。
4.1 剧本 Agent —— 把主题变成分场景剧本
python
def script_agent(theme):
prompt = f"""你是资深短剧编剧。请把下面的主题扩写成一集 4-6 个场景的漫剧剧本。
每个场景包含:场景描述、人物、台词。主题:{theme}"""
return chat(
model="gpt-4o", # 文本模型走网关
messages=[{"role": "user", "content": prompt}],
temperature=0.8,
)
4.2 分镜 Agent —— 把剧本拆成一个个镜头
这一步是承上启下的枢纽。它要把剧本拆成结构化的镜头清单,每个镜头必须包含一段精确的画面描述(后面文生图直接拿它当 prompt):
python
import json
def storyboard_agent(script):
prompt = f"""把以下剧本拆解成镜头列表,输出 JSON 数组。
每个镜头含字段:shot_id, visual_prompt(画面英文描述,用于文生图),
camera(运镜), dialogue(台词)。剧本:{script}"""
raw = chat(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}],
response_format={"type": "json_object"},
)
return json.loads(raw)["shots"]
4.3 文生图 Agent —— 镜头描述变关键帧
注意:漫剧最难的是角色一致性——同一个角色在不同镜头里得长得像同一个人。我的处理办法是给所有镜头注入一段统一的"角色锚定描述 + 固定画风",并固定随机种子:
python
def image_agent(shot, role_anchor, seed=42):
# 角色锚定 + 画风,拼到每个镜头的画面描述前面
full_prompt = f"{role_anchor}, {shot['visual_prompt']}, comic style, consistent character"
resp = client.images.generate(
model="flux-dev", # 文生图模型,同样走网关
prompt=full_prompt,
size="1024x1024",
# 固定 seed 是保持角色一致性的关键手段之一
extra_body={"seed": seed},
)
return resp.data[0].url
角色一致性是漫剧的命门。除了 seed + 锚定描述,更进阶的做法是用同一张角色参考图做"图生图"或走专门的角色 LoRA,这里先用最省事的方案跑通。
4.4 视频 Agent —— 关键帧动起来
把每个关键帧送进图生视频模型,加上分镜里指定的运镜:
python
def video_agent(image_url, camera):
resp = client.post( # 图生视频接口走网关
"/videos/generations",
body={
"model": "kling-v1", # 图生视频模型
"image": image_url,
"motion": camera, # 运镜:推、拉、摇等
"duration": 4,
},
)
return resp["video_url"]
4.5 配音 Agent —— 台词变声音
python
def voice_agent(dialogue, voice="zh-female-1"):
resp = client.audio.speech.create(
model="tts-1", # 语音合成模型走网关
voice=voice,
input=dialogue,
)
return resp.content # 音频二进制
五、串起来:总调度跑通一整集
五个 Agent 都有了,总调度做的事就是按顺序把它们串成流水线:
python
def make_drama(theme):
# ① 剧本
script = script_agent(theme)
# ② 分镜
shots = storyboard_agent(script)
# 给本集定一个统一的角色锚定描述
role_anchor = "a young girl with short blue hair, red jacket"
clips = []
for shot in shots:
# ③ 文生图
frame = image_agent(shot, role_anchor)
# ④ 图生视频
clip = video_agent(frame, shot["camera"])
# ⑤ 配音
audio = voice_agent(shot["dialogue"])
clips.append({"video": clip, "audio": audio})
# 最后用 ffmpeg 把片段 + 配音合成成片
return compose(clips)
注意所有模型调用——文本、图像、视频、语音——全部走同一个 4sapi 网关,一个 Key 搞定。这就是统一网关最爽的地方:业务代码里你几乎感觉不到背后接了多少家不同的模型。
六、前端:给非技术用户一个能点的界面
后端跑通后,前端我用 React + 一个简单的进度条就够了。核心是把这条流水线的进度可视化,让用户知道现在跑到哪一步:
jsx
function DramaMaker() {
const [theme, setTheme] = useState("");
const [stage, setStage] = useState(""); // 当前环节
const stages = ["剧本", "分镜", "生成画面", "生成视频", "配音合成"];
async function run() {
const res = await fetch("/api/make", {
method: "POST",
body: JSON.stringify({ theme }),
});
// 用 SSE 或轮询实时更新 stage
}
return (
<div>
<input value={theme} onChange={e => setTheme(e.target.value)}
placeholder="输入一句话主题,比如:少女与机器猫的冒险" />
<button onClick={run}>一键生成漫剧</button>
<Progress stages={stages} current={stage} />
</div>
);
}
安全提醒:这个 /api/make 接口背后会消耗真金白银(每次生成都在烧 token 和算力),上线前一定要加上用户鉴权和调用频率限制,别让接口裸奔——否则被人刷一晚上,账单能让你心梗。
七、几条实战经验
跑通之后,我总结了几条真正省钱省心的经验:
- 分镜环节务必输出结构化 JSON。我一开始让模型输出自然语言,结果后面解析全是坑。强制
json_object 格式,下游处理顺畅太多。
- 图先批量生成、让用户筛一轮再做视频。图生视频是整条线里最贵最慢的环节。先把关键帧都生成出来,让用户挑/重抽满意了,再统一进入视频环节,能省下大量无效算力。
- 角色锚定描述抽出来做成全局变量。一集里所有镜头共用,别让模型每次自由发挥,否则角色长相会飘。
- 网关调用加重试和超时。视频生成耗时长、偶尔会超时,给每个 Agent 的调用包一层重试装饰器,别一次失败就整集崩。
- 小模型干粗活,大模型干精活。剧本润色这种可以用
gpt-4o-mini,关键的分镜拆解再上 gpt-4o,token 账单立刻下来一截。
写在最后
回头看,搭一个 AI 漫剧网站,难点根本不在"会不会调某个模型",而在怎么把分散的能力编排成一条稳定的流水线。
五个 Agent 各管一段,一个中转网关统一接入——这套结构想清楚了,剩下的就是填代码。
中途接入 4sapi 这一步,本质上把"对接七八家厂商"的脏活,收敛成了"改一个 base_url"。这是我觉得整套方案里最值得借鉴的地方:把复杂度挡在网关后面,让业务代码保持干净。
下一篇我会写姊妹篇——用同样的思路搭一个 AI 漫画制作网站,那边的重点会落在分镜排版和角色一致性上,欢迎接着看。
本文代码为说明思路的简化示意,具体模型名称、接口字段请以 4sapi.com 官方文档为准。涉及付费接口,请做好用量控制。