把 AI 生成视频转场特效封装成一个 Skill,是短视频创作者和 AI 工程实践者都应该掌握的用法。所谓 Skill,简单说就是给 AI 助手准备的一套能力包:用户描述“我要让两段视频之间做一个 1 秒的交叉溶解”时,AI 不再靠泛泛的对话猜测转场参数,而是读取目录里写好的 SKILL.md,按固定步骤调用脚本,最终生成可验证的 FFmpeg 命令或直接产出视频。下面从 Skill 概念讲起,逐步搭建一个名为video-transition-skill的最小能力包,并给出运行验证、常见问题排查和扩展建议。
我会按“理解 Skill 机制 -> 准备环境 -> 编写 Skill -> 运行验证 -> 排错 -> 最佳实践”的顺序展开。如果你已经写过 Agent 插件,可以重点看第 3 章和第 4 章的脚本实现;如果你刚接触 Skill,建议从第 1 章开始读,避免后面配置失败时不知道问题出在哪一层。
1. 先搞清楚 Skill 到底是什么,再决定要不要自己写
1.1 Skill 解决的是“让 AI 按固定套路干活”的问题
大模型本身能聊天,但没法可靠地执行“读取视频时长、计算转场偏移、生成 FFmpeg 命令”这套固定流程。普通提示词可以让模型“大概知道”要做什么,却无法保证每次都能按同一套参数规范操作。Skill 的作用,是把这套流程变成 AI 可读取、可调用、可校验的能力包。
一个 Skill 通常是一个目录,里面至少包含一份说明文件和一些可执行资源。说明文件告诉 AI:这个技能在什么场景下使用,有哪些输入参数,应该按什么顺序执行,最后输出什么结果。AI 收到用户请求后,先判断当前任务是否匹配某个 Skill,如果匹配,就按照说明调用脚本、读取示例或运行命令。
在视频转场场景里,Skill 的核心价值是稳定。跨场转场涉及xfade、zoompan、fade等滤镜,参数稍有偏差就会得到黑屏、闪帧或偏移错误。把参数说明和生成逻辑写进 Skill,AI 就不需要回忆“上个视频是怎么做的”,而是直接查找能力包里的模板。
1.2 Skill、Agent、插件和普通脚本的边界
这几个概念经常混在一起。先看它们的分工:
| 概念 | 核心作用 | 在视频转场场景中的例子 |
|---|---|---|
| Skill | 给 AI 提供一套可复用的操作流程和工具说明 | video-transition-skill,包含 SKILL.md 和生成 FFmpeg 命令的脚本 |
| Agent | 负责拆解任务、调用多个工具、根据结果决定下一步 | 用户说“生成转场并发送到工作群”,Agent 先调用 Skill 生成视频,再调用上传脚本 |
| 插件 | 通常指扩展 IDE 或 CLI 功能的程序模块 | 编辑器中集成视频预览面板,不属于 AI 能力包 |
| 普通脚本 | 能独立完成一个具体操作,但 AI 不知道它存在 | 单独运行的make_transition.py,只能由人手动执行 |
Skill 和 Agent 的关系,可以理解为“职业手册”和“管理层”的关系。Agent 负责决策和编排,Skill 负责提供标准作业程序。如果只有脚本,AI 不知道该怎么用;如果只有提示词,执行结果不够稳定。Skill 正好把两者结合起来。
1.3 视频转场特效为什么适合封装成 Skill
视频转场是典型的高重复、高参数化任务。每一次转场都需要指定输入文件、转场类型、持续时间、开始时间和输出路径。参数组合很多,但规律固定。用户往往不会说“用 xfade 滤镜,transition=fade,duration=1.0,offset=3.2”,而是说“在第二个片段开始前做一个柔和过渡”。
封装成 Skill 后,AI 能完成一次“自然语言转结构化参数”的转换。它先把用户描述映射成 JSON 配置,再调用脚本生成命令,最后执行并反馈结果。这样用户不需要记住 FFmpeg 滤镜语法,AI 也不需要依赖记忆生成命令,整个链路更接近工程化。
2. 环境准备:一个能跑通的最小组合
2.1 需要准备哪些工具
要复现下面的示例,建议准备一个最小环境:
| 工具 | 用途 | 最低建议 |
|---|---|---|
| Python 3 | 运行脚本,解析 JSON 配置 | 3.8 及以上 |
| FFmpeg | 执行视频滤镜和编码 | 支持xfade滤镜的版本 |
| ffprobe | 读取视频时长等元数据 | 随 FFmpeg 安装 |
| 支持 Skill 机制的 AI 编程助手 | 让模型能读取 SKILL.md 并调用脚本 | 任选你已使用的工具 |
这里不绑定某一个具体平台。常见的编程助手对 Skill 的目录约定可能略有差异,有的放在项目.agents/skills下,有的放在用户级~/.claude/skills或~/.codex/skills下。落地前先查一下当前工具的文档,确认它读取的是哪个目录。
2.2 确认 Skill 目录约定
如果你的 AI 助手已经支持 Skill 机制,通常会有一个约定的查找路径。比如:
项目根目录/ .agents/ skills/ video-transition-skill/ SKILL.md scripts/ make_transition.py有些平台使用.claude/skills、.codex/skills或~/.codex/skills。还有的会把 Skill 放在用户级目录,方便所有项目共用。为了不对版本下结论,建议你按当前工具的文档确认关键词:SKILL.md、skills 目录、是否支持项目级配置。
确认目录时可以做一次最简测试:在候选目录下新建一个hello-skill/SKILL.md,写入“当用户说 hello 时,回复 skill ok”,然后让 AI 触发。如果助手能引用这个文件,说明目录路径正确。
2.3 准备测试视频片段
示例脚本需要两段输入视频。为了快速验证,可以用 FFmpeg 生成两个带颜色的测试片段:
ffmpeg -f lavfi -i color=c=red:size=640x360:duration=5 -c:v libx264 -pix_fmt yuv420p clip1.mp4 ffmpeg -f lavfi -i color=c=blue:size=640x360:duration=5 -c:v libx264 -pix_fmt yuv420p clip2.mp4执行完后检查:
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 clip1.mp4如果能看到类似5.000000的输出,说明测试片段可用。注意生成测试片段时建议指定-pix_fmt yuv420p,否则后续视频拼接可能因为像素格式不一致报错。
3. 创建 video-transition-skill:目录结构与核心文件
3.1 目录结构先定下来
一个最小的 Skill 可以只有SKILL.md,但做视频转场建议把“说明”和“可执行脚本”分开:
video-transition-skill/ SKILL.md scripts/ make_transition.py examples/ crossfade.json fadeblack.json每个文件的作用:
SKILL.md:给 AI 看的说明书,描述技能用途、参数、执行步骤和注意事项。scripts/make_transition.py:读取 JSON 配置,自动计算转场偏移,输出 FFmpeg 命令。examples/:存放不同转场类型的示例配置,方便 AI 快速复制。
目录结构不要写成多级嵌套。Skill 本身应该是独立、单一职责的能力包,目录越简单越容易被读取。
3.2 编写 SKILL.md,告诉 AI 什么时候用、怎么用
下面是一份可用的 SKILL.md 示例,你需要根据自己平台的 frontmatter 要求做调整:
# video-transition-skill 为两段视频生成转场特效。支持 crossfade、fadeblack、wipeleft、 slideleft、circleopen 等基于 xfade 滤镜的转场。 ## 适用场景 用户提供两段视频路径,并希望合成一个带转场效果的新视频时, 使用本技能。 ## 使用步骤 1. 确认两个输入视频文件存在,且可以被 ffprobe 读取。 2. 将用户需求整理成 JSON 配置,写入临时文件或直接作为命令行参数。 3. 先执行 dry-run 生成命令并展示给用户确认。 4. 用户确认后,使用 --run 执行生成。 ## 命令示例 python scripts/make_transition.py --config examples/crossfade.json --dry-run python scripts/make_transition.py --config examples/crossfade.json --run ## 配置字段 - input1: 第一段视频路径。 - input2: 第二段视频路径。 - transition: 转场类型,默认 crossfade。 - duration: 转场时长,单位秒,默认 1.0。 - offset: 可选,转场开始时间。不填时脚本会尝试自动计算。 - output: 输出视频路径,默认 output.mp4。 ## 注意事项 - duration 必须小于第一段视频的时长。 - 不要覆盖输入文件。 - 执行前先 dry-run,避免 ffmpeg 参数错误导致输出文件损坏。关键点在于“适用场景”要具体。AI 判断是否调用 Skill 时,依赖这份描述来判断匹配度。如果写得太宽泛,AI 可能在不合适的时候调用;写得太窄,又会漏掉真实需求。最好在真实助手环境中测试几轮,再补充边界情况。
3.3 编写 make_transition.py,把转场参数变成 FFmpeg 命令
脚本不需要处理像素级算法,FFmpeg 已经帮我们做好了。脚本的职责是把 JSON 配置转换成合理的 FFmpeg 命令,并在执行前校验参数。
先创建一个scripts/make_transition.py:
#!/usr/bin/env python3 import argparse import json import subprocess import sys from pathlib import Path TRANSITIONS = { "crossfade": "fade", "fadeblack": "fadeblack", "wipeleft": "wipeleft", "slideleft": "slideleft", "circleopen": "circleopen", } def get_duration(path: str) -> float: cmd = [ "ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", str(path), ] result = subprocess.run(cmd, capture_output=True, text=True) if result.returncode != 0: raise RuntimeError(f"无法读取视频时长: {path} -> {result.stderr}") return float(result.stdout.strip()) def build_command(config: dict): input1 = config.get("input1") input2 = config.get("input2") if not input1 or not input2: raise ValueError("配置中必须包含 input1 和 input2") transition = config.get("transition", "crossfade") if transition not in TRANSITIONS: raise ValueError(f"不支持的转场类型: {transition}") duration = float(config.get("duration", 1.0)) output = config.get("output", "output.mp4") duration1 = None try: duration1 = get_duration(input1) except RuntimeError: print("警告:无法读取第一段视频时长,将依赖配置中的 offset。", file=sys.stderr) if duration1 and duration >= duration1: raise ValueError("转场时长必须小于第一段视频时长") offset = config.get("offset") if offset is None: if duration1: offset = max(duration1 - duration, 0) else: raise ValueError("无法自动计算 offset,请在配置中提供 offset") else: offset = float(offset) filter_complex = ( f"[0:v][1:v]xfade=transition={TRANSITIONS[transition]}" f":duration={duration}:offset={offset}[v]" ) return [ "ffmpeg", "-i", input1, "-i", input2, "-filter_complex", filter_complex, "-map", "[v]", "-c:v", "libx264", "-pix_fmt", "yuv420p", "-y", output, ] def main(): parser = argparse.ArgumentParser(description="生成视频转场 FFmpeg 命令") parser.add_argument("--config", required=True, help="JSON 配置文件路径") parser.add_argument("--dry-run", action="store_true", help="只打印命令,不执行") args = parser.parse_args() config = json.loads(Path(args.config).read_text(encoding="utf-8")) cmd = build_command(config) print("生成的命令:") print(" ".join(cmd)) if args.dry_run: return print("开始执行……") subprocess.run(cmd, check=True) print("转场视频已生成:", config.get("output", "output.mp4")) if __name__ == "__main__": main()这段脚本有几个设计点。
get_duration用 ffprobe 获取第一段视频时长,目的是自动计算offset。在xfade滤镜中,offset表示转场开始的时间点,通常等于第一段视频时长减去转场时长。例如第一段视频 5 秒,转场 1 秒,offset 应为 4 秒,这样第二段视频从第 4 秒开始混合进入。
build_command返回的是字符串列表,而不是直接拼成 shell 字符串。这样执行时不需要经过 shell,可以减少特殊字符带来的问题。FFmpeg 命令中可能包含中文路径、空格、括号,使用参数列表更安全。
--dry-run是安全边界。脚本默认行为只打印命令,用户确认后再通过--run实际执行。如果 AI 直接执行未经确认的命令,一旦输出路径写错或参数异常,可能会覆盖已有文件。
4. 用 JSON 配置驱动转场生成
4.1 配置字段说明
为了让 AI 能稳定生成配置,建议在SKILL.md和示例文件里把字段写仔细。
以一个交叉溶解示例为例,创建examples/crossfade.json:
{ "input1": "clip1.mp4", "input2": "clip2.mp4", "transition": "crossfade", "duration": 1.0, "output": "output_crossfade.mp4" }字段含义如下表:
| 字段 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|
| input1 | 是 | 无 | 第一段视频路径 |
| input2 | 是 | 无 | 第二段视频路径 |
| transition | 否 | crossfade | 转场类型 |
| duration | 否 | 1.0 | 转场时长,单位秒 |
| offset | 否 | 自动计算 | 转场开始时间,单位秒 |
| output | 否 | output.mp4 | 输出视频路径 |
4.2 自动计算 offset 的原理
xfade滤镜要求两个输入视频在时间轴上重叠。它的时间轴逻辑是:第二段视频从offset秒处开始与第一段视频混合,混合持续duration秒。如果第一段视频总长为 5 秒,duration 为 1 秒,offset 应该是 4 秒。
如果 offset 设置过小,转场会在第一段视频还很亮时就开始出现第二段画面;如果 offset 过大,转场结束后第一段可能已经结束,画面会黑场。更严重的是,offset 加 duration 超过第一段视频总时长时,FFmpeg 会报错或输出异常。
因此,代码优先用 ffprobe 读取真实时长,再自动计算 offset。只有在读取失败时才要求用户在配置中手动填写 offset。实际项目中,如果输入视频来自剪辑软件,时长信息通常可靠;如果来自网络下载或录屏,最好保留手动 offset 覆盖能力。
4.3 从用户一句话到 Skill 执行的完整链路
当 AI 支持 Skill 机制后,完整链路可以这样理解:
- 用户说:“把 clip1.mp4 和 clip2.mp4 拼起来,中间用一个 1 秒的淡入淡出转场。”
- AI 识别到“两段视频”“转场”等关键词,判定匹配
video-transition-skill。 - AI 读取 SKILL.md,看到使用步骤和参数说明。
- AI 把用户描述整理成 JSON 配置,甚至可以自动创建临时配置,也可以参考
examples/crossfade.json。 - AI 先执行 dry-run,得到 FFmpeg 命令并展示。
- 用户确认后,AI 去掉
--dry-run执行脚本。
这个链路的关键是“结构化参数”。如果 AI 没有把用户描述转换成 JSON,而是直接生成 FFmpeg 命令,就不能复用脚本的校验和 offset 计算逻辑。Skill 的价值不是替代 FFmpeg,而是让 AI 的每一步都可复现、可校验。
5. 运行与验证:不能只看命令输出了
5.1 先跑 dry-run
在 AI 助手环境中,建议先运行:
cd video-transition-skill python scripts/make_transition.py --config examples/crossfade.json --dry-run预期输出类似:
生成的命令: ffmpeg -i clip1.mp4 -i clip2.mp4 -filter_complex [0:v][1:v]xfade=transition=fade:duration=1.0:offset=4.0[v] -map [v] -c:v libx264 -pix_fmt yuv420p -y output_crossfade.mp4这里offset=4.0是脚本自动计算出来的。如果 clip1 的时长不是 5 秒,这里会显示实际计算值。看到这段输出后,不要急着执行,先确认三件事:
- 路径是否正确。
- 转场类型是否匹配用户描述。
- offset 是否大于 0 且小于第一段视频时长。
5.2 实际执行生成视频
dry-run 确认无误后执行:
python scripts/make_transition.py --config examples/crossfade.json --run执行过程中会看到 FFmpeg 的日志。如果正常结束,命令行最后会显示:
转场视频已生成: output_crossfade.mp4此时先检查文件是否存在:
ls -lh output_crossfade.mp4文件大小不能是 0。如果文件非常小,很可能是 FFmpeg 阶段失败或者输出为空。
5.3 验证输出视频
验证不能只看文件存在。建议用 ffprobe 检查输出文件:
ffprobe -v error -show_entries format=duration,size:stream=codec_name,width,height -of default=noprint_wrappers=1 output_crossfade.mp4正常情况下能看到:
duration=9.000000 size=... codec_name=h264 width=640 height=360两个 5 秒视频通过 1 秒交叉溶解合成,总时长约为 9 秒。如果是 10 秒,可能没有真正实现转场,而是把两个视频直接拼接了。常见问题里会提到这个判断方法。
如果条件允许,再用播放器打开输出文件,肉眼确认画面过渡是否平滑。颜色测试片段比较适合验证:红蓝两个片段交叉溶解时,中间会出现红蓝色混合的紫色过渡,说明转场生效。
6. 常见问题排查:从现象倒推根因
6.1 SKILL.md 没有被 AI 识别
现象是:用户触发了转场需求,但 AI 不读取 SKILL.md,也没有调用脚本。
排查顺序:
- 确认 Skill 放在 AI 助手要求的目录下。不同的工具可能读取
.agents/skills、.claude/skills或.codex/skills。 - 确认文件名严格为
SKILL.md,大小写不能错。 - 确认 SKILL.md 里的描述足够清晰。如果“适用场景”太模糊,AI 可能不会匹配。
- 确认工具是否开启了 Skill 权限。有些 CLI 工具有自动批准或手动确认的权限模型。
可以先做一个最小 hello-skill 测试。如果最小用例能跑通,问题往往出在描述文本或路径上。
6.2 FFmpeg 报 No such filter
执行命令后出现:
No such filter: 'xfade'原因是 FFmpeg 版本太旧。xfade滤镜在 FFmpeg 4.3 之后才提供。你的机器上可能使用系统软件源安装的旧版本。
处理方式:
ffmpeg -version查看版本号。如果版本过低,需要更新 FFmpeg 或下载新版静态构建包。如果无法更新,最简单的方式是换用fade滤镜实现简单的淡入淡出,但两段视频拼接的逻辑会变复杂,建议优先升级 FFmpeg。
6.3 输出视频总时长等于两个片段时长之和
如果 output 总时长是 10 秒,而不是约 9 秒,通常说明xfade没有真正生效,或者命令被 Fallback 成了 concat。
检查点:
- 命令中是否包含
-filter_complex和xfade字样。 - 是否能看到转场过程。颜色片段中是否有混合色。
- 如果 AI 工具没有调用脚本,而是自己拼了命令,可以用 dry-run 输出的命令手动执行对比。
这个问题的根源是 AI 绕过了 Skill 脚本。遇到时不要继续调整 FFmpeg,先回到“有没有走 Skill 脚本”这条路径排查。
6.4 JSON 解析失败或 offset 报错
现象是脚本执行后报:
ValueError: 不支持的转场类型: crossfade或:
ValueError: 无法自动计算 offset,请在配置中提供 offset前者通常说明输入配置里写了不支持的类型,检查TRANSITIONS字典和 JSON 拼写。后者说明 ffprobe 无法读取第一段视频时长,可能输入文件路径错误、文件损坏或 ffprobe 未安装。
先手动运行:
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 clip1.mp4如果没有任何输出且返回值非 0,说明文件读不了,换一下输入视频,或在 config 中手写offset绕过自动计算。
6.5 输出画面花屏或绿屏
可能是像素格式问题。FFmpeg 某些滤镜链输出可能是 yuv420p,也可能是其他格式。脚本里已经加了-pix_fmt yuv420p,但如果手动执行命令时漏掉,播放兼容性会变差。另外,输入视频尺寸不一致时也容易出现异常。建议先把输入视频统一为相同分辨率再合成。
7. 最佳实践与扩展方向
7.1 编写 Skill 时的可复用清单
不要只把上面的例子复制到项目里就结束,建议按这份清单检查:
- 是否有独立的 SKILL.md,且文件名为全大写。
- 描述里是否说明了适用场景和禁用场景。
- 是否有明确的参数表,包含默认值。
- 是否区分 dry-run 和实际执行。
- 是否有示例配置,方便 AI 复制。
- 脚本是否使用参数列表调用子进程,而不是拼 shell 字符串。
- 输入输出路径是否做了校验。
- 是否检查了错误码并给出人可读的提示。
- 是否有针对输出文件的长度或内容验证方法。
这份清单可以复用到图片合成、音频处理、字幕生成等类似 Skill 开发中。Skill 越规范,AI 越不容易误用。
7.2 生产环境使用建议
在本地试验可以直接运行脚本,但进入生产或半自动流程时要注意:
- 加入日志:记录输入配置、生成的命令、执行结果、耗时和错误信息。
- 加入并发控制:FFmpeg 是大资源任务,多个任务同时执行会抢占 CPU。
- 对视频大小和时长做限制,防止输出巨大文件。
- 输出文件不要覆盖原片,建议写入独立输出目录并带时间戳。
- 对 AI 调用设置权限边界,不要让模型随意执行任意命令。脚本内部只暴露白名单参数,不要透传成 shell。
如果要在服务器上提供接口供前端调用,建议把 Skill 脚本封装成 REST API,而不是让前端直接触发命令行。这样既能做参数校验,也能统一记录操作日志。
7.3 扩展:更多转场、批量处理和其他 Agent 平台
当前脚本只支持xfade滤镜的几种转场。实际可扩展方向包括:
- 增加
xfade支持的其他转场名,比如fadewhite、slideup、smoothup、dissolve。 - 增加对单视频内部镜头的
zoompan推进效果,适合 vlog 节奏感。 - 增加批量处理,遍历一个目录下所有片段,两两拼接。
- 增加音频交叉淡化,使用
acrossfade滤镜。 - 把 Skill 迁移到支持相似机制的其他 AI 平台,只需保留脚本,调整 SKILL.md 的约定格式。
对于刚入门的读者,建议先不做太多转场类型,而是把“配置 -> dry-run -> 执行 -> 验证”这条链路跑熟。视频处理最容易出现的问题不是滤镜不会写,而是参数上下文没有对齐:时长、分辨率、帧率、像素格式都可能影响最终结果。把 Skill 当成一个受约束的工程组件来对待,AI 生成视频转场特效这条路就能走得更稳。