先说一个我最近特别有感触的场景:你让Agent去整理一段产品发布会视频的要点,它要么回你一句“我只能处理文本和图片”,要么就是假装听懂、给你编一段完全不靠谱的总结。这不是Agent笨,而是它天生就少了一个感知维度——眼睛看不到动态画面,耳朵听不到声音。claude-video这类Skill的出现,本质上就是在给Agent补上“看视频”这块短板。它不是一个独立的大模型,而是一套标准化的技能插件,通过抽帧、视觉理解、音频转写和目标总结的组合拳,把视频变成Agent能消化的结构化信息。这篇文章我就从设计思路、核心实现、实操细节到常见坑位,完整拆一遍这个项目,适合正在做Agent开发、或者天天被“视频内容理解”折磨的同行参考。

先说清楚一个前提:这里说的“看视频”,不是让模型直接吃MP4文件。现在的多模态模型再强,也没法把整段几十分钟的视频一次性灌进上下文里,算力和成本都扛不住。所以凡是做视频理解的Agent Skill,底层逻辑基本都绕不开“先拆解再理解”这条路。claude-video也不例外,它的核心套路,就是下面这几件事的组合。

1. 先搞清楚一件事:Agent为什么需要“看视频”能力

1.1 Agent的感知瓶颈:文本模型如何“看见”世界

大多数Agent产品跑在Claude、GPT这类大模型之上,它们的强项是文本推理、代码生成和结构化输出,但输入侧天然偏向文本和静态图片。遇到视频,模型既没有“连续播放”的概念,也没有“边看边记”的机制——你给它一个视频链接,它默认是抓瞎的。

这里有个很关键的认知:Agent不是不能处理视频,而是缺少把视频“翻译”成自身能理解的信息的中间层。就像一个人不懂法语,但他可以借助翻译官看懂法语材料。claude-video这个Skill,扮演的就是那个“翻译官”。它把视频的画面、语音、字幕这些异构信息,统一转化成文字描述和时间轴标注,Agent拿到手的是一份“视频的文字版切片报告”,接下来无论是总结、问答还是提取要点,都是它最擅长的活了。

我自己试过直接让没有这个Skill的Agent看视频链接,结果十次有八次它开始自由发挥,编造画面内容,而且编得理直气壮。这其实不怪Agent,问题出在“没有可靠的感知入口”。所以与其抱怨模型不聪明,不如从工程上把入口问题解决掉。

1.2 Skill机制:Agent能力扩展的标准姿势

Skill这股风从Anthropic提出Agent Skills概念之后,在开发者社区里火得很快。这东西本质就是一个目录结构:一个文件夹里放一个SKILL.md说明文件,外加若干脚本、模板和资源文件。Agent在运行时会根据任务需要,动态加载对应的Skill,按里面的指令一步步执行。

为什么这种机制对扩展Agent能力这么重要?因为它把“知识”和“工具”打包成了可复用的模块。以前给Agent加能力,要么改系统提示词,要么在代码里硬编码工具函数,改一处动全身,别人也没法复用。Skill模式把每个能力变成一个独立单元,你想让Agent会看视频,就往技能目录里丢一个claude-video;想让Agent会做数学建模,就丢一个数学建模Skill。互相独立、按需加载,这才是Agent生态开始走向标准化的信号。

再往深了说,Skill的加载机制通常还带一个“预执行指令”的概念。SKILL.md里不仅写清楚了“这个技能是干什么的”,还会告诉Agent“你遇到什么类型的请求时该调用我”“调用我之后第一步做什么、第二步做什么”。相当于给Agent塞了一份操作手册,而不是单纯给它一把锤子。

1.3 claude-video能做什么,不能做什么

先把边界划清楚,免得大家期望值跑偏。claude-video能做的,包括这几类事情:

  • 给一段完整视频生成内容摘要,比如“这是一段15分钟的产品发布会,前5分钟讲新硬件参数,中间讲软件生态,最后是价格公布”。
  • 针对视频内容做定向问答,比如“这个视频里主讲人提到的最重要的三个指标是什么”。
  • 按时间点定位关键事件,比如“第三分钟屏幕上出现了对比表格,对比了旧款和新款的续航”。
  • 提取视频里的文字信息,比如PPT上的要点、屏幕上的对话框、字幕内容。

