前阵子有个做Agent的朋友跟我吐槽,说他的智能体什么都好,就是一遇到视频就傻了。喂一个视频文件进去,模型直接报错,转成纯文字又丢掉大量画面信息,等于是让一个带眼睛的人闭着眼干活。这不是个例,我自己做Agent项目也踩过同样的坑,后来干脆写了一个叫 claude-video 的 Skill,让Agent真正具备“看视频”的能力,而不是靠“猜”。

这篇文章想把整个设计思路、实现细节、踩坑记录都摊开来讲。内容不挑框架,不管是Claude、开源模型还是自己搭的Agent,只要走的是“多模态输入 + 工具调用”这套路线,这个Skill的思路都能直接搬过去用。适合正在搞Agent开发、想让Agent处理视频素材的人,尤其适合那些已经被视频文件折磨过、想找一套成熟方案的人。

1. 需求拆解:Agent看视频到底难在哪

1.1 视频不是“一张大图”,而是时间轴

很多刚接触多模态Agent的同学会有一个直觉:视频不就是连续的画面吗,模型能看图片,那让它直接看视频不就行了?

现实远没这么简单。视频是一连串带时间关系的帧,一个10分钟的视频,按30帧每秒算,就是18000张图片,同时还有一轨音频。你把原始视频直接喂给模型,第一个炸掉的是上下文窗口,第二个炸掉的是token成本,第三个炸掉的是模型自己——它在处理这种高密度时序数据时,根本没法保持稳定的“注意力”。

所以claude-video这个Skill的第一个设计原则就是:别让模型直接处理视频文件,而是把视频拆解成模型真正能理解的信息单元。

1.2 视觉信息和听觉信息要分开处理

视频里实际包含两条信息流:画面流和语音流。画面里可能有动作、物体、场景变化、字幕、人物表情;语音里有对白、旁白、环境音。如果只处理画面,你会丢掉“这个人说了什么”;如果只转录音频,你会丢掉“这个动作是怎么发生的”。

我最初犯的错就是把视频丢给通用转写工具,然后让Agent基于文本答题。结果遇到一个教学类视频,内容讲的是“如何在跑步机上保持正确姿势”,画面里明明有示范动作,但转写出来的只有教练的解说词,Agent回答得干巴巴的,完全没有参考姿势细节。

解决方案很朴素:把视频抽帧成一组带时间戳的图片,再把音频转录成带时间戳的文本,最后把这两路信息按时间轴合并成结构化的“视觉文字笔记”。Agent在看这份笔记时,就相当于一个既看过画面、又听过声音的人在回忆内容。

1.3 Skill的本质:把能力包装成语义化的工具

如果你用过现在主流的Agent框架,应该很清楚“Skill”是什么意思。本质上它就是一段带有明确输入输出约定的能力封装,让Agent在需要时主动调用,而不是把全部逻辑塞进系统提示词。

我设计claude-video时,一直在想一个问题:Agent自己知道什么时候该“看视频”吗?答案是:它不知道。你给它的系统提示词写得再详细,它也不清楚面前这个文件到底是该抽帧、该转写、还是该走OCR。

解决方法是把这段能力包装成一个带有“触发说明”的Skill,在Agent的能力清单里写清楚它的适用场景、输入参数、输出格式。这样Agent看见视频类请求,就会自动匹配到claude-video,而不是在那瞎猜处理方式。

2. 核心方案设计:从视频到“带时间戳的多模态笔记”

2.1 抽帧策略:不该平均抽,要有重点

视频抽帧看起来简单,用ffmpeg一行命令就能搞定,但抽出来什么帧、抽多少帧、按什么规则抽,直接决定后续分析的质量。

我最早用的是均匀抽帧,比如每隔2秒抽1帧。这种策略在拍得比较规整的短视频上表现还行,但一遇到长视频或者镜头切换频繁的片子,就会出问题。最典型的情况是:一个镜头明明持续了10秒,均匀抽帧可能在中间某个瞬间抽到完全无关的帧,关键动作反而没录进去。

现在我的方案是三段式抽帧:

  • 第一段:全局探测,每隔3到5秒抽一帧,用来快速把握视频整体结构。
  • 第二段:场景切分检测,用帧间差异判断镜头切换点,在每个切换点附近补抽关键帧。
  • 第三段:根据视频时长动态调整密度,超过30分钟的长视频,优先保证前两分钟、中间和结尾的采样覆盖,避免过度抽取导致上下文爆炸。

