聊一个最近折腾了很久的方向:给Agent装上一双“眼睛”。我一直在做视频内容的自动化处理,从短视频理解、会议纪要到课程内容聚合,都卡在同一个问题上——Agent读不了视频。文本好办,丢进上下文窗口就行;视频完全不是一回事,它涉及抽帧、音频转写、时间轴对齐、视觉模型推理,任何一个环节断掉,Agent就像睁眼瞎。后来我接触到了claude-video这类Skill,简单说,它是一套让Agent具备视频理解能力的标准化技能包,把“视频输入→结构化信息输出”整条链路封装成Agent可以自主调用的工具。这篇文章把我从零搭建、反复踩坑到调优落地的完整过程记录下来,想搞Agent技能开发、视频理解管线的朋友可以直接参考。

1. Skill到底是什么东西

1.1 先理解Agent Skill这个新物种

在聊claude-video之前,得先搞清楚“Skill”在Agent体系里到底扮演什么角色。很多刚开始做Agent开发的人有个习惯:把所有能力描述都塞进系统提示词里,规则越写越长,最后模型经常前后矛盾,指令稍微复杂一点就乱套。Skill的思路完全不同,它把一类功能拆成两个部分:一个人类可读、Agent可解析的说明文件,再加上一堆真正干活的脚本和配置。Agent接到任务时,先读取Skill的说明,判断这个技能适不适合当前任务,适合就按里面的步骤调用脚本执行,整个过程是动态的、按需触发的。

我打个比方,系统提示词相当于给员工发的一本厚厚的员工手册,什么都写了但什么都记不住;Skill则像是给员工配了一个工具箱,每件工具外面贴着使用说明书,员工看到任务后自己去选工具、看说明、动手做。这个设计的核心优势在于:能力不需要常驻在上下文里,用到才加载,既省token又降低模型的认知负担。

更关键的是,Skill是可复用的。你写好的视频理解Skill,可以在不同的Agent项目里直接引用,也可以在团队内部分享。现在社区里已经有不少现成的Skill仓库,包含论文检索、数学建模、语言学习等各种方向。这些技能包的格式大同小异,核心都是“SKILL.md说明文件+可执行脚本”,理解了这一套,拿到别人写的Skill也能很快看懂、改造。

1.2 为什么视频理解必须做成Skill而不是普通代码

视频理解这个任务,天生就适合用Skill封装。你想想它和普通文本处理差多远:文本处理基本就是把输入丢给大模型,一次调用搞定;视频理解则是一条完整的数据管线,要先从视频文件里抽帧,要提取音频并转成文字,要把画面信息、语音信息按时间戳对齐,最后还要组织成模型能高效理解的结构化格式。这条链路上的工具也多而杂,抽帧常用ffmpeg,转写常用Whisper,OCR要单独跑,视觉理解要调用多模态模型。这些工具如果每次都写死在业务代码里,整个项目会非常臃肿,换个场景就废了。

Skill的封装粒度刚好卡在合适的中间层。Agent负责拆解任务意图,判断用户是想要视频摘要、关键事件提取还是逐句转写;Skill负责把这些意图落成具体动作,调度各个脚本完成耗时耗力的脏活累活。用户对Agent说“帮我把这个培训视频总结成十条要点”,Agent读完SKILL.md,知道该调用抽帧脚本,知道该把关键帧发给视觉模型,最后把结果拼装成一份结构化报告返回。

还有一个实际痛点:视频处理经常要调外部模型、跑本地脚本,如果这些逻辑全塞在Agent的主流程里,出错时非常难排查。Skill把复杂度隔离在独立模块里,脚本单独测试、单独调优,Agent只关心“调用了哪个技能、拿到什么结果”,出现异常也只需要替换对应脚本,不影响整体的Agent逻辑。这种模块化的设计理念,做工程的人都懂,只是套上Agent的外壳后,很多人反而忽略了它。

2. claude-video的核心设计思路

2.1 第一版方案:无脑抽帧喂视觉模型,直接翻车

我一开始做视频理解的时候,思路特别简单粗暴:按固定间隔从视频里抽帧,比如每秒抽一帧,然后把这几百张图全部丢给多模态模型,让它生成总结。听起来很合理对吧?实际上翻车翻得很彻底。