它做不到的也很明确:无法实时分析视频流,无法对超高清、超长(几小时以上)视频做精细逐帧理解,无法精确识别复杂动作细微差异(比如舞蹈动作的连贯性评估)。这些受限于抽帧策略和模型能力,属于当前阶段的技术边界。

搞清楚了这些边界,你对这个Skill的定位就能摆正:它解决的是“让Agent懂视频内容”这个80%的高频需求,剩下的20%极端需求,得靠更专业的定制方案。

2. claude-video的整体设计思路与方案选型

2.1 为什么选“抽帧+视觉模型”而不是直接喂视频

老实说,最初有人尝试过直接把视频按Base64塞给多模态模型,结果要么报错、要么上下文瞬间爆炸。一段10分钟的视频按每秒25帧算,一共15000帧,哪怕只抽取千分之一,也有15张图,再配上音频转写文本,一次任务的token消耗轻松破几十万。这还没算模型对“连续画面”的理解能力远没有达到人类水平,逐帧喂进去反而会稀释注意力。

所以行业内目前的主流做法,几乎统一是“抽帧降维”:先把视频按策略抽取代表性帧,再用视觉模型逐张识别或批量识别,产生文本描述;同时用语音识别提取音频内容,最后把这两路信息合并,交给主模型做推理。claude-video沿用的就是这条链路,它不是标新立异,而是选择了一条最稳、最可控、效果最可预期的路线。

这个方案还有个隐性好处:可插拔。抽帧可以用ffmpeg,视觉理解可以用Claude的视觉能力,也可以换成其他开源模型,音频转写可以用Whisper或云端接口。每一环都是标准接口,想替换哪一块都容易。这种设计哲学,对于要长期维护的项目来说,比某个花哨的单体方案划算得多。

2.2 关键链路:抽取、描述、聚合、推理

claude-video把视频理解拆成了四个阶段,这也是它SKILL.md里定义的主流程:

第一阶段是抽取。用ffmpeg按时间间隔或者场景切换点抽帧,同时抽取音频轨道。这个阶段的核心指标是“帧数别太多也别太少”,太多烧钱,太少丢信息。实际操作中,我一般按每条视频5到8分钟的体量,抽12到20帧做全局概览,再根据场景切换检测补几帧关键帧。

第二阶段是描述。把每一帧图像交给视觉模型,生成结构化的图像描述,比如“画面左侧是主讲人站在深蓝色背景前,右侧大屏显示一条上升曲线,标题为'季度营收增长'”,再配合OCR把屏幕上的关键文字抠出来。

第三阶段是聚合。把所有帧的描述、OCR文字、音频转写文本,按时间顺序拼接成一个带时间戳的“视频文字剧本”。这一步的关键是去重和合并:连续几帧画面类似的,只保留最有代表性的一条;语音和画面内容重复的,要避免重复计入。

第四阶段是推理。把聚合后的文本剧本交给主Agent模型,由它根据用户的需求生成摘要、回答提问或提炼结论。到了这一步,Agent做的事情其实和读一篇长文章没区别了。

这四个阶段里,前三个阶段是claude-video自己干的活,第四个阶段是把它交给Agent完成。整个Skill的代码量和复杂度都不高,核心工作量全在参数调优和异常处理上。

2.3 设计取舍:通用性优先还是深度优先

做这类Skill时一定会面临一个选择:是做通用型,能应付任何视频;还是做深度型,把某个场景做到极致。claude-video选的是通用优先,理由很务实——Skill的第一目标是让更多Agent直接可用,而不是服务某一个垂直场景。

通用优先的代价是,在某些特定场景下效果不够锐利。比如你做的是电商直播分析,需要细粒度识别商品摆放、口播卖点、弹幕互动,通用Skill就有点力不从心。这时候正确的做法是以claude-video为基础,在它的框架上叠加特定场景的规则,比如增加一帧里检测特定LOGO、或者针对直播场景优化OCR区域。

