1. 为什么我要给 Agent 装上一双“眼睛”

做 Agent 开发的朋友大概都有过这种体验:你精心搭好了一套工作流,让模型去处理一批素材,结果卡在第一步——它看不见视频里到底有什么。文本、图片、PDF 这些早就被各种工具啃得透透的,唯独视频这块,一直是个尴尬的盲区。你丢一个 mp4 过去,模型要么直接拒收,要么只能靠文件名瞎猜。claude-video 这个 Skill 要解决的就是这件事:让 Agent 真正具备“看视频”的能力,把一段视频拆成它能理解的帧序列和音频信息,再喂给模型做推理。

说白了,它不是一个播放器,也不是一个转码工具,而是一座桥——桥的一头是 ffmpeg 这套老牌音视频处理工具链,另一头是 Claude Code 这类 Agent 运行环境。桥搭好了,Agent 就能对视频做抽帧、提取关键画面、读取时长和分辨率、甚至配合语音转文字做内容理解。适合谁来参考?如果你正在用 Claude Code 做自动化,或者自己在写 Agent 框架、想让 Agent 处理多媒体输入,那这套思路你直接抄就行。哪怕你只是刚装完 Claude Code、还在摸索 Skill 机制的新手,跟着走一遍也能把整个链路跑通。

我先把结论摆在这:核心就三件事—— 用 ffmpeg 把视频拆成帧和音频 , 用 Skill 的目录结构和描述文件把能力注册给 Agent , 用一套约定好的调用协议让 Agent 知道什么时候该用它 。听起来简单,但每一步都有坑,下面我一个个拆。

2. 整体设计思路:为什么是 ffmpeg + Skill 这个组合

2.1 视频理解这件事,Agent 到底缺什么

先想清楚一个问题:Agent 处理视频,难点到底在哪?不是模型不够聪明,而是 输入格式对不上 。大模型的原生输入是 token 序列,图片可以切成 patch 变成 token,但视频是连续的帧流加音轨,直接塞进去既不现实也不经济。一段 10 分钟、30fps 的视频有 18000 帧,你不可能全喂进去。

所以正确的思路是 降维 :把视频这个高维连续信号,压缩成 Agent 能消化的离散信息。具体来说分两条线——视觉线抽关键帧,听觉线提音频转文字。抽帧不是随便抽,要按时间间隔或者场景变化来抽,保证抽出来的帧能代表视频的主要内容。音频线则交给语音识别,把说的话变成文本。这两条线合起来,Agent 就相当于“看了”这段视频。

claude-video 这个 Skill 的定位,就是把这套降维流程封装成一个 Agent 可以随时调用的能力。它不负责理解,理解交给模型;它只负责 把视频变成模型能理解的东西 。

2.2 为什么选 ffmpeg 而不是别的

音视频处理这个领域,ffmpeg 是绕不过去的。我试过用 Python 的 opencv 抽帧,简单场景够用,但一遇到各种奇葩编码格式就开始报错;也试过 moviepy,写起来舒服,底层还是调 ffmpeg,多一层封装反而多了出错的地方。ffmpeg 的好处是 格式支持全、命令行稳定、跨平台一致 ,你在 Linux 上跑通的命令,搬到 Windows 和 macOS 上基本不用改。

更重要的是,ffmpeg 的输出可以被精确控制。抽帧可以指定时间点、指定帧率、指定输出尺寸;提取音频可以指定采样率、声道数、编码格式。这些参数对 Agent 来说很关键——你抽出来的帧太大,token 消耗爆炸;太小,模型看不清细节。ffmpeg 让你能在这中间找到平衡点。

至于 Skill 这个形态,它是 Claude Code 生态里比较轻量的一种能力扩展方式。相比写一个完整的 MCP server,Skill 更像是一个“说明书 + 脚本”的组合,Agent 读到描述就知道这个能力是干嘛的、怎么调。对于 claude-video 这种“输入视频、输出帧和文本”的单一职责工具,Skill 的形态刚刚好,不用搞得太重。

2.3 整体架构长什么样

我把整个链路画成文字版,方便你理解数据怎么流动:

用户/Agent 传入视频路径
        ↓
claude-video Skill 被触发
        ↓
调用 ffmpeg 抽帧 → 输出到临时目录(jpg/png 序列)
调用 ffmpeg 提音频 → 输出 wav/mp3
        ↓
(可选)音频转文字 → 得到字幕文本
        ↓
返回给 Agent:帧文件路径列表 + 时长/分辨率元信息 + 文本
        ↓
