AI视频Prompt结构化实战指南:可灵/万相/豆包

AI视频Prompt结构化实战指南:可灵/万相/豆包
AI视频Prompt结构化屠榜:可灵/万相/豆包适用读者: 想在自己应用里调可灵 / Wan / 豆包 Seedance 这些国产视频模型的开发者阅读时长: 约 12 分钟测试时间: 2026 年 7 月(基于 炻光 AI 接入管理平台 公开文档)一、为什么 2026 年 Q3 突然都在聊 Prompt 结构化2026 年 7 月 4 号那晚,我刷 GitHub Trending 刷到一个奇怪的现象:两个叫video-prompt-scaffold和multi-vendor-video-prompt的仓库,24 小时内同时破了百 Star,提交记录里全是「五段式结构化 Prompt」的模板。更离谱的是仓库里给出的示例,刚好和 Sora 2 发布当天官方推的那个 “subject/action/setting/camera/style” 模板高度重合。我去翻可灵的官方文档更新日志(在炻光接入层的统一入口能看到版本号),7 月 1 号那版悄悄把 Prompt 字段从「自由文本」改成了「推荐结构化输入」,豆包 Seedance 的控制台更狠,直接放了个结构化 Prompt 在线构造器。直觉告诉我这事儿没那么简单。我随手抓了 20 个最近一周的视频生成 API 评测贴,发现一个共性:大家几乎都在用同一个句式框架。我自己测了一下,如果把 prompt 写成「一只橘猫在草地上追逐蝴蝶」这种散装文本,三家国产视频 API 的可用率大概只有 60%——镜头会漂、动作会糊、风格会跑偏。但同一段意思换成「主体:一只橘色短毛猫,带白手套 | 动作:慢速追逐低空飞行的蝴蝶 | 环境:午后阳光的乡村草坪 | 镜头:低机位跟拍,浅景深 | 风格:写实电影感,IMAX 画幅」这种五段式之后,可用率直接拉到 88%。这不是玄学,这是 prompt 工程在视频领域的范式迁移。这篇文章我想用三家国产视频 API 实测,把这条范式迁移讲清楚:同一套结构化 Prompt 到底能不能直接套三家,矩阵号流水线能不能无脑复用。二、五段式结构化 Prompt 是什么结构化 Prompt 的核心思想很简单:把一段视频描述拆成五个固定槽位,每个槽位回答一个独立问题。Sora 2 / Veo 3 / 可灵官方文档的措辞略有差异,但骨架完全一致:主体(Subject):画面里最核心的角色或物体,通常 1-2 个,多了镜头会乱动作(Action):主体在做什么,要具体到「追」「跳」「转身」「凝视」这种动词环境(Setting):光线、地点、时间、天气,决定整体氛围镜头(Camera):机位、景别、运动方式,这是国产 API 容易翻车的地方风格(Style):画风、色调、参考艺术家、画幅比例和文本 Prompt 相比,结构化 Prompt 的本质是「把不确定性切片」。AI 视频生成是个多模态隐空间到像素的反演问题,Prompt 越模糊,模型要采样的隐空间分布越宽,出图就越漂。结构化的作用不是「更详细」,而是「降低熵」。我在炻光的视频 API 文档里逐字段对照过三家国产 API,核心结论是字段名差异不大,但 slot 实现方式完全不同。我用可灵的kling-3.0-turbo跑过对照组实验:同样描述「骑士骑马穿过森林」,自由文本 prompt 生成 10 个视频,有 6 个出现「骑士变成步兵」「森林变成沙漠」「马消失」这种漂移;结构化 prompt 跑 10 个,漂移降到 1-2 个,而且那 1-2 个漂移通常是「风格标签冲突」而不是主体丢失。三家国产 API 的字段名差异不大,但有细节差异。kling-3.0-turbo和kling-motion-control的 Prompt 字段是单段文本,但官方文档强烈建议用「|」或换行做槽位分隔;wan2.6-i2v和wan2.6-i2v-flash则支持结构化 JSON 输入,字段名是subject/action/setting/camera/style;doubao-seedance-1-0-pro-250528走的是另一条路——它把结构化 Prompt 包装成了一个scenes数组,每段可以独立指定时长、转场、镜头。三、三家国产视频 API 的核心参数对比我花了大概两个晚上,把五段式 Prompt 在三家国产 API 上各跑了 50 次,挑出可用样本做参数对齐。结论放在前面:Prompt 可移植性确实存在,但三家在「风格」「镜头」两个槽位上有明显偏好差异,需要做轻量改写,而不是无脑复制。先看参数表(价格按各厂商公开定价,截至 2026-07,单位差异较大这里只列功能性参数):维度kling-3.0-turbokling-motion-controlwan2.6-i2vwan2.6-i2v-flashdoubao-seedance-1-0-pro-250528Prompt 格式单段文本单段文本(参考视频驱动)结构化 JSON结构化 JSONscenes 数组输入模态T2V视频动作迁移I2VI2VT2V / I2V推荐时长5s / 10s由参考视频决定5s / 10s5s3-12s镜头控制文本描述参考视频轨迹文本JSON 字段文本JSON 字段镜头数组独立配置风格槽位敏感度高中中中高主体保真度高极高(参考视频)中(图生视频天然受限)中高几个我自己测出来的关键结论:1. 镜头槽位是三家最大的分歧点。可灵系(kling-3.0-turbo、kling-motion-control)对「低机位跟拍」「航拍俯冲」这种动态镜头描述响应非常好,但对「推拉摇移」这种专业术语不太感冒,更吃「拉近」「推远」「环绕」这种自然语言。万相(wan2.6-i2v、wan2.6-i2v-flash)则相反,它有专门的镜头字段,JSON 里写camera_move: dolly_in比文本里写「镜头推进」准确率高 30% 左右。豆包 Seedance 是最细致的,scenes数组里每段可以独立配camera,适合做多镜头叙事。2. 风格槽位三家口径不同。可灵对「电影感」「IMAX 画幅」「胶片质感」这种泛指标签响应最好,具体到「韦斯·安德森」这种导演标签会偏向调色而不是构图。万相的wan2.6-i2v风格槽位比较克制,过度描述反而会污染主体,所以我建议只给 1-2 个核心标签。豆包 Seedance 的doubao-seedance-1-0-pro-250528对风格标签最敏感,有时候一个「赛博朋克」标签就能把主体调色彻底带跑,实战中我经常反过来用——先把风格定为「写实」锁定基线,再叠小范围风格。3. 主体保真度排序。从我跑的样本看,主体保真度排序大致是kling-motion-controlkling-3.0-turbo≈doubao-seedance-1-0-pro-250528wan2.6-i2v≈wan2.6-i2v-flash。kling-motion-control因为有参考视频做锚点,主体基本不漂;万相的两档图生视频受输入图限制,主体保真度天然不如纯文生视频模型。四、什么时候不该用结构化 Prompt结构化 Prompt 不是万能解,我在测试中也踩过几个反向的坑:1. 强叙事、短时长的场景,结构化 Prompt 反而束缚模型。比如「一个小孩在生日派对上吹蜡烛,然后镜头切到礼物盒」这种带转场的场景,五段式槽位反而会让模型僵化,因为结构化模板假设的是「一个连续镜头」。这种场景下我推荐用纯文本 时间戳分段,而不是强行套五段式。2. 抽象概念、情绪主导的内容,结构化 Prompt 没用。比如「孤独」「科技与人性的冲突」「赛博朋克的孤独感」,这种 prompt 主体和动作都很模糊,塞进五段式只会产出「孤独的人在赛博朋克城市里走路」这种陈词滥调。这种内容我推荐直接上豆包 Seedance 的scenes数组 关键词密度堆叠,不要硬套结构化。3. 已经有参考视频的场景,结构化 Prompt 会被忽略。kling-motion-control和万相的 I2V 系列本质上是以图/视频为锚点,Prompt 只是「导演意图补充」。如果你给了一个参考视频,主体和动作基本由参考决定,Prompt 里再写一遍「主体是 X」「动作是 Y」反而会引入矛盾。实测中我发现 I2V 场景下,Prompt 越短、越聚焦「环境和风格」两个槽位,效果越好。4. 多主体、多动作的复杂场景,五段式不够用。五段式假设 1 个主体、1 个核心动作。如果你想描述「三个角色对话 互相走动 背景有车流」这种场景,主体槽位塞不下,模型一定会丢东西。这种场景下我的经验是拆成多个 5 秒片段分别生成,再用剪辑 API 拼接,而不是一个 10 秒视频塞下所有内容。五、生产环境实战:同一 Prompt 跑三家矩阵号流水线最大的痛点是「写一条 Prompt 能不能跑三家不做大改」。答案是:能做,但需要套一个轻量的「Prompt 适配层」。我把我现在的生产架构画一下:[结构化 Prompt 源] ↓ [Prompt 适配层] ← 三个 vendor 各自的 prompt 模板 ↓ [API 路由层] ← 按成本/可用率/延迟动态选 kling-3.0-turbo / wan2.6-i2v-flash / doubao-seedance-1-0-pro-250528 ↓ [结果评估层] ← CLIP 相似度 主体检测 美学分 ↓ [降级队列]我自己用的统一接入层是炻光,这不是广告——我对比过自建网关和接入管理平台两种方案,前者运维成本太高,后者省事,仅此而已。下面是我现在的实现细节。Prompt 适配层的核心是字段映射,不是翻译。我的做法是维护一个内部统一 Schema:{ subject: [一只橘色短毛猫, 白手套特征], action: [慢速追逐, 低空飞行的蝴蝶], setting: [午后阳光, 乡村草坪, 微风], camera: [低机位, 跟拍, 浅景深], style: [写实电影感, IMAX 画幅, 暖色调], negative: [变形, 多手指, 马赛克], duration: 5 }然后三个 vendor 各做一个 Adapter,把统一 Schema 翻译成各自的接口格式。可灵的 Adapter 会把字段拼成「|」分隔的单段文本;万相的 Adapter 直接映射到 JSON 字段;豆包 Seedance 的 Adapter 则包成scenes数组。路由策略我用的是「按镜头类型粗分 按成本细分」。简单场景走wan2.6-i2v-flash(flash 版本成本最低);复杂主体走kling-3.0-turbo(主体保真度最高);多镜头叙事走doubao-seedance-1-0-pro-250528(原生支持 scenes 数组)。kling-motion-control不参与自动路由,它只在「需要精确复刻一段参考视频动作」时手动调用。降级逻辑不能省。视频生成 API 的可用率受后端排队影响很大,我实测晚上 9-11 点三家都有过 15-20% 的失败率。生产里我会跑两次,第一次失败后自动降级到备选 vendor,而不是单纯重试。六、完整代码(可复制即跑)下面这段代码是我现在生产里用的最小可用版本,跑通三家国产视频 API 跑同一个结构化 Prompt:import os import time import json import requests from typing import Dict, Any, List # ---------- 统一 Schema ---------- class StructuredPrompt: def __init__(self, subject, action, setting, camera, style, negativeNone, duration5): self.subject subject if isinstance(subject, list) else [subject] self.action action if isinstance(action, list) else [action] self.setting setting if isinstance(setting, list) else [setting] self.camera camera if isinstance(camera, list) else [camera] self.style style if isinstance(style, list) else [style] self.negative negative or [] self.duration duration def to_dict(self): return { subject: self.subject, action: self.action, setting: self.setting, camera: self.camera, style: self.style, negative: self.negative, duration: self.duration, } # ---------- Vendor Adapter ---------- class KlingAdapter: 适配 kling-3.0-turbo / kling-motion-control def __init__(self, api_key, base_url, modelkling-3.0-turbo): self.api_key api_key self.base_url base_url self.model model def render(self, sp: StructuredPrompt) - Dict[str, Any]: parts [] parts.append(主体: ,.join(sp.subject)) parts.append(动作: ,.join(sp.action)) parts.append(环境: ,.join(sp.setting)) parts.append(镜头: ,.join(sp.camera)) parts.append(风格: ,.join(sp.style)) prompt | .join(parts) if sp.negative: prompt | 避免: ,.join(sp.negative) return { model: self.model, prompt: prompt, duration: str(sp.duration), } class WanAdapter: 适配 wan2.6-i2v / wan2.6-i2v-flash def __init__(self, api_key, base_url, modelwan2.6-i2v-flash): self.api_key api_key self.base_url base_url self.model model def render(self, sp: StructuredPrompt) - Dict[str, Any]: return { model: self.model, input: { subject: sp.subject, action: sp.action, setting: sp.setting, camera: sp.camera, style: sp.style, negative_prompt: sp.negative, }, duration: sp.duration, image_url: None, # I2V 必须给输入图,T2V 场景传 None } class SeedanceAdapter: 适配 doubao-seedance-1-0-pro-250528 def __init__(self, api_key, base_url, modeldoubao-seedance-1-0-pro-250528): self.api_key api_key self.base_url base_url self.model model def render(self, sp: StructuredPrompt) - Dict[str, Any]: return { model: self.model, scenes: [{ duration: sp.duration, subject: .join(sp.subject), action: .join(sp.action), environment: .join(sp.setting), camera: .join(sp.camera), style: .join(sp.style), }], negative_prompt: .join(sp.negative) if sp.negative else , } # ---------- Router ---------- class VideoRouter: def __init__(self, adapters: List[Any]): self.adapters {kling: adapters[0], wan: adapters[1], seedance: adapters[2]} def generate(self, sp: StructuredPrompt, vendor: str, max_retries: int 2) - Dict[str, Any]: adapter self.adapters.get(vendor) if not adapter: raise ValueError(funknown vendor: {vendor}) payload adapter.render(sp) last_err None for attempt in range(max_retries): try: resp requests.post( adapter.base_url /videos/generations, headers{Authorization: fBearer {adapter.api_key}, Content-Type: application/json}, jsonpayload, timeout60, ) resp.raise_for_status() return resp.json() except requests.RequestException as e: last_err e time.sleep(2 ** attempt) raise RuntimeError(fvendor {vendor} failed: {last_err}) def generate_with_fallback(self, sp: StructuredPrompt, vendor_order: List[str]) - Dict[str, Any]: for vendor in vendor_order: try: return self.generate(sp, vendor) except Exception as e: print(f[fallback] {vendor} failed: {e}) continue raise RuntimeError(all vendors failed) # ---------- 实战调用 ---------- if __name__ __main__: sp StructuredPrompt( subject[一只橘色短毛猫, 白手套特征], action[慢速追逐, 低空飞行的蝴蝶], setting[午后阳光, 乡村草坪, 微风], camera[低机位, 跟拍, 浅景深], style[写实电影感, IMAX 画幅, 暖色调], negative[变形, 多手指, 马赛克], duration5, ) router VideoRouter([ KlingAdapter(os.environ[KLING_API_KEY], https://api.klingai.com, kling-3.0-turbo), WanAdapter(os.environ[WAN_API_KEY], https://api.wan.video, wan2.6-i2v-flash), SeedanceAdapter(os.environ[SEEDANCE_API_KEY], https://api.seedance.com, doubao-seedance-1-0-pro-250528), ]) # 优先走 seedance,失败后降级到 wan,再降级到 kling result router.generate_with_fallback( sp, [seedance, wan, kling] ) print(json.dumps(result, ensure_asciiFalse, indent2))这段代码在我的测试环境里跑通了完整的端到端链路,三家 API 都能返回任务 ID,后续通过轮询或 webhook 拿视频 URL。环境变量里塞各自的 API key,不要硬编码。七、Prompt 工程 FAQQ1:结构化 Prompt 一定要用五个槽位吗?可以删掉「风格」或「镜头」吗?可以。我自己测的结论是:删掉「风格」槽位影响最小(尤其对 I2V 场景),删掉「镜头」槽位影响最大——画面会变得像监控摄像头,缺乏电影感。我的推荐是「风格」可省,「镜头」必填。Q2:kling-motion-control适合跑结构化 Prompt 吗?不太适合。kling-motion-control的核心价值是用参考视频驱动动作迁移,Prompt 在这里只是补充参考视频未覆盖的部分。如果你能用参考视频,就用;没有参考视频,直接上kling-3.0-turbo。Q3:同一个 Prompt 跑三家,结果差异有多大?风格差异最大,主体和动作差异较小。wan2.6-i2v-flash因为是 flash 版本,细节会比标准版糊一点,但成本更低适合做 A/B test。doubao-seedance-1-0-pro-250528的调色最稳定,不容易出现「半夜画面突然变白天」这种穿帮。Q4:矩阵号流水线要不要为每家写不同的 Prompt?不要。我的做法是写一套结构化 Prompt,在 Adapter 层做翻译。如果一定要为某一家定制,优先级是kling-motion-controldoubao-seedance-1-0-pro-250528kling-3.0-turbo≈wan2.6-i2v。Q5:Prompt 越长越好吗?不是。我测过结构化 Prompt 超过 200 字之后,三家 API 的「指令遵循度」都会下降,主体开始漂。控制在 150 字以内最优,kling-3.0-turbo的容许上限大概在 180 字,wan2.6-i2v-flash最严格,140 字就开始掉。八、参考资料炻光 AI 接入管理平台 · 视频 API 文档Sora 2 system guide(subject/action/setting/camera/style 模板)可灵官方文档 2026-07-01 更新日志豆包 Seedance 官方产品页九、写在最后结构化 Prompt 是降低隐空间熵的工具,不是越多越好。五个槽位是经验值,不是教条。我建议从三个槽位(主体/动作/环境)起步,镜头和风格按需加,超过 200 字就开始减。Prompt 可移植性的瓶颈不在翻译,在语义对齐。同样的「低机位跟拍」,可灵、万相、豆包的理解差异不小。Adapter 层不要做硬翻译,要做语义对齐——把内部统一 Schema 作为「意图声明」,每个 vendor 的 Adapter 各自表达。生产里最该投资的是降级链路,不是 Prompt 本身。视频 API 排队严重,降级链路能让可用率从 80% 拉到 95% 以上。Prompt 优化能拉 5-10%,降级链路能拉 15-20%,投入产出比差三个数量级。