我的建议是:新手或者通用需求的团队直接采用它的通用设计,别一上来就想着定制。先把主流程跑通,把成本和效果摸清了,再基于前期的日志数据决定要不要加垂直逻辑。上来就深度定制,很容易陷入“每个视频都是特例”的泥潭。

3. 核心细节解析:每个环节的实操要点

3.1 抽帧策略:均匀抽帧、场景切换检测与关键帧

抽帧是整个流程的地基,抽帧抽得不好,后面所有环节都是空中楼阁。目前常用的抽帧策略有三种,各有适用场景。

第一种是均匀抽帧,就是每隔固定秒数抽一帧。比如视频长度300秒,想抽15帧,那就每20秒抽一帧。优点是实现简单、时间覆盖均匀,缺点是容易错过转瞬即逝的关键画面,比如一闪而过的价格页。

第二种是场景切换检测,用ffmpeg的select过滤器配合scene阈值,检测画面发生明显变化的位置,在这些位置抽帧。这样能保证“每次画面变了都抓到”,特别适合剪辑频繁的视频,比如宣传片、Vlog。

第三种是均匀抽帧+关键帧补充,也是我实际项目里最常用的组合。先均匀抽一遍保证全局覆盖,再用场景检测抽出来的帧和均匀抽的帧做去重合并。这样既不会漏掉重要转场,也不会让模型看到一堆几乎一模一样的连续画面。

抽帧密度怎么定?我总结了两个经验值:常规讲解类视频,每分钟2到3帧足够;画面信息密度高的视频,比如UI操作录屏、PPT讲解,每分钟可以加到4到6帧。超过这个密度,Token消耗翻倍,但理解效果的增量很小,边际收益严重递减。

3.2 图像描述:让视觉模型输出结构化信息

抽出来的帧要变成Agent能用的信息,中间要过视觉模型这一关。这里有个非常容易犯的错:直接让模型“描述这张图片”,得到的是散文式的泛泛而谈,没有结构,Agent后面根本没法做定向问答。

正确做法是在调用视觉模型时给一个严格的输出模板,强制它按JSON或者固定字段输出。比如每帧输出四个字段:画面主体、画面背景、屏幕文字(OCR结果)、动作事件。再给一个置信度或者重要性标记。这样处理之后,每帧的描述就是一个紧凑的结构化对象,聚合阶段拼接起来非常干净。

如果你的视觉模型支持原生OCR,优先用OCR能力提取屏幕文字,不要只靠视觉描述里的“转述”。转述会丢细节,也会引入幻觉——模型可能把屏幕上的数字读错。OCR虽然也可能错,但至少是可校验的,配合一个简单的数字校正规则(比如单位、百分比合理区间校验)效果会好很多。

另外,关于图像大小:抽出来的帧动辄1920x1080甚至4K,直接喂视觉模型不仅慢,而且浪费。我习惯先压缩到宽度1280或1024,保持宽高比,再转成JPEG。信息量损失有限,但请求速度和解析成本都能降一大截。

3.3 音频与字幕:兼顾非视觉信息

画面只是视频的一半信息,另一半在音频里。主讲人的口播内容、背景音里的关键信息、访谈对话,都需要语音转写才能拿到。如果是带字幕的视频,直接抽取字幕轨是最省钱的方案;没有字幕的话,就得用语音识别模型。

语音识别这块有两个选择:本地跑Whisper,或者用云端API。本地Whisper的好处是免费、数据不出内网,缺点是对硬件有要求,长视频转写慢;云端API快,但要花钱,也有隐私顾虑。我的建议是:内部工具用本地Whisper的base或small模型,批量处理、不着急出结果;对延迟敏感的生产环境再用云端接口。

有一个容易忽略的细节:语音识别的结果一定要带时间戳。因为之后你要把它和画面描述合并成时间线,逐句对应“这句话是第几分钟说的、当时屏幕上是什么”。不带时间戳的纯文本转写,等于把视频变成了广播剧,画面信息就丢了。

3.4 时间轴对齐与事件聚合

两路信息到手之后,核心难点是时间轴对齐。画面描述可能有“第3分钟出现了价格表”的时间标记,语音转写可能有“在第3分12秒提到价格”的字幕时间。但两者是独立产生的,直接拼在一起会出现错位。