处理一个30分钟的视频,我会把抽帧控制在60到90张左右,既能覆盖主要内容,又不至于把Agent的上下文窗口塞爆。算下来,假设每张图经过视觉编码后占用一定token,60张图的token开销大约相当于输入几万字的文本,这是目前大多数上下文窗口能接受的数量级。

2.2 音频转录:别忽略说话人分离

音频转录这个环节,很多人会直接用一个ASR工具一把梭。但如果你要处理的视频里有多个人对话,或者有采访、讨论场景,单纯转写会把“谁说的”这个信息全丢掉。

claude-video在设计时引入了一个可选的说话人分离步骤。如果视频里只有一个音轨且没有明显多说话人场景,我可以省掉这步;一旦检测到多人对话,就对音频段做一次嵌入聚类,给不同说话人打上标签,转录结果里会带上类似“说话人A:……”的前缀。

这里我踩过一个印象很深的坑。有一次处理一个产品发布会视频,画面里是PPT和演讲者交替出现,单独看转录文本完全能get演讲者在讲什么,但Agent回答“PPT上显示的数据是什么”这种问题时直接卡壳。后来才发现,演讲者只是在念关键结论,具体数据全在PPT画面上。这个案例让我彻底确认了视觉和听觉信息必须并行处理,缺一不可。

2.3 结构化输出:让Agent能“跳着看”

处理完抽帧和转录,如果你只是把一堆图片路径和一大段文本扔给Agent,那等于把压力全甩给了模型。它还得分心去对齐帧和文本的对应关系,很容易出错。

我想到的办法是输出一份带时间戳的JSON结构,把画面、对话、场景变化按时间轴组织在一起。大致长这样:

{
  "video_meta": {
    "duration": 187.4,
    "resolution": "1920x1080",
    "fps": 30
  },
  "segments": [
    {
      "start": 0.0,
      "end": 12.5,
      "scene_type": "opening",
      "visual_notes": [
        {"frame_id": "frame_00012.jpg", "timestamp": 4.0, "description": "主持人站在舞台中央,背后屏幕显示大会主题"},
        {"frame_id": "frame_00026.jpg", "timestamp": 9.0, "description": "镜头切到观众席,有人在鼓掌"}
      ],
      "transcript": [
        {"speaker": "主持人", "text": "欢迎大家来到今天的发布会现场", "timestamp": 1.2}
      ]
    }
  ]
}

为什么非要用这种结构?因为Agent在回答问题时,可以基于时间轴“跳着看”。比如用户问“开场讲了什么”,Agent只需要看segments[0]的内容;问“第二个产品介绍在哪里”,它可以快速定位到对应片段。这比把整份视频笔记灌进上下文再让它自行检索要高效得多,也稳定得多。

3. Skill的落地实现:构建一个可复用的视频理解流水线

3.1 Skill的目录结构与文件职责

先说一下我在项目里的目录组织方式,大家可以直接照着搭:

claude-video/
├── SKILL.md              # Skill的核心说明文件
├── main.py               # 主流程入口
├── pipeline.py           # 视频处理流水线:抽帧、转写、合并
├── frame_reader.py       # 抽帧模块,封装ffmpeg调用
├── audio_transcriber.py  # 音频转录模块
├── scene_detector.py     # 场景切分检测逻辑
├── output_formatter.py   # 输出JSON格式化
├── config.yaml           # 可调节的参数配置
└── requirements.txt      # 依赖文件

SKILL.md是整个Skill的说明书,Agent通过它来判断这个能力适不适用于当前请求。我的SKILL.md里会写清楚几件事:这个Skill干什么用、什么时候触发、什么时候不该触发、输入要求、输出格式、有哪些参数。

很多人做Skill会忽略“什么时候不该触发”这一点。实际上这个非常关键。如果你不写,Agent可能在看一张普通图片时也去调claude-video,白白浪费大量token和延迟。我在SKILL.md里明确写了“仅适用于短视频(不超过2小时)”“当输入为单张静态图片时请勿调用”这两条约束,实测交叉调用率下降了不少。

3.2 主流程逻辑:Agent怎么驱动这段能力

我把主流程设计成一条清晰的流水线,每一步有独立的函数,方便Agent在任一步失败时精准重试。

核心代码逻辑如下:

def process_video(video_path: str, task: str, params: dict) -> dict:
    # 1. 解析视频元信息
    meta = probe_video(video_path)
    
    # 2. 抽帧,生成带时间戳的帧列表
    frames = extract_frames(
        video_path, 
        strategy=params.get("frame_strategy", "adaptive"),
        interval=params.get("frame_interval", 3.0)
    )
    
    # 3. 若有音轨,进行转录
    transcript = []
    if meta["has_audio"]:
        transcript = transcribe_audio(
            video_path,
            lang=params.get("language", "auto"),
            speaker_diarize=params.get("speaker_diarize", True)
        )
    
    # 4. 将帧描述、转录文本按时间轴合并
    notes = merge_frames_and_transcript(
        frames, transcript, task=task
    )
    
    # 5. 输出结构化笔记
    return build_output(meta, frames, transcript, notes)

注意第4步里有个参数叫 task ,这是我觉得这个Skill设计里比较重要的一个地方。Agent在调用时,会把用户的任务语义传进来,比如“总结视频内容”“找出某个物体的出现时间”“提取演讲者的主要观点”。不同的任务会让合并阶段关注不同的信息。

如果是“提取主要观点”,合并时重点保留转录文本里的逻辑连接词和结论句;如果是“找到某个物体出现的时间”,VLM描述帧时会刻意关注物体检测结果,并在描述里带上“画面中有红色跑车”这类信息。这样的任务定制化,能让Agent在有限的上下文里用到最精准的信息。

3.3 VLM描述帧:低成本的理解桥

帧本身是一张图片,但Agent看到图片的方式和人类不同。对于视觉语言模型,它可以直接看懂图片;但对于纯文本Agent,它只能靠“帧描述文本”来理解画面。

把帧转成文本描述这一步,我用了一个轻量级视觉模型来生成“画面标注”。比如一张会议室照片会被描述成:

第14秒:会议室内,白板上有三个要点,第一是用户增长,第二是收入预测,第三是风险控制;屏幕前站着一个演讲者,正在指向白板上的第二点。

这段描述代替原始图片进入Agent的上下文。好处很明显:token占用小、跨模型迁移方便(不要求Agent背后的模型带视觉能力)、检索和定位更直接。

但我建议不要盲信这一步的准确性。视觉模型生成描述时也会出错,尤其是细节密集的画面。所以claude-video在生成描述时会同时保留时间戳和描述文本,Agent如果对某个时间点存疑,还可以让Skill返工重抽那个时间段的帧,做二次验证。

3.4 参数配置:实用的默认值与调优方向

我在config.yaml里放了一些参数模板,给不同场景用:

fast_mode:
  frame_interval: 10.0
  resolution_scale: 0.5
  transcribe_language: auto
  max_frames: 30

balanced_mode:
  frame_interval: 3.0
  resolution_scale: 0.8
  transcribe_language: auto
  max_frames: 80

deep_mode:
  frame_interval: 1.0
  resolution_scale: 1.0
  transcribe_language: auto
  max_frames: 300

绝判断用哪个模式,我直接在SKILL.md里让Agent先看视频时长和用户需求。10分钟以内的短视频默认走balanced_mode;超过30分钟的长视频建议fast_mode;用户明确要求“逐帧分析”“精确提取”时,才用deep_mode。

分辨率缩放这点也值得说明。抽帧时把画面缩小到一半,能显著降低后续VLM序列化图片的token开销,同时对大多数物体识别和场景理解任务影响不大。除非用户要读视频里的小字(比如PPT上的表格数据),否则我基本都开0.5倍缩放。

4. 接入Agent与实测效果

4.1 两种接入方式:埋进系统提示词 vs 挂在工具层

我试过两种接入路径,各有优劣。

第一种是把claude-video当普通工具注册到Agent的工具列表里,所有涉及视频的请求都走这个工具。优点是调用可控、鉴权方便、失败重试逻辑清晰;劣势是Agent有时会误判“这个视频需要看”还是“这个视频只需要转个码”,调用前日志经常出现反复试探。

第二种是把这个Skill的能力预埋在系统提示词里,让Agent在对话早期就把视频处理流程跑起来,提取完信息后再进入正式问答。这种方式响应更快,Agent不会出现“先问用户要不要处理视频”这种蠢问题;但侵入性更强,改一次提示词要重新调试。

我目前的主力方案是把两者结合:工具层注册claude-video,系统提示词里补一句“当发现用户提交视频时,先调用claude-video获取视频笔记,再基于笔记回答”。这种组合已经很稳定了。

4.2 实测案例:处理一个5分钟的产品演示视频

拿一个真实案例来走一遍流程。输入是一个5分钟的产品演示视频,内容是某公司介绍自己的智能手表,包括外观展示、功能演示、价格公布三个部分。

