资讯动态

AI视频剪辑自动化实战:基于Whisper、LLM与ffmpeg的智能粗剪工具全解析

发布时间:2026/10/26 16:33:56 来源:尧图企业网站定制
搞视频剪辑的人一定懂这种痛苦一条口播录了 25 分钟回放一看开头“嗯”“那个”占了 3 分钟中间有两段反复讲同一个观点结尾还拖了 1 分多钟的收尾废话。手动剪吧来回拖进度条一帧一帧找切割点剪完一条片子眼睛都快瞎了不剪吧观众划走的速度比你剪片还快。我年初做了一个开源小工具 Video AI Cutter核心功能一句话就能说清楚把视频里“不该留”的片段自动找出来按语义完整度拼出成片。它不需要你手工标记任何剪切点只需要给一个输入视频工具会自己完成语音转写、句子筛选、静音对齐、视频拼接的全流程。这篇文章既是 Video AI Cutter 的 Readme也是我整个开发过程的踩坑记录。想自己复刻一个、或者直接拿来改造成自己工作流的同学跟着这篇走就够了。先说结论这个项目本质上不是“剪辑工具”而是一个“判断工具”。剪辑的手艺活还是留给人但它能把最耗时的“素材通读、标记、粗切”这三大步全部自动化。它适合口播视频、直播切片、会议录播、课程回放、播客视频化这几类场景核心用户是内容创作者和想折腾自动化工作流的开发者。如果你想给团队搭一套“自动出粗剪”的流水线这个项目也能当底座。1. 这个工具到底在干什么先给一个整体定位。市面上已有的“AI 剪辑”工具多半是套壳本质还是把视频扔进去由云端模型做分析你只能在黑盒里点“生成”。Video AI Cutter 走的是另一条路全部环节本地化每一步都可以看到中间产物每一个判断逻辑都可以调参。整套流程拆开看是这样输入一条视频先抽音频转成 16kHz 单声道 WAV。用 Whisper 系模型做语音识别拿到带时间戳的逐句文本。把逐句文本交给大模型让它标记哪些句子是冗余内容。用静音检测找到真正的“可切割点”把 LLM 的标记对齐到这些切割点附近。算出保留时间区间先生成一个带可视化预览的 JSON 清单。确认后交给 ffmpeg 拼接输出成片。这个设计的核心思路是“把大问题拆成小问题每一个小问题都能单独验证”。语音识别错了可以单独调 Whisper 的模型和提示词冗余判断太激进可以单独改 LLM 的温度和阈值拼接有问题可以单独查 ffmpeg 的参数。不会出现黑盒里跑了一小时、最后不知道错在哪的情况。为什么不用现成的“智能剪辑 API”最直接的原因是隐私和成本。口播视频和会议录播往往涉及未公开的内容把整段素材传到第三方服务本身就过不了我这道心理关。而且一次调用 API 的价格本地 CPU 跑半小时的电费就能覆盖。本地方案的另一个好处是完全可复现——今天调出来的参数三个月后依然能跑出一模一样的结果。这个工具的定位也从一开始就定死了不做特效、不转场、不调色只做一件事——“把视频修剪成更紧凑的版本”。输出的是粗剪不是精剪。想靠它一条龙出成品是不现实的但用它把 25 分钟素材变成 18 分钟干净初剪效率提升是肉眼可见的。2. 拆解三条核心链路转录、判断、切片2.1 为什么要用 Whisper 而不是传统字幕工具“AI 裁剪”的前提是必须知道每一句话在什么时间点出现。传统字幕工具依赖音字对齐算法对中文的断句能力一般而且很多工具只输出字幕文件不给你足够稳定的逐句时间戳。Whisper 系的模型天然输出带时间戳的 segments每个 segment 包含 start、end、text 三个核心字段这正好是裁剪逻辑需要的三要素。我在项目里优先推荐的是 faster-whisper而不是官方原版 Whisper。原因很实际官方 Whisper 在 CPU 上跑 small 模型处理 1 分钟音频可能要 2 到 5 分钟而 faster-whisper 用的是 CTranslate2 后端配合 int8 量化速度能快 3 到 4 倍。我用一台 i5-12400F 的 CPU 机器实测处理 25 分钟视频的音频faster-whisper small int8 大约 4 分钟跑完官方版要跑到 12 分钟以上。对“本地跑”这个目标来说速度就是体验。模型选型我给了一张表直接写在 README 里模型参数量中文识别效果CPU 速度分钟音频/分钟处理显存建议tiny39M能听出大概断句乱极快1GB 以下base74M句子基本正确名字爱错快1GBsmall244M中文可用语气词识别不错中2GBmedium769M中文效果明显提升慢4GBlarge-v31550M接近人工转写很慢6GB 起我默认配的是 small。理由是裁剪不需要 100% 正确的文字只需要正确的时间戳和大致准确的句子边界。small 在“句子边界”上的表现已经够用而且速度快。如果你剪的是会议录播这种对文字精度要求高的场景换 medium代价是处理时间增加 2 到 3 倍。还有一个细节喂给 Whisper 的音频必须是 16kHz 单声道。ffmpeg 抽音频时默认输出是原采样率直接喂进去也不是不行但 Whisper 内部会重采样长视频可能出现时间戳轻微偏移。更稳的做法是显式转一下ffmpeg -i input.mp4 -vn -ac 1 -ar 16000 -f wav audio_16k.wav这个操作几乎瞬时完成但能省掉后面一大堆时间戳对齐的麻烦。2.2 LLM 负责“判断”但别让它替你做决定转写完成之后手上是一堆带起止时间的话。现在要回答的核心问题是哪些话该留哪些话该剪。这个判断我用的是 LLM。判断依据不是“这句话语法对不对”而是“这句话对观众有没有信息增量”。我把每条句子拼成这样的 JSON 喂给模型[ {index: 0, start: 1.2, end: 8.5, text: 今天我们聊一聊如何搭建一个自动化剪辑流水线}, {index: 1, start: 9.0, end: 11.2, text: 嗯就是那个其实内容不是特别复杂}, {index: 2, start: 11.8, end: 23.4, text: 首先你需要准备一台能跑得动语音识别的电脑} ]提示词大致是这样你是视频编辑助手。下面是一段视频的逐句文本请判断每个句子是否冗余。 冗余标准包括口头禅、与主题无关的离题内容、前后重复的表达、纯粹的语气词填充。 请只输出 JSON 数组每个元素包含 index、keeptrue/false、reason 三个字段。 注意宁可漏判不要误删。拿不准的句子一律 keep。注意最后两句“宁可漏判不要误删。拿不准的一律 keep”。这句话决定了整个工具的使用体验。LLM 一旦误删关键句成片语义就断了用户对工具的信任感会瞬间崩塌而漏判几句废话成片只是不够紧凑用户还能接受。我把这个原则直接写进了默认提示词同时在 judge 参数里暴露了一个threshold字段默认 0.5数值越大裁得越激进。本地跑 LLM我用的是 Ollama 加载 qwen 系 7B 模型用 CPU 也能跑单条 25 分钟视频约 200 句文本分 3 批喂完耗时 2 分钟左右。如果你的机器有显卡这个环节几乎是秒级。如果你不想本地折腾 LLM也可以把 judge 模块替换成 OpenAI 兼容接口代码里留了LLM_API_BASE这个配置项指向任意兼容服务都行。2.3 切片为什么选 ffmpeg concat 而不是直接剪拿到“哪些句子保留”之后面临的最后一个技术问题是怎么把这些保留片段拼起来。最直觉的答案是根据句子时间戳把不保留的区间剪掉保留的区间直接拼接。但这里有个隐藏陷阱句子的 start、end 是由语音识别的精度虽然不错但不会精确落在画面帧上。如果你直接按句子的 end 去硬切裁出来的画面很可能会切断一个完整动作观感上会有“跳了一下”的生硬感。我的解法是引入“静音对齐”。在正式切割前用 ffmpeg 的 silencedetect 找出所有静音段ffmpeg -i audio_16k.wav -af silencedetectnoise-30dB:d1.5 -f null --30dB是静音判定阈值d1.5是最小静音持续秒数。输出日志里会出现silence_start: 8.6 silence_end: 10.2然后把 LLM 标记的“冗余句子的边界”吸附到最近的静音段上。这样切点永远落在“没声音”的地方成片的节奏是完整的不会出现一句话说到一半突然被切断的窒息感。至于最终拼接我用的是 ffmpeg 的 concat demuxerffmpeg -f concat -safe 0 -i seglist.txt -c copy output.mp4-c copy的意思是流复制不重新编码速度极快画质零损失。但用 concat 有一个铁律所有输入片段的编码参数必须一致。如果原始视频是可变帧率或者不同片段来自不同来源-c copy拼接出来会花屏或者音画不同步。所以我在 pipeline 里加了一个环境变量FORCE_REENCODE默认关闭如果拼接出问题打开后会把所有片段统一重编码为 H.264 AAC 再拼接ffmpeg -i seg_%d.mp4 -c:v libx264 -preset veryfast -crf 20 -c:a aac -b:a 128k ...3. 目录结构和 Readme 里的核心配置3.1 项目目录怎么组织最顺手这个项目我采用了非常典型的“入口 核心模块”结构不搞花活好处是新人拿到仓库 5 分钟就能定位到想改的代码video-ai-cutter/ ├── app.py # 命令行入口也支持 Streamlit 模式 ├── cutter/ │ ├── __init__.py │ ├── transcribe.py # 音频抽取 Whisper 转写 │ ├── judge.py # LLM 冗余判断 │ ├── segment.py # 静音对齐 区间计算 ffmpeg 拼接 │ └── utils.py # 文件处理、日志、时间戳转换 ├── config.yaml # 全部可调参数 ├── requirements.txt └── README.md你可能注意到我把所有逻辑按照流水线阶段切分而不是按照“模型”“算法”切分。这是刻意的。因为实际调试时你通常只会遇到一个阶段的问题要么转录结果差要么判断不精准要么拼接出错。按阶段切分定位问题的半径最小。比如你要调 LLM 的提示词只需要打开 judge.py别的一行都不用碰。3.2 config.yaml 里最关键的四个参数配置文件我尽量精简到 8 个字段但真正决定了裁剪效果的只有下面四个这里展开讲讲。model_size: small # Whisper 模型档位 min_silence_ms: 1500 # 静音最短持续时间毫秒 keep_threshold: 0.5 # LLM 判断保留的置信阈值 max_segment_duration: 300 # 单个片段最大时长秒model_size前面讲过了不展开。min_silence_ms是静音检测的最小持续毫秒数。设太短比如 300ms正常人说话的换气停顿都会被识别成剪切点结果就是画面频繁跳动设太长比如 3000ms很多冗余语段后面没有这么长的空白切点吸附不上去裁剪力度不够。我在不同素材上试下来1500ms 是一个比较通用且安全的默认值。演讲类素材可以提到 2000msVlog 这种语速快的素材用 1200ms 会更跟手。keep_threshold是 LLM 判断的后处理阈值。LLM 返回每个句子的原始置信分如果 keep 的概率低于这个值才判定为冗余。默认 0.5 是严格模式只有模型很确定是废话才剪调到 0.7 以上裁剪会更激进适合本身废话特别多的直播切片。max_segment_duration是针对“直播切片”场景加的防呆参数。有时候整段视频说话太密集几乎没有静音每段保留片段会连成七八分钟的超长块。设置这个参数后segment.py 会自动在超长块内部找相对安静的点强切。这属于“宁可切碎也不让成片拖沓”的兜底策略但注意切割点仍会吸附到静音位置不会硬生生切断人声。4. 实操从命令行把一条 25 分钟视频剪成 18 分钟下面这条完整链路我不只写在 README 里也实际跑过很多遍。就用一条 25 分钟的 1080p 口播视频做演示机器配置是 i5-12400F 16GB 内存 核显纯 CPU 跑。4.1 第一步转录和句子时间戳环境准备部分只说三件事。第一Python 版本建议 3.10 以上装 faster-whisper、streamlit、pyyaml、openai 库用于兼容 LLM API。第二ffmpeg 必须存在于系统 PATH 中。第三如果要用本地 LLM确认 Ollama 在跑。准备好之后命令行执行python app.py --input demo.mp4 --output demo_cut.mp4 --model smallapp.py 的第一段逻辑会调用transcribe.py流程就是先抽音频再调 faster-whisper 识别。实测在 CPU 上25 分钟音频耗时约 4 分钟。识别完成后工作目录下会生成一个transcript.json里面每一段长这样{ start: 11.8, end: 23.4, text: 首先你需要准备一台能跑得动语音识别的电脑 }我建议你在这一步先停下来打开 transcript.json 看一遍。为什么因为这一步直接决定后续裁剪质量。如果识别出来的句子断句全乱先别急着往下跑回去换更大的模型或者检查音频是不是有严重回声。反正转录只花 4 分钟多跑几次也不心疼。4.2 第二步让 LLM 标记冗余句子transcript.json 生成后judge.py会按每 50 条句子一组批量发给 LLM。这里有一个小优化发送之前先把句子按时间戳排序并给每条句子一个全局唯一的 indexLLM 返回后按 index 归位。这样即使某一组句子返回顺序不对也不会污染全局结果。LLM 判断结果会合并进同一份 JSON变成{ start: 11.8, end: 23.4, text: 首先你需要准备一台能跑得动语音识别的电脑, keep: true, reason: 核心信息句说明前置条件 }跑完这步后会打印一行统计[Info] 共识别 143 句建议保留 112 句建议裁剪 31 句看到这个统计我通常会先不急着切片而是打开 JSON 扫一眼“建议裁剪”的句子。LLM 的 reason 会告诉你它为什么裁比如“口头禅填充”“重复前句观点”“离题闲聊”。如果你觉得某个 reason 明显不靠谱就去调提示词或者调低 keep_threshold。这个环节非常建议反复迭代几次因为你的视频内容风格直接决定了什么样的判断标准最合适。4.3 第三步生成保留区间并预览拿到了每句话的 keep 布尔值之后segment.py开始干活。它先把连续的 keeptrue 句子合并成若干保留区间然后调用 ffmpeg silencedetect 拿到所有静音段。接着做的是对齐每个保留区间的边缘向最近的大于 1.5 秒的静音段吸附。对齐完成后会生成一份preview.json里面是一个个数组[ {start: 0.0, end: 25.6, keep: true}, {start: 25.6, end: 40.2, keep: false}, {start: 40.2, end: 88.3, keep: true} ]这个 preview.json 是整个项目里我最看重的部分。因为它是“可审查的中间产物”你可以在不跑任何视频剪辑软件的情况下快速核对裁剪方案是否合理。如果你不想走命令行可以加--ui参数启动 Streamlit 界面界面上会列出每个区间的起止时间、保留/裁剪状态、对应的文字内容。鼠标点一下就能临时改 keep 状态改完重新生成 preview.json然后一键导出。这种“先审查方案再执行渲染”的模式实际体验下来比直接出一版成片再返工舒服太多了。毕竟成片渲染一次少说 3 分钟审查 JSON 只要 30 秒。4.4 第四步ffmpeg 输出成片最后一步segment.py 根据 preview.json 里所有 keeptrue 的区间先去切割出碎片文件ffmpeg -i input.mp4 -ss 0.0 -to 25.6 -c:v libx264 -preset veryfast -crf 20 -c:a aac -b:a 128k seg_001.mp4这里为什么不用-c copy因为切割点经过静音吸附后往往不落在关键帧上直接流复制会导致片段开头花屏或卡顿。所以我默认走一次轻量重编码preset veryfastcrf 20能在画质和速度之间取得平衡。1080p 视频实测重编码速度约 3 倍实时25 分钟素材编码 18 分钟成片耗时大约 3 分半。所有碎片生成后写入 seglist.txtfile seg_001.mp4 file seg_002.mp4 file seg_003.mp4再执行拼接ffmpeg -f concat -safe 0 -i seglist.txt -c copy demo_cut.mp4提示concat 拼接时所有碎片已经是统一编码格式所以这一步用-c copy是安全的速度很快20 秒内完成。输出完还会顺手生成一个自动字幕文件demo_cut.srt如果发布平台需要字幕这一步等于白赚的。整个流程实测下来从裸视频到 18 分钟成片总耗时约 10 分钟其中真正人工介入的只有“审查 preview.json”这一步大约 1 到 2 分钟。相比手动剪辑至少 1 小时起步效率提升是数量级的。5. 避坑指南我在开发中踩过的几个坑5.1 Whisper 长音频漏句和漂移项目开发初期我用官方 Whisper 直接转写 40 分钟的长视频结果中段有连续 2 分钟没有任何输出第二次换一小段音频测试又能识别出来。排查发现是长音频的 VAD语音活动检测把一段低音量人声当成了静音导致整段漏掉。解决办法是在转写前关闭官方 Whisper 自带的 VAD 过滤改用独立的silero-vad先做一次音频切分把超过 30 分钟的长音频切成片段每段之间保留 0.5 秒重叠再交给 Whisper 转写。转写完成后按时间戳拼接回完整序列。加了这层逻辑之后长视频漏句的问题基本消失。时间戳漂移则是另一个坑。现象是转写出来的文字和画面声音不同步越到后面偏差越大。根因是输入音频的采样率不是标准的 16kHz。现在我在 transcribe.py 里强制先把音频转成 16kHz 单声道 WAV漂移问题再也没有复现过。5.2 ffmpeg 关键帧和 -c copy 的坑这是新手最容易踩的坑。我第一次尝试输出成片时为了追求速度直接用-c copy切割所有保留区间结果前三个片段正常第四个片段开头花屏第五个片段直接黑屏几秒。原因前面也提到了切割点不在关键帧上。ffmpeg 做流复制时遇到第一个关键帧之前的非关键帧数据只能丢弃导致画面从花屏或黑屏开始。解决方案有两个切割时强制最近关键帧对齐-ss放在-i前面ffmpeg 会先 seek 到前一个关键帧再丢弃多余帧直到精确位置。这样可以用-c copy做切割。放弃流复制统一重编码。我在项目里默认选了方案 2因为方案 1 在部分素材上仍会出现首帧微卡。如果你想追求无损和速度可以切到方案 1但发布前一定把成片从头到尾扫一遍。另外一个相关经验如果原视频是从网上下载的帧率经常是 VFR可变帧率这种素材无论如何都要重编码一次否则后续任何拼接操作都容易出问题。5.3 LLM 过度裁剪的问题第一次跑通全链路后我拿一条自己录的视频测试发现成片确实短了很多但中间有一段逻辑完全接不上。打开 preview.json 一看LLM 把“因为所以”里的“因为”句给裁了只留下了“所以”句。语义断层就是这么来的。这不是模型能力问题而是提示词缺少对“逻辑关联词”的保护。后来我在提示词里加了这么一条规则如果句子中包含因果、转折、递进关系的关联词如“因为”“所以”“但是”“而且”默认保留。加了这条之后误删逻辑关键句的情况大幅减少。另外一个有效手段是给 LLM 看上下文——不要把每条句子单独发出去判断而是每批带上前后各 1 条的上下文模型更容易判断“这句话是不是在承接前文”。如果你的素材本身就比较跳跃还有一个兜底参数context_penalty默认 0.2表示相邻两句中只有一句被标记为裁剪时会自动放行只有当连续两句以上都是冗余标记时才真的剪。这个参数简单粗暴但非常有效强烈建议开启。5.4 大视频上传与运行性能优化Streamlit 版本上线后有朋友传了一个 2GB 的 4K 素材结果上传到一半页面报错。查了半天才发现 Streamlit 默认单文件上传上限是 200MB需要改.streamlit/config.toml[server] maxUploadSize 2048注意单位是 MB写成 2048 就是 2GB。但就算能上传处理 4K 素材对本地 CPU 也是灾难。我的建议是处理前先用 ffmpeg 把输入统一压成 1080p因为裁剪判断只需要音频和画面内容4K 分辨率对判断结果没有任何帮助反而让重编码时间翻好几倍。合并在工具里做成了默认选项--pre-transcode处理 4K 素材时会先转成 1080p 再走流水线。性能优化方面有一个经验值得分享不要对整段音频做完整的 Whisper 转写后再判断而是先用 VAD 把有效语音段抽出来静音部分跳过处理。口播视频一般有 15% 的时间是空白跳过这些空白能让转写时间缩短接近 15%。此外faster-whisper 的batch_size默认 8如果你的显存吃紧把它调到 4CPU 用户则建议直接开compute_typeint8识别的精度几乎不掉速度能快接近一倍。6. 一点后续扩展想法工具第一版跑通之后我又在这个框架上加了一个非常实用的子功能按“句子完整度”自动生成字幕烧录版。流程是转录、判断、切片之后把保留片段的字幕用 ass 格式烧进画面省掉剪辑软件里二次加字幕的工序。这个功能对发短视频的人来说特别实用成片直接就能发布。另外裁剪的判定维度目前只用了文本语义和静音其实还可以加一个画面维度。比如固定机位的直播画面长时间静止但人声在说话这种片段可以通过画面相似度检测在保留语义的同时把“黑屏画面”单独剪掉或替换成插屏图。维度多了之后整个系统的可玩性会再上一个台阶但目前第一版的“语义 静音”两维组合已经能覆盖绝大多数口播内容的裁剪需求了。按我这一百多次运行的经验这个工具最适合的工作流是录完视频先让机器出粗剪版人只负责在 preview.json 阶段做审查改动量通常不会超过 5%。真正的精剪还是需要人工的但精剪时有了一版干净的材料效率比从原始素材开始剪高太多了。如果你也是被粗剪折磨的内容创作者花一晚上搭起来第二天就能感受到“让机器先剪一遍”的快乐。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