实际做法是把时间轴切成粒度一致的分片,比如每30秒一个块。把落入同一个块的画面描述和语音文本归并到一起,生成一个块级别的摘要。这样每一块就是一个“场景单元”,包含了这段时间内发生了什么、说了什么。所有块按时间顺序排下来,就是一份完整的视频结构化文档。

聚合时还有两个细节:一是去重,连续多个块画面内容相同,可以合并,避免Agent反复看“同一张脸对着同一块PPT”;二是优先级,当画面信息和语音信息冲突时(比如语音在讲A,画面上是B),默认以语音为主,因为口播通常更能代表创作者的意图,画面可能是装饰性的。

4. 从零实现一个可用的claude-video Skill

4.1 Skill目录与SKILL.md的规范写法

先看Skill的标准目录结构。一个可发布的claude-video Skill,推荐这么组织:

claude-video/
├── SKILL.md
├── scripts/
│   ├── extract_frames.py
│   ├── transcribe_audio.py
│   └── build_timeline.py
├── assets/
│   ├── frame_templates/
│   └── prompt_templates/
└── requirements.txt

SKILL.md是灵魂文件,它的作用不是给程序员看,而是给Agent看的。Agent通过读它来决定“什么时候调用、怎么调用、步骤是什么”。所以SKILL.md的写法要直接、分步骤、明确。

# claude-video Skill

## 用途
当用户提供视频文件路径或视频链接,并希望基于视频内容进行总结、问答、要点提取时,使用本Skill。

## 步骤
1. 检查输入:确认视频文件存在,获取视频长度和分辨率。
2. 抽帧:调用 scripts/extract_frames.py,默认每20秒抽一帧,并做场景检测补充。
3. 音频转写:调用 scripts/transcribe_audio.py,输出带时间戳的文本。
4. 构建时间线:调用 scripts/build_timeline.py,合并画面与文本,生成结构化报告。
5. 基于报告回答用户问题。

## 注意事项
- 视频长度超过1小时时,先告知用户处理时间会较长。
- 所有中间文件存放在临时目录,处理结束后清理。

这里有个容易被忽略的点:SKILL.md里写的“注意事项”,Agent真的会读。你想让它规避什么坑,就白纸黑字写在里面,这比在代码外层做一堆防御性判断更有效。因为模型是意图导向的,你告诉它“长视频要提前告知”,它在长视频场景下就会真的去执行这个动作。

4.2 抽帧脚本与参数计算

抽帧脚本是核心中的核心,我用的是ffmpeg + Python的组合。ffmpeg负责抽帧,Python负责参数计算和调度。下面这个脚本片段可以直接抄作业:

import subprocess
import json

def get_video_info(path):
    """读取视频时长和分辨率"""
    cmd = ["ffprobe", "-v", "quiet", "-print_format", "json",
           "-show_format", "-show_streams", path]
    result = subprocess.run(cmd, capture_output=True, text=True)
    data = json.loads(result.stdout)
    duration = float(data["format"]["duration"])
    for stream in data["streams"]:
        if stream["codec_type"] == "video":
            width = stream["width"]
            height = stream["height"]
            return duration, width, height
    return duration, 0, 0

def extract_frames(path, output_dir, interval=20):
    """按固定间隔抽帧"""
    duration, width, height = get_video_info(path)
    # 根据时长动态调整间隔,保证帧数不过多
    if duration > 3600:
        interval = 60
    elif duration > 1800:
        interval = 45
    elif duration > 600:
        interval = 30
    cmd = [
        "ffmpeg", "-i", path,
        "-vf", f"fps=1/{interval},scale=1280:-2",
        "-q:v", "2",
        f"{output_dir}/frame_%04d.jpg"
    ]
    subprocess.run(cmd, check=True)
    return len(os.listdir(output_dir)) - 1

这个脚本里的动态间隔值得说两句:视频越长,间隔越大,这是基于总帧数约束的反推。按1280宽度压缩后,单张JPEG大约150到300KB,视觉模型单帧处理消耗也固定。如果1小时视频按每20秒一帧抽,就是180帧,处理成本太高。所以我在脚本里做了个阶梯式调整:10分钟内20秒一帧,10到30分钟30秒一帧,30到60分钟45秒一帧,超过1小时60秒一帧。这样长视频也能控制在60到80帧以内。