Agent 读取帧图片 + 文本,交给模型做理解

这里有个设计取舍值得说: Skill 本身不做理解,只做转换 。为什么?因为理解是模型的事,Skill 如果掺和进去,就变成了一个黑盒,Agent 不知道中间发生了什么,出了问题也没法排查。保持 Skill 的“透明”,让它只负责把视频拆开、把零件摆好,Agent 拿到零件后自己决定怎么用,这样灵活性和可调试性都更好。

3. 核心细节解析:抽帧、提音频、元信息三件套

3.1 抽帧策略:抽多少帧才够用

抽帧是整个流程里最需要动脑子的地方。抽多了 token 爆炸,抽少了信息丢失。我的经验是分场景:

  • 对话类视频 (访谈、课程):画面变化小,重点在音频,抽帧频率可以低,比如每 10 秒一帧,甚至只在场景切换时抽。
  • 操作演示类 (教程、开箱):画面变化大,关键动作可能就一两秒,需要按固定间隔抽,比如每 2 秒一帧。
  • 影视/短视频 :节奏快,建议用场景检测抽帧,ffmpeg 的 select 滤镜可以做到。

ffmpeg 抽帧的基础命令是这样的:

ffmpeg -i input.mp4 -vf "fps=1/2" -q:v 2 frames/frame_%04d.jpg

这条命令的意思是:输入 input.mp4,用 fps 滤镜按每 2 秒抽一帧( fps=1/2 表示每秒抽 1/2 帧,即 2 秒一帧),输出质量等级 2 的 jpg 到 frames 目录,文件名按 frame_0001.jpg 递增。

几个关键参数解释一下:

  • -vf "fps=1/2" :抽帧频率。 fps=1 是每秒一帧, fps=1/2 是两秒一帧, fps=2 是每秒两帧。根据视频长度和内容密度调整。
  • -q:v 2 :jpg 质量,范围 2-31,数字越小质量越高。2 已经很高了,一般用 2-5 就够。
  • frame_%04d.jpg :输出文件名模板, %04d 表示 4 位数字补零,保证排序正确。

注意:抽帧前一定要先探测视频时长,否则你不知道会抽出多少帧。用 ffprobe 可以拿到时长:

ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.mp4

这条命令只输出时长秒数,干净利落,方便脚本里直接取值算帧数。

3.2 音频提取:为语音转文字做准备

音频这条线相对简单,但格式选择有讲究。语音识别模型一般对 wav 支持最好,采样率 16kHz、单声道是通用配置:

ffmpeg -i input.mp4 -vn -ac 1 -ar 16000 -acodec pcm_s16le audio.wav

参数含义:

  • -vn :不要视频流,只处理音频。
  • -ac 1 :单声道。语音识别不需要立体声,单声道还能减小文件体积。
  • -ar 16000 :采样率 16kHz。这是大多数语音识别模型的标准输入采样率,高了浪费,低了丢信息。
  • -acodec pcm_s16le :PCM 16 位小端编码,wav 的标准格式。

如果你的语音识别服务支持 mp3,也可以直接输出 mp3 省空间:

ffmpeg -i input.mp4 -vn -ac 1 -ar 16000 -b:a 64k audio.mp3

64k 码率对语音来说足够了,人声频段就那么宽,再高也听不出差别。

3.3 元信息提取:让 Agent 知道视频的“底细”

Agent 在决定怎么处理视频之前,需要先知道视频的基本信息:多长、多大、什么编码、多少帧率。这些用 ffprobe 一次性拿到:

ffprobe -v error -select_streams v:0 -show_entries stream=width,height,r_frame_rate,duration -of json input.mp4

输出是 JSON 格式,方便程序解析。 -select_streams v:0 表示只看第一个视频流,避免拿到音频流的信息混淆。

拿到这些信息后,Agent 可以做判断:比如视频超过 30 分钟,就降低抽帧频率;分辨率超过 1080p,就先把帧缩小再输出,省 token。

3.4 Skill 的目录结构与描述文件

Claude Code 的 Skill 一般放在特定目录下,每个 Skill 一个文件夹,里面至少有一个描述文件(通常是 markdown 格式),告诉 Agent 这个 Skill 是干嘛的、什么时候用、怎么调。

一个典型的 claude-video Skill 目录结构:

claude-video/
├── SKILL.md          # 描述文件,Agent 读这个决定是否调用
├── scripts/
│   ├── extract_frames.sh   # 抽帧脚本
│   ├── extract_audio.sh    # 提音频脚本
│   └── probe_video.sh      # 元信息探测脚本
└── README.md         # 给人看的说明