第一个问题是token爆炸。一个十分钟的视频,每秒一帧就是600帧,多模态模型按图计费,每张图都要消耗大量的上下文容量和真金白银。我跑过一次测试,一个三分钟的产品演示视频,抽了180帧,单次调用的视觉token消耗大得惊人,成本比人工看视频还高。第二个问题是模型根本抓不住重点。均匀抽帧意味着大量重复画面,一个人对着镜头讲三分钟,前中后半段画面几乎一样,模型收到一堆相似的图,反而被干扰,总结出来的内容逻辑混乱,甚至把同一句话重复强调好几遍。第三个问题是时序信息彻底丢失,模型分不清事件发生的先后顺序,视频里“先故障后修复”的因果关系,在输出里完全看不出来。

这个版本让我意识到,视频理解的核心不是“多喂图”,而是“喂对图”。平均抽帧只是简单地切时间轴,完全无视了画面内容的变化。真正靠谱的做法,是要让视频理解的链路模拟人类的观看方式:眼睛追着画面内容走,内容变化大的地方停下来细看,内容重复的地方快速跳过。

2.2 正确姿势:视觉流、音频流、文本流三路分离再合并

想通这一点之后,我把整个管线重新设计了一遍。核心思路是三路信息流平行处理,最后按时间轴合并成一个结构化结果。

第一路是视觉流。用场景检测算法找出视频中画面发生显著变化的时刻,在那些时间点提取关键帧。比如镜头切换、画面跳转、人物入场退场,这些都是值得“停下来细看”的地方。第二路是音频流。把视频的音轨抽出来,用语音转写模型转成带时间戳的文本,这是整个链路里信息密度最高的一路,因为大多数视频的核心内容都在人说的话里。第三路是文本流,包括视频自带字幕和画面中的文字信息,字幕文件如果有就直接拿来用,没有就用OCR识别关键帧上的文字,比如PPT内容、屏幕截图、标题字幕。

三路信息分别处理完之后,再按时间戳对齐合并。某个时间点的关键帧里有什么画面,同时段说了什么话,字幕写了什么字,拼在一起就是一条完整的事件记录。Agent拿到这些事件记录后,再用大模型做摘要、提炼要点、梳理逻辑关系。这个“先并行处理、后交叉合并”的架构,既保证了信息不遗漏,又控制了单次喂给模型的量,成本和准确性都得到了很好的平衡。

2.3 抽帧策略的参数细节

抽帧是整个管线里最容易被低估的环节。参数选得好不好,直接影响后续视觉理解的准确性和资源消耗。我经过大量测试,总结了一套比较可靠的配置,分享出来供参考。

场景检测我用的是ffmpeg的select滤镜,配合scene阈值来判断画面变化程度。阈值是一个0到1的值,我处理不同类型的视频时会调整:讲课类视频,画面相对固定,阈值调高到0.4左右,只在幻灯片切换或人物有大动作时才抽帧,全程基本稳定;快节奏的商业宣传片、游戏录制,画面变化频繁密集,阈值要降到0.2甚至更低,否则容易漏掉关键转折点。

除了场景检测,还有一个保险策略:设置最小时长间隔,防止在快速连续切换的视频里抽出一大堆无效帧。我通常限制最短间隔为0.5秒,最长间隔为15秒。也就是说,即使画面长时间不变,最多15秒也要抽一帧兜底,避免整个视频完全没有视觉信息的片段。这个策略在长视频处理中特别重要,它保证了信息的连续性,又不至于让重复画面淹没关键内容。

经过这么处理后,一个10分钟的视频最终只留下50到120张关键帧,比之前的600帧少了大约80%。信息量没怎么丢,但token消耗和成本直线下降,模型理解准确率反而因为干扰少了而明显提升。

3. 实操:从零构建一个视频理解Skill

3.1 Skill目录结构与前置依赖

理论讲完,直接上手。我们先看一个标准的claude-video Skill目录长什么样:

claude-video/
├── SKILL.md
├── config.yaml
├── scripts/
│   ├── extract_frames.py
│   ├── transcribe_audio.py
│   ├── ocr_frames.py
│   └── build_report.py
└── requirements.txt

每个文件各司其职。SKILL.md是整个技能的入口文档,Agent先读它来判断何时使用这个技能;config.yaml存放抽帧阈值、模型参数、时间戳格式等配置;四个脚本分别做关键帧提取、音频转写、画面OCR和最终报告组装;requirements.txt记录Python依赖。

环境方面,核心依赖就三样:ffmpeg用于音视频解复用和抽帧,openai-whisper用于语音转写,以及一个多模态视觉模型的客户端SDK。ffmpeg需要提前装好并加入系统PATH,其他依赖写进requirements.txt即可。

3.2 SKILL.md的关键写法

SKILL.md写得好不好,直接决定Agent调用的准确率。我的经验是,这份文档要回答三个问题:这个技能是什么、什么场景用、怎么调用。