4.3 描述、转写与时间线构建的配合

抽完帧之后,进入描述和转写环节。视觉描述我封装了一个函数,强制输出结构化JSON:

def describe_frame(frame_path, client):
    prompt = (
        "请分析这张视频截图,只输出JSON格式,包含以下字段:\n"
        "{\"subject\": \"画面主体\", \"scene\": \"背景描述\", "
        "\"ocr\": \"屏幕上可见的文字\", \"event\": \"正在发生的动作或事件\"}\n"
        "如果某个字段没有内容,填null。不要输出JSON以外的任何内容。"
    )
    with open(frame_path, "rb") as img:
        response = client.messages.create(
            model="claude-3-5-sonnet-20241022",
            max_tokens=500,
            messages=[{
                "role": "user",
                "content": [
                    {"type": "image", "source": {"type": "base64", "data": img.read()}},
                    {"type": "text", "text": prompt}
                ]
            }]
        )
    return json.loads(response.content[0].text)

音频转写我用本地Whisper,输出带时间戳的段落:

import whisper

model = whisper.load_model("base")
result = model.transcribe(audio_path, word_timestamps=True)
segments = []
for seg in result["segments"]:
    segments.append({
        "start": seg["start"],
        "end": seg["end"],
        "text": seg["text"].strip()
    })

最后用build_timeline.py把两路结果合并成块。我的实现是按30秒一个时间段切分,遍历所有帧描述和语音段落,按时间落块。每个块最终输出成下面这种格式:

[00:00-00:30]
画面:主讲人开场,白板上写着“2025战略”
语音:“大家好,今天我们来谈谈明年的重点方向”
OCR:2025战略、增长、目标

所有块拼成一份markdown文档,就是Agent最后要看的那份“视频结构化报告”。到这一步,claude-video的核心闭环就已经走通了。

4.4 集成到Agent中的调用流程

Skill做好之后,怎么让Agent真正用起来?这取决于你用的Agent框架。如果你用的是Claude Code,直接把claude-video文件夹放进skills目录即可;如果是自己搭的Agent,则要在系统提示词里声明可用技能列表,并在工具调用层挂载对应脚本的执行入口。

我的习惯是在Agent的系统提示词里加这样一段说明:

可用技能:
- claude-video:输入视频路径或链接,输出视频内容的结构化报告。
当用户请求涉及视频内容理解时,必须先调用claude-video,基于报告回答,禁止编造画面内容。

这段提示词的最后一句话非常重要:“禁止编造画面内容”。实测下来,加上这句话之后,Agent在视频信息不足时会更诚实地回答“报告中未提到”,而不是强行脑补。这是个用词上的小技巧,但对输出质量的提升是肉眼可见的。

5. 真实使用中的常见问题与排查技巧实录

5.1 上下文爆炸:帧数、Token与成本控制

最常踩的坑就是Token消耗失控。第一次跑通的时候,我拿一段25分钟的教程视频做测试,抽了75帧,每帧描述平均输出200个Token,光图像描述就有15000 Token,再加上语音转写和最终报告,一次任务下来消耗差不多5万Token。如果每天都处理几十个视频,这个成本还是有点肉疼的。

排查思路很简单:给Skill加上“预算意识”。在SKILL.md和脚本里都做帧数上限控制,比如单任务默认不超过40帧,超长视频强制降低抽帧频率。描述的max_tokens也从500降到300,保证关键信息不丢的前提下,压缩输出长度。另外,对画面内容高度重复的帧,可以在描述前先做一次粗略的感知哈希(pHash)比对,相似的帧直接跳过,这个优化能把帧数再砍掉30%左右。

还有一个小技巧:把图像描述环节的模型换成更便宜的型号,比如用Claude Haiku做逐帧描述,只把最终推理交给最强的模型。逐帧描述本身是机械性的活,便宜模型完全够用,没必要每次都上旗舰模型。

5.2 画面模糊、字幕抖动导致OCR识别不准