SKILL.md 的内容要写得让 Agent 一看就懂。核心是回答三个问题: 这个 Skill 能做什么 、 什么情况下该用它 、 怎么调用它 。比如:

---
name: claude-video
description: 当需要理解视频内容时使用。可以抽帧、提取音频、获取视频元信息。
---

# claude-video

让 Agent 具备处理视频的能力。

## 使用场景
- 用户提供了一个视频文件,需要分析内容
- 需要从视频中提取关键画面
- 需要把视频里的语音转成文字

## 调用方式
运行 scripts/extract_frames.sh <视频路径> <输出目录> <抽帧间隔秒数>
运行 scripts/extract_audio.sh <视频路径> <输出音频路径>
运行 scripts/probe_video.sh <视频路径>

描述文件里的 description 字段最关键,Agent 就是靠这句话判断要不要触发这个 Skill。写得太宽泛,Agent 动不动就调用;写得太窄,该用的时候想不起来。我的经验是 把触发条件写具体 ,比如“当用户提供视频文件路径且需要分析内容时”,而不是笼统的“处理视频”。

4. 实操过程:从零把 claude-video 跑起来

4.1 环境准备:ffmpeg 安装的几条路

ffmpeg 安装是新手最容易卡住的地方,我按平台说清楚。

Linux(Ubuntu/Debian) :

sudo apt update
sudo apt install ffmpeg

装完用 ffmpeg -version 验证。如果提示找不到命令,检查 PATH。

macOS :

brew install ffmpeg

Homebrew 装的 ffmpeg 一般带全了常用编码器,够用。

Windows :

官网下载编译好的包,解压后把 bin 目录加到系统 PATH 里。注意选对版本,一般选 essentials 版本就够,full 版本体积大很多但多了些不常用的编码器。解压路径别带中文和空格,否则命令行调用容易出问题。

提示:如果你需要硬件加速(比如用 GPU 解码),Linux 下可以装带 nvidia 支持的 ffmpeg 版本,但普通抽帧提音频用不上,CPU 足够了。别为了这个折腾半天,除非你确实要处理大量高清视频。

装完后跑一条测试命令确认能用:

ffmpeg -f lavfi -i testsrc=duration=5:size=320x240:rate=30 -f null -

这条命令生成一个 5 秒的测试视频然后丢弃,不报错就说明 ffmpeg 工作正常。

4.2 抽帧脚本的完整实现

我把抽帧脚本写成一个带参数校验的 bash 脚本,这样 Agent 调用时不容易出错:

#!/bin/bash
# extract_frames.sh - 从视频中抽帧
# 用法: ./extract_frames.sh <视频路径> <输出目录> <抽帧间隔秒数>

set -e

VIDEO_PATH="$1"
OUTPUT_DIR="$2"
INTERVAL="${3:-2}"  # 默认 2 秒一帧

if [ -z "$VIDEO_PATH" ] || [ -z "$OUTPUT_DIR" ]; then
    echo "用法: $0 <视频路径> <输出目录> [抽帧间隔秒数]"
    exit 1
fi

if [ ! -f "$VIDEO_PATH" ]; then
    echo "错误: 视频文件不存在: $VIDEO_PATH"
    exit 1
fi

mkdir -p "$OUTPUT_DIR"

# 计算 fps 值:间隔 2 秒 → fps=1/2
FPS="1/$INTERVAL"

ffmpeg -i "$VIDEO_PATH" \
    -vf "fps=$FPS" \
    -q:v 3 \
    "$OUTPUT_DIR/frame_%04d.jpg" \
    -hide_banner -loglevel error

FRAME_COUNT=$(ls "$OUTPUT_DIR"/frame_*.jpg 2>/dev/null | wc -l)
echo "抽帧完成,共 $FRAME_COUNT 帧,输出到 $OUTPUT_DIR"

几个细节说明:

  • set -e :任何命令出错就退出,避免错误被忽略。
  • INTERVAL="${3:-2}" :第三个参数可选,默认 2 秒。
  • -hide_banner -loglevel error :隐藏 ffmpeg 的版本信息和进度输出,只显示错误,让脚本输出干净。
  • 最后统计帧数,方便 Agent 知道抽了多少。

4.3 提音频脚本与语音转文字衔接

提音频脚本类似:

#!/bin/bash
# extract_audio.sh - 从视频中提取音频
# 用法: ./extract_audio.sh <视频路径> <输出音频路径>

set -e

VIDEO_PATH="$1"
AUDIO_PATH="$2"