Agent收到视频后,先调用claude-video,识别出时长300秒、有音轨。然后进入抽帧阶段,按balanced_mode每隔3秒抽一帧,总计100帧;场景切分检测发现三个明显镜头段:外观特写(0到90秒)、功能演示(90到240秒)、价格公布(240到300秒)。音频转录正常,识别出两个说话人,一个是旁白,一个是产品经理。

合并后的视频笔记,包含三个segments,每个segment都有画面描述、对话文本和说话人标记。用户问“手表有哪些表带颜色可选”,Agent直接定位到第一个segment的第30到45秒,通过画面描述里的“展示了黑色、银色、金色三款表带”加上旁白的对应内容,给出准确答案。

这个流程以前靠纯文本转写是无论如何做不到的。因为表带颜色这个信息很大概率只在画面里出现,旁白可能只说“多种配色可选”,连具体的颜色名字都不提。

4.3 成本与性能测算

一个无法回避的问题:这样处理一个视频,到底贵不贵?

以5分钟视频为例,balanced_mode抽100帧,其中只有约三分之一的帧被VLM详细描述,剩余帧做简略分类;音频转写大约会产生800到1200字的文本。整体token消耗,如果按常见的多模态模型计费来估算,大约在几万到十几万token区间,成本基本在几分钱到几毛钱之间,具体取决于模型单价。

如果你跑在开源模型上,成本几乎可以忽略,主要花的是GPU推理时间和显存占用。一个直观的量化是:用消费级显卡处理5分钟视频,抽帧约10秒,音频转写约20秒,VLM描述帧约1到2分钟,总处理时间一般在3分钟以内。这个数据在我的实测中比较稳定。

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

5.1 抽帧抽出一堆黑屏,画面分析完全失效

这个问题我在处理带淡入淡出效果的视频,或者片头片尾有黑场素材时遇到过无数次。原因很好理解,视频里确实存在大量无内容的暗帧,VLM分析它们只会浪费token。

解法是在抽帧后加一个亮度过滤:计算每帧的平均亮度,低于阈值的帧直接标记为“过渡帧”,不进VLM描述列表。同时,场景切分检测也应忽略亮度突变的瞬间,避免把黑场误判成“新场景”。

5.2 转录文本与画面时间戳对不上

音频转录回来虽然带了时间戳,但音视频的起始偏移如果没校准,会出现文本开头和画面开头错位的情况。尤其在处理从录制软件或剪辑软件导出的视频时,有些文件音轨前会有一段静音,导致转录文本整体向后偏移。

我的做法是在pipeline开始时先做一次音画同步检测,比对第一段有效音频能量和第一帧画面的时间关系,得到一个偏移量,后续所有时间戳都加上这个修正。这个逻辑看着简单,但能把时间戳误差从秒级压到毫秒级。

5.3 上下文窗口被撑爆,Agent开始“失忆”

这是所有人都绕不开的问题。视频笔记再精简,一个30分钟的视频转出来的内容也有大几百行。如果用户连续问十个问题,上下文重复塞入这些内容,迟早爆掉。

我的思路是给claude-video加一个“检索优先”的逻辑:当用户提问时,不是把整份视频笔记扔给Agent,而是在笔记里做一个粗粒度检索,提取跟问题最相关的2到3个segments,只把这几段内容放进上下文。

实测下来,这种方法把有效准确率提升了不少,还顺带解决了长对话中“模型越到后面回答越敷衍”的老毛病。

5.4 安全与规范使用提醒

最后必须提一点:视频理解能力的边界。Agent能看视频,意味着它能处理带有个人信息、版权内容的视频素材。我在SKILL.md里明确写了一条:仅处理用户确认有权分析的视频,且所有抽帧、转录结果默认不持久化存储,处理完即清理。这个不光是道德要求,也是对用户数据负责的基础操作。

合规方面也提醒大家,尤其是涉及公开视频素材或他人创作的场景,尽量让Agent在回答中标注“该信息来自视频内容分析”,避免被误当作独立事实来源。

写在最后

我自己的体会是,给Agent加视频能力,并不是要让它像人类一样“观影”,而是让它能用结构化的方式理解一段连续时间的视觉和听觉信息。claude-video的核心理念就是两句话:视频不可直接喂给文本模型,所以拆成抽帧加转录;拆出来的碎片必须按时间轴组织,才能让Agent在需要时精确取用。

这套方案不算复杂,但它让我的Agent在面对视频类需求时,终于不再是“瞎子”了。如果你也在做Agent开发,试着把视频拆解成“带时间戳的多模态笔记”,你会打开很多此前以为做不到的使用场景。

Logo

邀请您加入社区

更多推荐