基于 Agno 的视频分类实战:用 Gemini 原生视频输入与结构化输出完成视频打标
【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno
导读
视频分类(Video Classification)是数据标注流水线中的一项基础原语:给整段视频片段(clip)打一个标签,模型看完整段视频后输出一个全局结论,相当于把图像分类的时间维折叠进来。本文基于 agno 仓库cookbook/data_labeling/_13_video_classification/目录中的完整示例,讲解如何用 Agno Agent + Google Gemini 实现视频的原生输入、闭集标签分类与置信度输出,并深入源码说明Video媒体对象与 Gemini 视频接入的底层原理。读完本文,你将能独立搭建一个可运行、可扩展的视频内容分类 Agent。
理解视频分类这一标注原语
视频分类要解决的核心问题,是为一段视频输出一个片段级别的标签(clip-level label)。这与图像分类是同一个原始任务,区别在于模型需要"看完"整个片段——包括连续帧、镜头切换与时间维度上的内容演变——再给出一个覆盖整段视频的单一结论。
从 cookbook/data_labeling/_13_video_classification/README.md 的说明看,这一原语适用于以下典型场景:
- 内容审核(Content moderation):对用户上传的短视频片段进行门禁式过滤,先判定类别再决定是否放行;
- 素材预打标(Pre-tagging):按场景类型预先为素材库中的视频添加标签,便于后续检索与推荐;
- 安防分流(Routing):根据事件类别对摄像头片段进行路由归类。
如果业务需要的是带时间戳的类型化事件/场景提取(例如"第 3 秒到第 8 秒出现人物动作"),则应转向 cookbook/data_labeling/_14_video_extraction/README.md(视频提取),两者是互补关系:分类回答"这段视频是什么",提取回答"这段视频里发生了什么、发生在什么时候"。
运行环境与启动命令
两个示例脚本都依赖 Gemini 模型对视频的原生理解能力,因此需要准备:
- 环境变量
GOOGLE_API_KEY(Gemini API 密钥); - 安装 agno 及依赖(脚本中用到
agno、httpx、pydantic、rich等库); - 示例视频通过公网 URL 实时下载,无需本地准备素材。
在仓库根目录下直接运行:
python cookbook/data_labeling/_13_video_classification/basic.py python cookbook/data_labeling/_13_video_classification/with_confidence.py运行时脚本会从https://agno-public.s3.amazonaws.com/demo/sample_seaview.mp4拉取视频字节,交给 Agent 分类,并通过rich.pretty.pprint打印 URL 与结构化分类结果。
⚠️ 示例素材命名提示:README 特别说明
sample_seaview.mp4是个命名误导——这段视频实际是一段短小的实验室场景(科学家通过显微镜观察样本),并非海景。因此期望的输出标签更可能是indoor或people,而不是nature。这一点在调试结果时非常重要,避免因"期望值与实际不符"而误判模型能力。
示例一:单标签分类(basic.py)
basic.py 演示了最基础、最通用的视频分类流程,全流程仅分三步:定义输出 Schema → 创建 Agent → 传入视频运行。
第一步:用 Pydantic 定义闭集标签 Schema
from typing import Literal from agno.agent import Agent, RunOutput from agno.media import Video from pydantic import BaseModel, Field from rich.pretty import pprint class Classification(BaseModel): scene_type: Literal[ "nature", "urban", "indoor", "people", "vehicle", "animal", "other", ] = Field(..., description="Dominant scene type in the clip")关键设计点:
- 闭集标签:
Literal[...]把输出约束在 7 个候选值内(nature/urban/indoor/people/vehicle/animal/other),这正是"分类"与"提取"的本质区别——模型只能从预定义的封闭集合中挑选一个; Field(..., description=...):字段描述会随 Schema 一起注入提示词,引导模型理解该字段语义("片段中的主导场景类型");output_schema:Agno Agent 的output_schema参数接受任意 PydanticBaseModel,运行时会强制模型按该结构返回结构化输出。
第二步:创建 Agent
agent = Agent( model="google:gemini-3.5-flash", instructions="You classify short video clips by dominant scene type.", output_schema=Classification, )三个参数各司其职:model指定 Google Gemini 系列模型(该 cookbook 的配套示例均使用google:gemini-3.5-flash,支持原生视频输入);instructions给出简短任务说明;output_schema绑定上述结构化输出模型。
第三步:下载视频并运行
if __name__ == "__main__": url = "https://agno-public.s3.amazonaws.com/demo/sample_seaview.mp4" video_bytes = httpx.get(url).content run: RunOutput = agent.run( "Classify this clip.", videos=[Video(content=video_bytes, format="mp4")], ) pprint({"url": url, "result": run.content})这里展示了 Agno 媒体输入的标准姿势:
- 用
httpx下载视频字节流; - 构造
Video(content=video_bytes, format="mp4")媒体对象; - 通过
agent.run(prompt, videos=[...])将视频与文本提示一起送入模型; - 从
RunOutput.content取出结构化分类结果(即Classification实例)。
示例二:带置信度的分类(with_confidence.py)
with_confidence.py 在单标签基础上增加了一个置信度维度,其工程动机在文件开头注释中写得很清楚:让下游消费者可以把低置信度片段转交人工审核或更强的模型处理。
扩展 Schema:增加 confidence 字段
class Classification(BaseModel): scene_type: Literal[ "nature", "urban", "indoor", "people", "vehicle", "animal", "other", ] = Field(..., description="Dominant scene type in the clip") confidence: Literal["high", "medium", "low"] = Field( ..., description="Confidence in the label" )confidence同样使用Literal["high", "medium", "low"]约束为三档离散值,便于下游做确定性路由(而非解析自由文本)。
用指令约束置信度语义
比基础版更精细的是 instructions 的写法,它把三档置信度的判定标准写得非常具体:
instructions = """\ Classify the clip and report a confidence: - high - the dominant scene is unambiguous across the clip - medium - the dominant scene is identifiable but some shots break the pattern - low - the clip mixes several scene types and you had to pick """这四条规则实际上定义了一个可操作的置信度判定协议:
- high:主导场景在整段视频中无歧义;
- medium:主导场景可识别,但部分镜头不符合该模式;
- low:视频混合了多种场景类型,模型不得不"硬选"一个。
这种"把评估标准写进 instructions"的做法,比让模型自行发挥可靠得多,也是本示例值得借鉴的实战模式。
运行
run: RunOutput = agent.run( "Classify this clip with confidence.", videos=[Video(content=video_bytes, format="mp4")], )仅提示词略有不同("Classify this clip with confidence."),其余流程与 basic 版完全一致。
源码纵览:Video 媒体对象的字段与校验
理解Video对象是掌握 Agno 多媒体输入的关键。其实现位于 libs/agno/agno/media/media.py,核心设计如下:
三种内容来源(且三选一):
| 字段 | 类型 | 说明 |
|---|---|---|
url | str \| None | 视频的远程 URL |
filepath | Path \| str \| None | 本地视频文件路径 |
content | bytes \| None | 原始视频字节(统一规范化为 bytes) |
validate_and_normalize_content校验器强制"恰好提供一个内容来源":全部为空或同时提供多个都会抛出ValueError。同时自动为对象生成id(uuid4)。
媒体元数据:format(如mp4/mov/avi/webm)、mime_type(如video/mp4)、duration(秒)、width/height(像素)、fps等字段用于描述视频本身。
内容读取:get_content_bytes()按content → url → media_reference → filepath的优先级返回字节;若携带了media_reference(媒体被卸载到对象存储时的引用),则通过传入的MediaStorage句柄解析真实字节。此外还提供get_url(),用于生成模型或浏览器可直接拉取的 URL。
源码纵览:Agent.run 如何接收视频
视频输入是Agent.run的一等参数。在 libs/agno/agno/agent/agent.py 中,run()的签名同时接收audio、images、videos、files四类媒体序列,videos的类型为Optional[Sequence[Video]],随后统一派发到_run.run_dispatch(...)执行。
在 Gemini 模型一侧(libs/agno/agno/models/google/gemini.py),消息中的videos会被逐个格式化后插入消息体:
- 若视频已上传为 Gemini File 对象(
content为GeminiFile),则使用Part.from_uri(uri, mime_type)引用远端文件; - 否则调用
_format_video_for_message:字节内容用Part.from_bytes(mime_type="video/mp4", data=...)直接内联;本地文件路径则先上传到 Gemini API 再引用。 - 值得注意的细节:Google 官方建议单视频场景下把文本提示放在视频之后,因此代码将视频 part 插入到消息 parts 的头部位置(
message_parts.insert(0, video_file))。
从这条调用链可以看出,Agno 对"远程 URL、本地文件、字节流"三种视频来源做了统一抽象,上层业务代码只需构造Video对象,底层自动完成上传与格式化。
与视频提取(_14_video_extraction)的边界划分
为方便决策,将两个相邻目录的能力边界对比如下:
| 维度 | _13_video_classification(本文) | _14_video_extraction |
|---|---|---|
| 输出粒度 | 片段级单一标签(闭集) | 类型化对象:事件、场景描述、带时间戳的动作 |
| 典型 Schema | scene_type: Literal[...] | 场景列表 /(action, start, end)结构化记录 |
| 典型场景 | 审核门禁、素材打标、安防路由 | 视频归档索引、长视频章节生成、(video, labels)训练集构建 |
| 是否需要时间信息 | 不需要 | 需要(action_timestamps.py输出秒级起止时间) |
规则可以概括为一句话:只需要"这段视频是什么"就选分类;需要"里面发生了什么、何时发生"就选提取。
工程实践要点
结合示例与源码,总结几条可直接复用的实践建议:
- 用
Literal强制闭集:分类任务的标签必须是有限集合,Literal让非法输出在 Schema 层面就无法产生,配合output_schema做到"结构即约束"; - 把置信度判定标准写进 instructions:三档置信度的判定规则越明确,模型输出越稳定,下游路由(人工审核 / 升级模型)就越可靠;
- 利用
Field(description=...)传递字段语义:描述文本会参与提示词构建,帮助模型理解字段含义; - 视频来源灵活:远程 URL、本地路径、原始字节三种输入方式对应
url/filepath/content三个字段,cookbook 示例采用字节流方式(httpx下载),生产环境可改用文件路径或预先上传; - 警惕素材命名与内容的错位:
sample_seaview.mp4实际是实验室场景,跑通示例后应以"视频真实内容"而非文件名来校验输出。
延伸阅读
- 进阶示例:本目录的完整脚本见 cookbook/data_labeling/_13_video_classification/basic.py 与 with_confidence.py;
- 相关原语:需要时间戳级事件提取时,参考 cookbook/data_labeling/_14_video_extraction/README.md 及其三个示例脚本(
basic.py、scene_descriptions.py、action_timestamps.py); - 媒体对象实现:libs/agno/agno/media/media.py 中的
Video类与get_content_bytes/get_url; - 运行入口:libs/agno/agno/agent/agent.py 中
run()的videos参数与调度逻辑; - Gemini 视频接入:libs/agno/agno/models/google/gemini.py 中视频消息格式化与文件上传逻辑。
【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考