if [ -z "$VIDEO_PATH" ] || [ -z "$AUDIO_PATH" ]; then
    echo "用法: $0 <视频路径> <输出音频路径>"
    exit 1
fi

ffmpeg -i "$VIDEO_PATH" \
    -vn -ac 1 -ar 16000 -acodec pcm_s16le \
    "$AUDIO_PATH" \
    -hide_banner -loglevel error

echo "音频提取完成: $AUDIO_PATH"

拿到 wav 之后,接语音识别。如果你用的是本地模型(比如 whisper 系列),直接跑就行;如果用云端 API,把 wav 传上去拿文本。这一步不在 Skill 内部做,而是交给 Agent 决定用哪个识别服务,保持灵活性。

4.4 元信息探测脚本

#!/bin/bash
# probe_video.sh - 获取视频元信息
# 用法: ./probe_video.sh <视频路径>

set -e

VIDEO_PATH="$1"

if [ ! -f "$VIDEO_PATH" ]; then
    echo "错误: 视频文件不存在: $VIDEO_PATH"
    exit 1
fi

ffprobe -v error \
    -select_streams v:0 \
    -show_entries stream=width,height,r_frame_rate,duration \
    -show_entries format=duration,size \
    -of json \
    "$VIDEO_PATH"

输出 JSON 里包含宽高、帧率、时长、文件大小,Agent 解析后就能做决策。

4.5 在 Claude Code 里注册并调用

把 claude-video 文件夹放到 Claude Code 的 skills 目录下(具体路径看你的安装配置,一般在用户目录下的 .claude/skills/ 或者项目内的 .claude/skills/ )。放好后重启 Claude Code,或者用它的 skill 重载命令。

验证是否注册成功:在对话里问一句“你能处理视频吗”,如果 Agent 提到了 claude-video 的能力,说明注册成功。

实际调用时,你直接说“帮我分析一下这个视频 /path/to/video.mp4”,Agent 会自己判断触发 claude-video,先探测元信息,再抽帧提音频,最后把帧和文本拿去做理解。整个过程你只需要给一个视频路径。

注意:Skill 的触发依赖描述文件的 description 字段,如果 Agent 没触发,先检查这个字段写得够不够明确。我踩过的坑是描述写得太学术,Agent 理解不了,改成大白话“当用户提供视频文件需要分析时使用”就正常了。

5. 常见问题与排查技巧实录

5.1 抽帧相关的高频问题

问题一:抽出来的帧是黑的或者花屏。

这通常是视频编码格式特殊,或者 ffmpeg 版本太老不支持。先升级 ffmpeg 到较新版本,再试。如果还不行,加 -vsync vfr 参数让 ffmpeg 按可变帧率处理:

ffmpeg -i input.mp4 -vf "fps=1/2" -vsync vfr -q:v 3 frames/frame_%04d.jpg

问题二:抽帧数量远超预期。

检查视频时长和抽帧间隔。如果视频是 1 小时,间隔 2 秒,那就是 1800 帧,确实多。这种情况要么加大间隔,要么先用场景检测只抽关键帧:

ffmpeg -i input.mp4 -vf "select='gt(scene,0.3)',showinfo" -vsync vfr frames/frame_%04d.jpg

gt(scene,0.3) 表示场景变化超过 30% 才抽,能大幅减少帧数。

问题三:输出目录不存在导致失败。

脚本里已经用 mkdir -p 处理了,但如果你手动跑命令,记得先建目录。这是新手最常见的错误,ffmpeg 不会自动创建输出目录。

5.2 音频提取的坑

问题一:提取的音频没声音。

检查原视频是不是本来就没音轨。用 ffprobe 看有没有 audio stream:

ffprobe -v error -select_streams a -show_entries stream=codec_name -of default=noprint_wrappers=1 input.mp4

没输出就说明没音轨,不是提取的问题。

问题二:音频文件太大。

wav 是无损的,体积大正常。如果只是做语音识别,转成 mp3 或 opus 能小很多:

ffmpeg -i input.mp4 -vn -ac 1 -ar 16000 -b:a 32k audio.opus

opus 在低码率下语音质量比 mp3 好,32k 就够用。

5.3 Skill 调用层面的问题

问题一:Agent 不触发 Skill。

三个排查方向:描述文件的 description 是否明确、Skill 目录位置是否正确、Claude Code 是否重启加载。我遇到过目录放对了但没重启,Agent 一直看不到的情况。

问题二:脚本没有执行权限。

Linux/macOS 下脚本需要可执行权限:

chmod +x scripts/*.sh

Windows 下用 git bash 或者 wsl 跑,别用 cmd 直接跑 bash 脚本。

问题三:路径里有空格或中文导致失败。

脚本里变量加引号 "$VIDEO_PATH" 能处理空格,但中文路径在某些环境下仍有问题。建议处理前先把视频复制到纯英文路径下。

5.4 常见问题速查表

现象 可能原因 解决方法
抽帧全黑 编码不支持 升级 ffmpeg,加 -vsync vfr
帧数过多 间隔太小 加大间隔或用场景检测
音频无声 原视频无音轨 用 ffprobe 确认
Agent 不触发 描述不明确 改 description 为具体场景
脚本无权限 未加执行权限 chmod +x
路径报错 空格/中文 加引号,复制到英文路径

5.5 几个我踩过的坑和独家技巧

技巧一:抽帧前先缩放,省 token。 如果视频是 4K,抽出来的帧也是 4K,喂给模型 token 消耗巨大。加个 scale 滤镜先缩到 720p:

ffmpeg -i input.mp4 -vf "fps=1/2,scale=1280:-1" -q:v 3 frames/frame_%04d.jpg

scale=1280:-1 表示宽度缩到 1280,高度按比例自动算。模型看 720p 的帧足够理解内容了。

技巧二:用临时目录,别污染工作区。 抽帧会产生大量文件,建议输出到 /tmp 或系统临时目录,处理完让 Agent 自己清理。我在脚本里加了个清理逻辑,处理完自动删帧,避免磁盘被塞满。

技巧三:长视频分段处理。 超过 30 分钟的视频,一次性抽帧可能几百上千张,Agent 处理不过来。可以按时间分段,每段单独抽帧,Agent 逐段分析。ffmpeg 的 -ss 和 -t 参数可以指定起始时间和时长:

ffmpeg -ss 00:10:00 -t 00:05:00 -i input.mp4 -vf "fps=1/2" frames/part2_%04d.jpg

注意 -ss 放在 -i 前面是快速定位,放在后面是精确但慢。抽帧用快速定位就够。

技巧四:帧文件名要能排序。 %04d 补零到 4 位,保证 frame_0001 到 frame_9999 排序正确。如果视频帧数可能超过 9999,用 %05d 。

6. 这套方案还能怎么扩展

claude-video 目前做的是“视频转帧 + 音频转文本”的基础能力,但它的扩展空间很大。我自己在用的几个方向:

方向一:接 OCR 做画面文字提取。 抽出来的帧如果有字幕、PPT、界面文字,可以再过一道 OCR,把画面里的文字也变成文本。这样 Agent 对视频的理解就从“画面 + 语音”扩展到“画面 + 语音 + 画面文字”,信息更全。

方向二:场景检测替代固定间隔。 固定间隔抽帧在画面变化剧烈时会漏掉关键帧,在画面静止时又浪费帧。用 ffmpeg 的 scene 检测滤镜,只在画面变化时抽帧,效率更高。我实测下来,对教程类视频,场景检测能减少 60% 的帧数,但关键信息一个不丢。

方向三:和 Agent 的记忆机制结合。 处理过的视频,把抽帧结果和文本摘要存起来,下次遇到同一个视频直接读缓存,不用重复处理。这对批量处理场景很有用。

方向四:支持更多输入源。 目前是本地视频文件,扩展到网络视频流、摄像头实时流也是可行的,ffmpeg 本身就支持这些输入。不过实时流处理对延迟要求高,需要另做优化。

我个人在实际操作中的体会是,Skill 这类工具的价值不在于功能多复杂,而在于 边界清晰、职责单一 。claude-video 就干一件事——把视频拆成 Agent 能吃的格式,拆完就退场,剩下的交给模型。这种设计让整个链路可调试、可替换、可扩展。你如果也在做 Agent 的多媒体能力,建议从这种“单一职责”的 Skill 开始,别一上来就搞大而全的框架,先把一个场景跑通,再逐步加能力。踩过几次坑之后你会发现,能稳定跑通的基础能力,比花哨但脆弱的复杂功能有用得多。

Logo

火山引擎视频云技术社区,是面向 AI 音视频开发者的技术交流平台。这里汇聚源自抖音、豆包等亿级 DAU 产品的 RTC、直播、点播、AI 媒体处理、音视频互动技术,提供接入指南、最佳实践、性能调优、场景案例、Demo 代码、开源项目、白皮书和 API 文档。社区汇聚官方工程师与一线开发者,为 AI 视频通话、数字人、AI 视频处理等应用的开发与落地提供技术支持。

更多推荐