给Agent装上眼睛:claude-video视频理解Skill实现全拆解
我在给Agent加技能这条路上折腾了小半年,试过让它读PDF、解析Excel、操作浏览器,但每次一碰到视频就卡壳。"这视频里讲了什么""帮我把这个教程的关键步骤拎出来"——这类需求的本质是:Agent需要一双眼睛,而不只是会读文字。于是就有了 claude-video 这个Skill。
这篇文章会完整拆解这个Skill的实现方案:Skill目录结构怎么设计、ffmpeg帧提取参数怎么选、Claude视觉模型怎么接、Token成本怎么控制,以及我最开始踩过的那些坑。适合正在做Agent开发、想给Agent加多模态能力的同学参考,纯想理解原理的也能顺着捋一遍。
1. 为什么Agent需要"眼睛":视频理解要解决的真实需求
我一直觉得多模态能力是Agent从"能用"到"好用"的分水岭。文本类任务做到后面,大家拼的都是编排和工具调用熟练度,反而真正的瓶颈在于:世界上大多数信息根本不以纯文本形式存在。视频尤其典型——一个10分钟的教程,可能70%的信息是靠画面演示传递的,字幕和音频稿承载不了全部内容。
有个很直观的例子。我给Agent布置了"把这段产品演示视频整理成操作手册"的任务,如果它只能读音频转写稿,那么它看到的就是"然后这里点击一下,这边会弹出一个窗口"这类话,完全无法理解"这里点击"点的到底是哪个按钮、"弹出一个窗口"长什么样。人脑看视频会自然地对照画面和语音信息。要让Agent做同样的事,就得给它一双眼睛,让它在看视频的时候能真的"看见"每一帧里发生了什么。
claude-video 这样的Skill,解决的就是这个需求。不过这里有两个名词需要先理清楚—— Skill和Agent的区别 。简单说:Agent是决策者和执行者,负责理解任务、规划步骤、调用工具;Skill是被调用的能力模块,封装了"这个特定任务怎么做"的经验和脚本。打个比方,Agent是厨师,Skill是菜谱。没有厨师,菜谱只是一堆纸;没有菜谱,厨师什么菜也不会做。claude-video 就是一张针对"视频理解"这道菜的菜谱。
从底层来看,视频理解难在三个地方:
- 信息密度大 :一秒钟24帧画面,10分钟视频就是14400帧,全部塞给视觉模型既不现实也不划算
- 多模态交叉 :画面、字幕、语音、音频节奏互相补充,只看画面会漏掉关键台词,只听声音又漏掉视觉信息
- 时间维度 :视频是有时间顺序的,Agent不仅要回答"画面里有什么",还要回答"事情发生的先后顺序"
这三个难点决定了 claude-video 的核心不是"接一个视觉模型API"这么简单,而是要做一整套采样和融合策略。这也是我写这个Skill的主要原因——真正麻烦的不是调用Claude的视觉能力,而是怎么选帧、怎么问、怎么把结果拼成一个有用的输出。
2. Skill先行:claude-video的整体结构与运行逻辑
在设计 claude-video 之前,我给自己定了一条原则:任何Skill都应该是一个可以独立运行的闭环,而不是把逻辑散落在Agent的主提示词里。这样才好维护、好调试、好复用。
2.1 一个Skill的骨架应该长什么样
Anthropic生态里Skill的标准结构大致是这样的:
claude-video/
├── SKILL.md # 技能元信息、触发条件、使用说明
├── requirements.txt # Python依赖清单
├── config.yaml # 帧提取参数、模型参数、输出格式配置
├── scripts/
│ ├── extract_frames.py # 视频帧提取
│ ├── analyze_video.py # 调用视觉模型进行分析
│ ├── filmstrip.py # 帧拼接,节省Token
│ └── utils.py # 公共工具函数
└── assets/ # 缓存、临时文件
SKILL.md 是整个Skill的"入口说明书",它决定了Agent什么时候该调用这个Skill、怎么调用。我的 SKILL.md 前端信息大概长这样:
---
name: claude-video
description: 当用户提供视频文件或视频路径,并希望了解视频内容、总结画面要点、提取操作步骤、定位特定场景时,使用此Skill。支持mp4、mov、avi等常见格式。
trigger: 检测到视频文件输入,或用户明确要求"看视频""总结视频""这个视频讲了什么"
---
很多人在写Skill时都不重视description,但实际上对Agent来说,description就是"雷达"。写得太泛,Agent不知道什么时候该调用;写得太细,又容易漏掉边缘场景。我的经验是:把用户最常说的几种问法直接写进trigger里,匹配率会明显提升。
2.2 处理流程:从视频文件到结构化结论
claude-video 的完整处理流程是:
- 接收视频文件后,先用ffmpeg做技术检查——分辨率、时长、编码格式,确认能正常解码
- 按配置的采样策略提取关键帧,保存到临时目录下的JPEG图片
- 对帧做批量处理:要么直接分组发给视觉模型,要么先拼接成filmstrip再发
- 同时(可选)调用音频转写工具,拿到语音层的文本信息
- 视觉模型输出的描述和转写文本一起注入分析提示词,生成最终结构化结果
我把第3步和第4步设计成 并行执行 的,因为视频的画面信息和语音信息天然是两个独立维度,最后再融合,比先融合再分析要省Token,也更灵活。后面实测也验证了这一点——只靠画面能识别出人物的操作动作,只靠字幕能拿到精确的台词和术语,两者结合才完整。
2.3 为什么拆成独立脚本而不是一个大函数
这里多说一句设计层面的思考。拆成 extract_frames.py 和 analyze_video.py 两个脚本,最直接的好处是 能单独调试 。开发早期,我经常发现帧提取很成功、图片也很清晰,但分析结果一塌糊涂。如果所有代码揉在一个文件里,你根本定位不到问题出在帧质量还是模型提示词。
另一个考虑是复用性。extract_frames.py 将来可以被其他视觉类Skill直接引用;analyze_video.py 也能单独跑——输入一个图片目录就能输出分析结果,未必非要绑定视频。这种"拆成可独立运行的小模块"的习惯,在我后来写其他Skill时帮了很大忙。
3. 核心实现:帧提取、视觉分析与上下文组装
这一节是 claude-video 真正的核心。我把帧提取策略、视觉模型调用、Token成本控制三件事讲透,这部分也是实操参考价值最高的内容。
3.1 ffmpeg帧提取:三种策略怎么选
帧提取是整个Skill的地基,也是最容易被低估的一步。选帧选得好不好,直接影响后续分析的质量。
策略一:均匀采样
最朴素的方式是按固定时间间隔取帧:
ffmpeg -i input.mp4 -vf "fps=1/2" -q:v 2 frames/frame_%04d.jpg
上面这条命令表示每2秒取一帧。
-q:v 2
是JPEG质量参数,范围2-31,值越小质量越高,2到5之间都是合理区间。别用默认值,默认的JPEG压缩会让画面细节糊掉,尤其影响小字和图标。
均匀采样的优点是简单可控、覆盖均匀;缺点是没有重点,遇到"前3分钟在闲聊、后2分钟突然进入正题"这种节奏不均的视频,会浪费大量帧在废话上。
策略二:场景检测
用ffmpeg的scene检测,在画面内容发生明显变化时取帧:
ffmpeg -i input.mp4 -vf "select='gt(scene,0.3)',showinfo" -f null - 2>&1
Python封装之后可以拿到变化点的时间戳列表:
import subprocess
import re
def detect_scenes(video_path, threshold=0.3):
cmd = [
"ffmpeg", "-i", video_path,
"-vf", f"select='gt(scene,{threshold})',showinfo",
"-f", "null", "-"
]
result = subprocess.run(cmd, capture_output=True, text=True)
pts_times = re.findall(r"pts_time:([\d.]+)", result.stderr)
return [float(t) for t in pts_times]
threshold 是场景变化敏感度,0到1之间。0.3-0.4通常能比较好地捕捉"PPT翻页""镜头切换"这类明显变化,同时又不会因为画面里一个轻微移动就疯狂取帧。
场景检测的好处是精准,坏处是要把完整视频先过一遍,多一道耗时流程。另外,它容易漏掉"镜头没切但画面内容在缓慢变化"的场景,比如渐入渐出的动画。
策略三:混合策略
我最终在 claude-video 里默认用的是混合策略:先做场景检测选出关键帧,同时做低频率的均匀采样兜底,两边结果合并去重。这样既覆盖了重点,又不至于漏掉画面连续变化的长镜头段落。
采样频率怎么定?给个参考经验:10分钟的视频,混合策略出来的候选帧一般在100到200张之间,再根据实际需要和Token预算做二次筛选或拼接。这个量既能保留足够细节,又不至于让成本和延迟失控。
3.2 用Claude的视觉能力分析帧序列
帧提取完成后,接下来就是把图片交给Claude看。单个帧直接传是最直观的方式:
import base64
from anthropic import Anthropic
client = Anthropic()
def frame_to_base64(frame_path):
with open(frame_path, "rb") as f:
return base64.b64encode(f.read()).decode()
def analyze_frames(frame_paths, question):
content = []
for path in frame_paths:
content.append({
"type": "image",
"source": {
"type": "base64",
"media_type": "image/jpeg",
"data": frame_to_base64(path)
}
})
content.append({"type": "text", "text": question})
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=2048,
messages=[{"role": "user", "content": content}]
)
return response.content[0].text
这里有一个非常关键的设计决策: 一次调用最多塞多少帧? 这直接关系到效果和成本。
Claude 的视觉模型对单张图片是按Token计费的。一张普通分辨率的JPEG,大概消耗1000到1600个Token。如果你把150帧全部塞进一次调用,光图片就是二十万Token,贵不说,模型在长上下文里对早期图片的记忆也会衰减,结果往往是"看到了所有画面,但什么都没记住"。
我实测后的经验是: 一次调用控制在8到12帧之间 ,针对这一小段帧回答一个具体问题,然后多轮调用,把结果汇总。就像人看视频也是"一段一段"地看,而不是把几千帧一次性在脑子里过。
如果你需要的是"大范围扫描",那还有另一种做法——filmstrip拼接,把若干帧缩小后拼成一张网格图:
ffmpeg -i input.mp4 -vf "fps=1/10,scale=320:-1,tile=3x3" -an contact_%03d.jpg
这条命令把每10秒取一帧、缩放到320宽度、并按3x3排列拼成一张大图。9个时间点的画面合成一张图,Token成本大约是直接传9张独立图的九分之一。缺点也很明显:分辨率压缩后细节识别能力下降,适合做"快速概览",不适合做精细分析。实际使用时,我通常先用filmstrip做第一轮概览,再针对感兴趣的时间段用原分辨率帧做精细分析,两轮结合。
3.3 提示词设计:让分析结果结构化、可复用
视觉分析最容易被忽视的是提示词设计。直接问"这张图里有什么",模型会给你一段散文式的描述,在Agent工作流里基本没法用。我用的提示词模板是强制输出JSON的:
question = """
请仔细分析这些视频帧,它们是按时间顺序排列的。
基于这些画面,回答以下问题:
1. 画面中出现的主要人物或物体是什么?
2. 正在发生什么操作?按时间顺序描述关键动作。
3. 画面中是否有文字信息(如PPT标题、界面文案、字幕)?请原样输出。
请以JSON格式返回:
{
"objects": [],
"actions": [],
"texts": [],
"timeline_summary": ""
}
"""
强制JSON输出的价值在于:下游Agent可以直接把结果解析成结构化数据,再结合语音转写文本,进行后续的问答、总结或检索。调试过程中我发现,只要在提示词里明确"请以JSON格式返回"并给出字段示例,模型输出的规范度会非常高。偶尔有个别字段缺失,用
json.loads
加一个异常兜底就好。
语音转写这块,claude-video 调的是本地的 faster-whisper,好处是隐私友好、不额外产生API费用,坏处是需要一定的机器算力。对10分钟的视频,转写通常不到1分钟就能跑完,属于可接受的代价。
4. 实战验证:三类典型视频的测试结果
光说不练没用。我把 claude-video 接到Agent上,跑了三类视频测试——网课录像、产品演示视频、短视频,分别看它在不同场景下的表现。
4.1 网课录像:自动提炼章节大纲
测试用的是一段45分钟的网课录像,内容是"HTTP缓存机制",PPT翻页频繁、画面基本静止。
提取帧数方面,混合策略共选出210帧,先用filmstrip做概览,再对重点区间做精细分析。最终输出的结果是一份带时间戳的章节大纲,比如"00:00-03:12 缓存的定义与分类"、"03:15-08:40 强缓存与协商缓存对比"、"08:45-15:20 Expires与Cache-Control的区别"。
和我手动看视频记录的大纲对照,覆盖率在90%以上。一个小遗憾是第23分钟左右老师口述了一个"个别同学可能遇到的坑",只有语音没有PPT画面,这块如果只靠视觉模型确实会漏。后面我做了个修正:语音转写完成后,把转写文本单独过一遍,提取"视觉画面无法体现的知识点",再把两边结果合并。修正后覆盖率提升到了95%左右。
4.2 产品演示视频:操作步骤的精细拆解
第二段测试用的是某个SaaS产品7分钟的演示视频,画面里大量鼠标移动、界面切换、表单填写。这个场景考验的是视觉模型对"操作动作"和"界面元素"的理解能力。
结果是:claude-video 成功拆解出了16个操作步骤,包括"在右上角设置入口打开偏好设置""切换到'通知'标签页""勾选'邮件通知'并保存"。模型能准确识别界面上的中英文混合文案,甚至连按钮颜色这种细节都能说出来。不过也暴露了一个问题:鼠标快速划过表单、弹窗一闪而过时,单靠1帧/2秒的采样会错过关键瞬间。对这种操作密集的视频,我把采样频率临时调到了1帧/0.5秒,用额外的Token换回细节,效果立刻上来了。
这个经验后来被我写进了 config.yaml——增加了
density: high|medium|low
参数,Agent可以按视频类型手动指定采样密度,默认medium,操作演示类的视频手动切到high。
4.3 短视频内容分析:从脚本到画面构图
第三类测试是分析一条48秒的短视频,内容是个搞笑短剧。这类内容的信息密度和节奏跟教程完全不同,视觉信息量大、切换快、还有大量动作和表情。
claude-video 输出的分析包括:场景数量4个、主要人物2人、核心剧情线(A邀请B参加聚会、B误以为被捉弄、反转是惊喜派对)、关键道具(蛋糕、彩带)、以及画面构图特点(多用中景和近景切换制造笑点节奏)。
说实话,这类创意内容的分析主观性很强,机器输出不一定完全准确,但作为"内容体感理解"的参考,已经足够让Agent基于它做二次创作——比如改写文案、生成脚本、或者做同类风格检索。短视频分析这块,我认为真正的价值不在"分析内容"本身,而在于给后续创作提供一个结构化底座。
5. 集成到Agent工作流的正确姿势
claude-video 做得再好,如果不接入Agent工作流,它就是一个独立的命令行工具。真正让它变成Agent能力的,是集成这一步。
5.1 两种主流集成方式
我试过两种集成方式,各有适用场景。
方式一:作为MCP工具接入
把 claude-video 的核心逻辑封装成一个MCP工具,Agent通过工具名直接调用。好处是标准、解耦,别的Agent也能方便地用起来;缺点是MCP层的读写和通信会额外增加一些延迟,而且工具描述如果写得不好,Agent可能会漏调用。
方式二:把Skill的触发逻辑写进Agent系统提示词
这种更"轻",不搞单独的服务,直接把 claude-video 的 SKILL.md 内容作为Agent系统提示词的一部分,让Agent在处理用户消息时自行判断"该不该调用视频理解能力"。好处是响应快、灵活,坏处是系统提示词会越来越长,Token开销增加,且Agent的自判成功率依赖提示词质量。
实际项目中,我通常会混用:Agent侧维护一份精简版的"能力清单",里面有 claude-video 的简介和触发条件;Agent判断需要时,通过子进程或函数调用执行对应的Python脚本。这样既保留了Agent的自判灵活性,又不需要维护一个完整的MCP服务。
5.2 上下文传递:不要把分析和总结混在一起
有一个常见错误设计:让Agent"一边分析视频一边回答用户问题"。这会导致Agent为了回答用户问题,硬把视觉模型的中间输出塞进回复里,产生一堆噪音。
我把上下文传递分成两段。第一阶段,claude-video 只负责分析,输出结构化的JSON存到一个中间变量里,Agent不直接看到分析过程;第二阶段,Agent根据用户的实际问题,从结构化结果中检索并组织答案。有点像RAG的思路——先建索引,再回答问题,两者在不同层次解耦。这样既省Token,回答质量也更稳定。
5.3 并行处理与异步任务的设计
视频分析耗时较长,几十秒到几分钟不等,Agent如果同步等待,用户体验会很差。我在集成时做了两件事:一是把耗时任务放到后台队列执行,Agent先返回"视频正在分析中,稍后告诉你结果";二是分析完成后,通过消息推送或状态轮询把结果回传。
这听起来像工程常识,但在Agent开发里特别容易被忽略——很多人在Demo阶段用同步方式跑通了就算了,一放到真实场景就暴露出超时问题。claude-video 的完整分析流程(帧提取+场景检测+视觉分析+语音转写)在普通机器上对10分钟视频通常需要1到3分钟,这个耗时决定了异步处理不是可选项,而是必须项。
6. 踩坑记录:我在开发claude-video时遇到的六个问题
这部分分享一些真实的坑,每个都是花时间踩出来的,希望能帮后来者省点功夫。
6.1 帧文件名排序陷阱
第一个坑来得特别快。我用
frame_%04d.jpg
命名帧文件,提取出来后直接在Python里
sorted(os.listdir(frames_dir))
,发现顺序是乱的——不是1、2、3、4,而是1、10、11、12、2、20、21。原因很简单:字符串按字典序排序,
frame_10.jpg
排在
frame_2.jpg
前面。
这个问题如果不处理,模型看到的画面顺序是乱的,时间线分析直接全错。修复很简单:
def sorted_frames(frames_dir):
return sorted(
os.listdir(frames_dir),
key=lambda x: int(re.search(r"(\d+)", x).group(1))
)
或者用zfill左补零,
frame_001.jpg
这种命名天然规避了字典序问题。这个坑虽然小,但确实影响最终效果,而且特别隐蔽——不仔细核对时间线结果根本发现不了。
6.2 Token预算失控:一次分析烧掉几万Token
开发阶段我踩过一个更疼的坑:一次完整分析下来Token费用高得吓人。问题出在三个地方:一是帧数没有上限,视频越长帧越多;二是
-q:v
质量参数设太高,每张图片体积巨大,而Claude对图片按分辨率计费,大图自然贵;三是没有用filmstrip,几百张图全部原图直传。
后来我把Token预算逻辑写进了 config.yaml:
budget:
max_frames_per_batch: 12 # 每次视觉调用最多帧数
overview: "filmstrip" # 概览阶段使用拼接图
detail_interval: 0.5 # 精细分析阶段采样频率
max_total_frames: 240 # 单视频总帧数上限
超过
max_total_frames
的视频,先按比例稀疏化,再对用户重点关注的区间做局部精细分析。这个逻辑上线后,单视频分析成本降到了原来的三分之一左右,效果损失几乎可以忽略。
6.3 视频里的文字:OCR能力还是不够
我原以为Claude视觉模型能很好地识别画面里的所有文字,实测下来发现不一定。大号字体、清晰界面的文案识别率很高,但小字号、花式字体、或者带背景噪声的文字(比如飘过的弹幕),识别率明显下降。
针对这个问题,我在pipeline里加了一个可选的OCR步骤,用PaddleOCR对关键帧做文字识别,再把OCR结果作为补充信息注入分析提示词。这相当于给Agent做了一次"视觉+OCR"的双通道读取,实测对PPT翻拍类视频的字幕提取提升明显。代价是多一道处理流程,所以做成可选开关,默认关闭,用户明确需要精准提取文字时再打开。
6.4 ffmpeg环境问题:好解码器比好模型更实际
别看ffmpeg是老牌工具,环境坑也不少。我遇到过的有:部分视频编码(比如HEVC、AV1)需要额外的解码器,服务器上精简编译的ffmpeg直接报错;中文字体问题导致的drawtext失败;视频文件大时,默认临时目录磁盘空间不够。
性能上也有个小建议:如果视频分辨率是4K,提取帧前先缩放:
ffmpeg -i input.mp4 -vf "scale=1280:-1,fps=1/2" -q:v 3 frame_%04d.jpg
原因很简单,4K原图的Token开销是按面积算的,同样内容缩到1080p,Token成本能降不少。在不影响内容理解的前提下,统一缩放到720p或1080p是最经济的做法。这条规则现在写在了 extract_frames.py 的默认参数里。
6.5 转写文本的时间轴与帧的时间轴对不齐
还有一个比较隐蔽的问题:语音转写的文本自带时间戳,帧提取的时间戳基于视频播放时间,理论上两者应该对得上,实际却经常出现偏移。
偏移来源一般是转写模型内部做了静音裁剪,或者ffmpeg读取时丢帧。我在融合阶段的做法是:不直接依赖任何一方的时间戳做"精确对齐",而是建立"时间段-内容"的映射——把视频切成30秒一个的区间,每个区间独立汇聚画面信息和语音信息,在区间层面做融合。这样即使单帧的时间戳有偏差,区间级的信息匹配依然稳定。
6.6 Agent触发失败:用户就是不发视频文件
最后一个坑来自Agent行为层面。用户对Agent说"帮我看看这个视频",但没有附上文件,Agent就不会触发 claude-video,而是干巴巴地回复"请先上传视频文件"。听起来合理,但体验很差。
我改进了 SKILL.md 的description,加了"当用户提到视频但未提供文件时,应主动询问视频来源(本地路径、URL或直接拖拽上传),并验证可访问性后再调用"。另外还在Skill里加了URL下载支持的代码——现在Agent可以从一个可访问的视频链接直接拉取文件进入分析流程。看似小的优化,实际使用率提升非常大。
7. 边界、成本与下一步扩展
到这里,claude-video 已经能完成"视频输入→结构化分析→融入Agent回答"的完整链路。我得坦白说它仍然有边界。
最明显的短板是音频里除了对话以外的信息:视频背景音乐的氛围、音效的节奏变化,目前 claude-video 基本不处理。替代方案是接一个音频理解模型做情感或氛围分析,但我还没找到性价比合适的方案,这块先搁着。
另外一个约束是延迟和成本。一次完整分析,10分钟的视频在普通机器上耗时1到3分钟,Token成本折合下来几毛到几块钱人民币不等,取决于采样密度和模型档次。如果你要处理大量视频,建议先跑一遍filmstrip概览,筛选出值得精细分析的片段再做深度处理,别一步到位。
后续我打算做两件事。一是帧嵌入检索——把关键帧的视觉特征向量化,让Agent实现"找视频里出现过XX的画面"这类语义检索任务,相当于把视频变成可搜索的资产,这也让 claude-video 天然变成一个视频RAG系统的数据入口。二是多视频对比——目前一次只分析一个视频,但实际工作中经常有"帮我对比三版宣传片有什么区别"这类需求,这需要把单个视频分析的结果统一成同构schema,再做跨视频对齐比较。
做Agent开发这段时间,我越来越觉得多模态理解是当前Agent能力拼图里溢价最高的一块。很多人卡住不是因为不会调API,而是没把顺序想清楚:先定义清楚能力边界,再设计采样与融合策略,最后才是接入Agent工作流。claude-video 这个Skill把前面两步做得比较扎实,所以接进Agent之后表现一直很稳定。希望这篇拆解能给你带来一些可以直接上手的思路。
更多推荐
所有评论(0)