录屏类视频和手机拍摄的视频,常见问题是画面糊、字幕抖动、屏幕反光。OCR在这种输入下错误率会明显上升,尤其容易把数字读错,比如把“1.2亿”读成“1.3亿”。这在商业场景下是很严重的错误。

我的处理方案是双通道校验:OCR结果和语音转写结果做交叉比对。如果语音里提到“一亿两千万”,而OCR结果是“1.3亿”,就以语音为准,并且标记为“疑似OCR错误”。在最终报告里,把这类矛盾点单独列一个“信息冲突提醒”区块,让Agent在回答时提示用户“该数字存在画面与语音不一致的情况”。与其硬着头皮给一个可能错误的数值,不如把冲突暴露出来,这也是一个负责任的内容理解工具该有的态度。

5.3 长视频处理超时与中断

做长视频处理时,最头疼的是任务跑到一半超时。ffmpeg抽帧本身就慢,语音转写更慢,一个多小时的长视频光转写就要好几分钟,接口超时是常事。

解决思路是把流程拆成可断点续跑的模式。每阶段的结果都落盘保存:抽帧结果存为图片文件,转写结果存为JSON,时间线构建结果存为markdown。下次再跑同一个视频时,先检查中间产物是否存在,存在就直接跳过对应阶段。这样即使某一阶段挂了,重新执行也只是从断点继续,不会从头再来。另外,转写阶段可以采用分片并行:把音频切成60秒的小段,多线程同时转写,最后按时间顺序合并。实测下来,这段优化能把长视频转写时间从“不可用”拉到“勉强可用”。

5.4 依赖与环境的坑

最后说几个环境层面的坑。一是ffmpeg版本问题:老版本对某些视频编码格式支持不好,遇到“Video codec not supported”之类的报错,先升级ffmpeg,不要急着改参数。二是Python虚拟环境:Whisper依赖的torch版本和你的其他项目很可能冲突,建议用独立的虚拟环境装,别图省事直接装全局。三是临时目录权限:Agent运行环境如果是容器化的,临时目录可能只读,输出目录要提前确认可写,否则会在最不起眼的地方挂掉,而且报错很隐晦。

6. 我的一些体会与后续可玩的方向

6.1 踩坑之后的几点心得

我把这套Skill在几个真实项目里跑了两个月,最大的体会是:视频理解这个事,工程细节比模型能力更影响效果。模型选得再好,抽帧策略不对,该漏的信息照样漏;提示词写得再好,帧图压得太大,请求照样超时。整个链路里每一个环节都是木桶的一块板,短板决定了最终效果的天花板。

另一个体会是:一定要给Agent“承认不知道”的余地。视频漏了关键信息是常态,强行让Agent补全它没看到的东西,只会产出幻觉。所以我在SKILL.md里专门加了一条规则:“如果结构化报告中没有覆盖用户问到的内容,明确告知用户该信息未在视频中检测到,并建议检查原视频对应时间段。”这条规则让输出的可信度高了一个档次,用户反馈明显更信任Agent给的结果。

最后是关于成本的心态。有些人一看要消耗这么多Token就打退堂鼓,我的建议是先别急着优化钱,先把效果跑出来,确认这条路走得通,再回头做抽帧密度优化和模型降级。顺序反了,很容易在“省钱”上花掉远超省下的钱的时间。

6.2 可以继续扩展的方向

以claude-video为底座,往深了做还有很多方向。比如加上“区域关注”机制,只对画面特定区域做OCR和描述,适合处理监控视频、体育赛事这种场景;再比如加上“事件时间线导出”功能,把视频里的关键事件按时间顺序导出成CSV或者日历格式,方便做内容运营排期;还有“批量视频总结”,给一个视频目录,自动生成每一条的摘要卡片,这个对内容库管理非常实用。

如果对多模态理解有更深的需求,还可以把抽帧结果喂给专门做的视频理解微调模型,做更细粒度的动作识别。这条路的技术门槛高一些,但有了claude-video打底的数据管线,积累训练数据反而成了顺手的事。Skill这个东西,最大的价值不在于某一个脚本,而在于它把一套可以复用的流程固化了下来,让后续的每次扩展都不用从零开始。

Logo

邀请您加入社区

更多推荐