---
name: claude-video
description: 处理视频文件,提取关键帧、转写语音、识别文字,生成结构化视频内容报告
---

## 使用条件
- 用户提供视频文件或视频链接
- 任务涉及视频内容理解、摘要、要点提取、内容检索

## 输入格式
- 视频路径或URL
- 可选参数:输出语言、摘要长度、是否包含时间戳

## 执行步骤
1. 调用 extract_frames.py 提取关键帧
2. 调用 transcribe_audio.py 转写音频
3. 如有屏幕文字,调用 ocr_frames.py
4. 调用 build_report.py 生成最终报告

## 输出格式
返回结构化的时间轴事件列表和摘要文本

这里有个容易被忽视的技巧:description字段一定要写清楚“使用条件”,Agent是根据这个描述来做语义匹配的。描述越具体,Agent误用的概率越低。我还习惯在SKILL.md末尾加一个“使用示例”区段,给出一段完整的输入输出样例。实测下来,加了示例之后Agent的调用准确率提升非常明显,因为模型能从中推断出调用模式。

3.3 核心脚本实现细节

关键帧提取脚本,核心是调用ffmpeg的场景检测。我封装了一个Python函数:

import subprocess
import json

def extract_frames(video_path, output_dir, scene_threshold=0.3,
                   min_interval=0.5, max_interval=15):
    # 第一遍:场景检测,找出画面变化时间点
    probe_cmd = [
        "ffmpeg", "-i", video_path,
        "-filter:v", f"select='gt(scene,{scene_threshold})'",
        "-showinfo", "-f", "null", "-"
    ]
    result = subprocess.run(probe_cmd, capture_output=True, text=True)

    # 解析ffmpeg输出的pts_time,得到场景切换时间点
    scene_times = []
    for line in result.stderr.splitlines():
        if "pts_time:" in line:
            time_str = line.split("pts_time:")[1].split()[0]
            scene_times.append(float(time_str))

    # 第二遍:按时间点抽帧,同时处理最短/最长间隔
    # 具体实现:遍历scene_times,按min_interval去重,
    # 并补充max_interval兜底帧

转写脚本用的是Whisper,这里要特别注意时间戳的精度。Whisper默认返回句子级别的时间戳,做视频对齐完全够用:

import whisper

def transcribe(video_path, output_path):
    model = whisper.load_model("base")  # 根据精度需求选型号
    result = model.transcribe(video_path, word_timestamps=False)
    segments = []
    for seg in result["segments"]:
        segments.append({
            "start": seg["start"],
            "end": seg["end"],
            "text": seg["text"].strip()
        })
    with open(output_path, "w", encoding="utf-8") as f:
        json.dump(segments, f, ensure_ascii=False, indent=2)
    return segments

Whisper的模型分tiny、base、small、medium、large几个档位,实测下来中文视频至少要用small,base的识别正确率在专业术语和口音面前很吃力。如果视频里有大量英文或中英混合内容,建议直接用medium或者带指定语言的参数。

3.4 让Agent真正“看懂”画面:视觉推理提示词模板

抽帧和转写只是把原料准备好了,真正让Agent“看懂视频”的,是喂给多模态模型的关键帧提示词。这块我踩过不少坑,最开始直接问“描述这张图片”,模型输出天马行空,后来总结出一套好用的模板:

以下是一段视频中的一个关键帧,该帧出现在视频的 {start_time} 到 {end_time} 秒之间。
请以事实描述为主,不要推测画面外的内容。
需要输出:
1. 画面内容:画面中的主体、场景、人物动作
2. 屏幕文字:画面中的标题、字幕、代码、图表文字(没有就写无)
3. 事件判断:画面中正在发生什么事件
4. 重要性:你认为这帧画面在整段视频中的重要程度(高/中/低)

加上时间戳和“事实描述”约束之后,模型回答的可用性一下子提高了很多。关键在于明确告诉模型“你看的是一个视频中的某一帧,而不是一张孤立的图片”,模型会因此倾向于描述事件性内容,而不是纠结于构图、光线这些无关细节。另外,重要性标注字段非常有用,后续生成摘要时,可以按重要性给不同帧分配权重,把“高”重要性的画面内容优先纳入总结。

4. 常见问题与排查实录

整个开发过程不是一帆风顺的,我把实际遇到频率最高的问题整理成一份速查表,按照问题现象、根本原因、解决办法来对照排查。

常见问题 根本原因 解决办法
长时间视频处理时内存爆掉 抽帧脚本一次性把所有帧加载进内存 改为逐帧处理,边抽边存;配合生成器逐批送入模型
转写文本和画面内容对不上 抽帧时间点与Whisper时间戳不是同一时间基准 统一使用视频内部的pts时间戳,避免用系统当前时间;抽帧后立即记录时间点
视觉模型输出明显错误的画面描述 提示词缺约束,模型过度推测 强制“只描述画面可见内容”,禁止推断画面外信息
连续讲话的长镜头只抽到一两帧 场景检测认为画面没变化,忽略了内容变化 增加最长间隔兜底帧,超过设定秒数强制抽帧
OCR识别PPT上的中文文字错别字多 中文字体密集、分辨率低 抽帧时放大该区域,或调整关键帧的分辨率后再OCR
反复调用导致调用费用超预算 没有缓存机制,相同视频重复处理 为视频生成内容哈希,处理结果落盘缓存,二次请求直接读缓存
Agent拒绝调用Skill SKILL.md中的使用条件描述不清晰 重写description,补充更具体的触发场景和关键词

4.1 时间戳不同步这个坑,值得单独说

这是所有问题里最隐蔽的一个。有一次我处理一个直播回放视频,发现转写文字说的是“下面我们看第三页”,但抽帧抽到的画面还是第二页,整个报告内容错位严重。排查了很久,最后发现是脚本里分别用了两套时间基准——一个用的是视频内部的时间戳,另一个用的是处理脚本的系统运行时间,两套时间在视频需要转码、等待模型响应时就会出现漂移。

解法很简单但很隐蔽:抽帧脚本在处理完每一帧后立即把对应的视频时间点写进文件名或者数据库,而不是在处理完毕后再统一回填。这样即使中间有延迟,出来的人工时间线也不会和数据基准拆散。

4.2 成本失控的应对策略

视频理解的成本大头在视觉模型调用上。关键帧越多越烧钱。我后来加了一个“预筛”机制:所有关键帧先用一个轻量的小模型做快速分类,只保留画面内容变化明显、有文字信息、或者包含人物动作的帧,其他重复度高的直接丢弃。预筛阶段用小模型,费用极低;通过预筛的帧再送进大模型做精细理解,费用花在刀刃上。

另外缓存策略也是省钱利器。我给每个视频文件算一个SHA-256值,处理前先查缓存表,处理完就把结果存起来。同一个视频第二次请求直接秒回,既不重复烧模型费用,又能大幅降低用户等待时间。在批处理场景里,这个缓存命中率非常高,实测一个月下来能省掉将近一半的API费用。

5. 从“能看”到“看得懂”:还能怎么玩

视频理解Skill搭好以后,我发现它真正的价值不只是“看视频”,而是变成了一个底座能力,可以往上叠各种玩法。

我把三个方向的实际项目验证结果列一下。第一个是视频知识库,把一批培训视频全部跑一遍Skill,得到结构化的时间轴事件和摘要文本,然后用向量数据库存起来,接入RAG流程,用户以后可以用自然语言提问“去年七月那个故障复盘会上提到的根因是什么”,系统能直接定位到对应视频的具体时间段并给出回答。这个方向做完,相当于把非结构化的视频资料变成了可检索的结构化资产。

第二个是自动化内容生产链条:拿一个原始视频作为输入,用Skill提取关键帧和转写稿,再用大模型生成图文笔记、宣传文案甚至二次创作的短视频脚本,整个过程不需要人工观看视频。我以前处理一个30分钟的发布会视频,手动整理要点至少要两小时,现在全流程自动化下来只需要十几分钟,质量和人工整理的差距不大。

第三个是Agent工作流的联动。Skill做成了标准模块之后,可以被主控Agent编排进更复杂的任务里。比如一个“学习助手Agent”,用户丢一个网课视频进来,Agent先用claude-video提炼章节要点,然后基于要点生成练习题目,再把用户的回答和视频原片段做对比点评,一套完整的“看-学-练-评”闭环就串起来了。这种组合能力,是单点工具很难做到的。

根据我个人实际操作中的体会,做这类Skill最有价值的地方反而不是那些花哨的模型调用,而是把底层管线做扎实。抽帧参数、时间戳对齐、缓存策略、提示词约束,每一个环节打磨到位,整个系统才谈得上稳定可靠。视频理解看起来是个很酷的方向,但真正落地时拼的都是这些基础功。最后再分享一个小技巧:Skill的SKILL.md里一定要留一个“使用示例”区段,把输入输出样例写清楚。我在多个Agent项目里对比过,有这个区段的Skill调用成功率能稳定提升一截,原因很简单——大模型从具体例子里学调用模式,比从抽象描述里推断要容易得多。如果你也在做Agent技能开发,强烈建议从这个细节开始优化起。

Logo

邀请您加入社区

更多推荐