前阵子有朋友问我:我的 Agent 现在能聊天、能写代码、能搜网页,但一遇到“帮我把这个培训视频里讲的内容整理成提纲”就束手无策。原因很简单,LLM 本身不擅长直接啃视频文件,更别说动辄几百兆的 MP4 和带各种排版特效的 PPT。后来我索性自己动手,做了一个专门干这件事的 Agent Skill:把视频和 PPT 的内容提取做成一个标准化技能,Agent 调用一次,就能拿到结构化文本,再拿去总结、问答、检索都行。这篇文章就是我整个从 0 到 1 的开发记录,外加一份能直接照着用的使用指南。
这个 Skill 解决的核心问题就一句话:把 Agent 接不住的非结构化文件,变成它能消费的结构化内容。视频走“音频转写 + 关键帧 OCR”双通道,PPT 走“结构解析 + 渲染兜底”双模式,最终输出统一的 Markdown 文本和 JSON 结构。适合三类人看:想给自家 Agent 加文件处理能力的开发者、在做内部知识库和培训资料整理的团队、以及对 Agent Skill 机制感兴趣但不知道从哪下手的学习者。
1. 为什么做这个 Skill:需求拆解与整体设计思路
1.1 Agent 缺的不是对话能力,而是“能动手”的能力
这两年 Agent 的形态越来越成熟,但大多数卡在同一个地方:能说不能做。所谓“做”,指的是对真实世界里的文件、数据、工具进行操作。视频和 PPT 是办公场景里信息密度最高、但也是最难被 LLM 直接消费的两种格式。想象一下,一份 2 小时的培训录像,如果直接告诉 Agent“帮我总结重点”,它根本无从下手——它读不了视频帧,听不到音频流,也没有办法像人一样快进、暂停、截图。
所以 Agent Skill 这个机制本质上就是给 Agent 配“手”和“眼睛”。我的思路很直接:与其让 Agent 去硬解视频,不如把视频转成它最擅长处理的文本。视频转文本、PPT 转文本,这两件事本身是成熟技术,难点在于怎么把它们封装成可复用、可组合、输出稳定的能力模块。这就像一个专业的资料员先把原始素材整理成索引卡片,再交给分析师去写报告,效率和质量都会高很多。
1.2 选定视频与 PPT 这两个切入点的原因
我刻意选了视频和 PPT 一起做而不是只做一个,是因为它们恰好覆盖了两种典型的信息提取路径,技术上又高度互补。
视频内容提取的核心是“多模态转写”:音频转文字负责捕捉“说了什么”,关键帧 OCR 负责捕捉“展示了什么”。举例来说,一个产品发布会的录像,主讲人的语音描述往往不完整,关键信息都在背后的 PPT 大屏上。如果漏掉 OCR 通道,提取出来的内容就会缺一大块。
PPT 内容提取的核心则是“结构还原”:一份 PPT 本身就是半结构化的内容容器,有标题、正文、表格、备注、图表,如果只是粗暴地把所有文字混在一起输出,那等于把一本好端端的书撕成碎片扔给 Agent。必须尽可能地保留页面层级、标题层级、表格结构、备注信息,才能让后续的总结和问答有意义。
更关键的是,这两个模块在技术上可以共用一套设计模式:先做格式解析,再做内容抽取,最后做结构化输出。视频里有“转写块”,PPT 里有“页面块”,无非是给每个文本块打个类型标签和位置元数据。
1.3 整体架构:三条流水线 + 一个统一出口
我最终的设计是三段式流水线:输入适配层 → 提取处理层 → 结构化输出层。
输入适配层负责解决“文件从哪来”的问题,支持本地路径、HTTP 直链、二进制流三种方式,这样不管 Agent 是从用户对话里拿到文件路径,还是从网盘下载临时文件,都能接住。
提取处理层是核心,两个提取器独立开发、独立测试,内部可以各搞各的,但对外暴露统一接口。提取结果用标准 JSON 结构承载,核心字段包括:类型(transcript 或 slide_text)、来源位置(时间戳或页码)、文本内容、置信度、附加元数据(如说话人、图表标签等)。
这样一个 Agent 无论调视频提取还是调 PPT 提取,拿到的都是同一套结构,后续无论是直接喂给 LLM 做总结、存入向量库做检索,还是转成 Markdown 展示给用户,都不用再写适配代码。
2. 技术选型与核心原理:怎么选、为什么这么选
2.1 视频提取链路:音频转写 + 关键帧 OCR 双通道
视频处理的第一个决定是“要不要先抽音频”。答案是必须。一个常规 720P 视频的音频流码率大约在 128kbps,用一个本地转写模型处理一小时音频大约只要几分钟到十几分钟;但如果你试图用视觉模型逐帧理解视频画面,开销会高一个数量级,而且大量画面是无效信息。
所以我把视频提取分成两条并行通道。通道 A 是音频转写,用开源语音转写模型把视频中的语音内容转成带时间戳的文本;通道 B 是关键帧 OCR,从视频里挑出那些画面信息量大的帧(比如出现标题、图表、幻灯片的时刻)做文字识别。两条通道的结果最后在时间轴上做对齐合并,输出一段连续的视频内容文本。
选型上有几个考量。音频转写模型我优先选支持时间戳输出的方案,因为时间戳是视频文本索引的灵魂,没有它,后续做“第几分钟讲了什么”这类原生命令就无从谈起。关键帧抽取不能简单按固定间隔抽帧,因为固定的间隔会漏掉关键画面,我是用了场景切换检测算法来抽取,只有当画面发生明显变化时才保留这一帧,这样效率和质量都能兼顾。
2.2 PPT 提取链路:结构解析优先,渲染 OCR 兜底
PPT 提取的第一原则是:能读结构就不要靠猜。PPT 文件的底层是 XML,里面每个文本块、每个形状、每个表格都有明确的位置和层级信息。直接解析 XML 有几个无可替代的好处:速度快(一个几百页的 PPT 解析只需要秒级)、文本准确率高(不会出现 OCR 识别错字)、结构信息完整(能明确知道这段文字是标题、正文还是备注)。
但也有解析不到的场景。很多商务 PPT 会把一页内容直接做成一张整图,这种“图片型 PPT”在 XML 里根本没有可提取的文字,必须把页面渲染成图片再做 OCR。所以我的设计是双模式:先用解析器扫一遍,能提取的直接提取,遇到图片型页面或者混合型页面,自动降级到“渲染 + OCR”模式。
这里要注意一个顺序问题:不能一开始就无脑渲染所有页面做 OCR。渲染十页的 PPT 可能只要几秒,渲染一个几百页的就要好几分钟,而且 OCR 再准也会有识别误差。先快后慢、先结构化后兜底,这是纯工程经验。
2.3 为什么最终选了这套组合而非“全交给大模型”
有人可能会问:现在多模态大模型不是能直接看图、看视频了吗?为什么不干脆全交给它?我的切身体会是:对于高频、批量的内容提取场景,专用管线远比直接调用大模型更合适。
直接调多模态大模型的优势是理解力强,能看懂图表背后的含义;劣势也很明显:一是长视频受上下文窗口限制,不可能一口气处理完;二是成本高,一个长视频如果要逐帧分析,费用是普通文本处理的几十倍;三是输出不稳定,大模型有幻觉,会把没讲过的内容“脑补”进提取结果里,这在资料归档场景是不能接受的。
所以我的定位很明确:专用管线负责“忠实提取”,大模型负责“理解加工”。提取模块只做一件事,就是把视频和 PPT 里的内容准确、完整、结构化地挖出来,既不添油加醋也不偷工减料;至于总结重点、提炼观点、回答提问这些创造性工作,才交给后面的大模型。这个分工既稳定又省钱,是整套方案的核心思想。
3. 从零开始的开发实录:Skill 的完整诞生过程
3.1 第一步:定义 Skill 的接口契约
任何 Skill 开发的第一步,都是想清楚输入输出长什么样。因为 Agent 调用 Skill 的方式本质上就是一个函数调用,如果函数签名不清晰,Agent 根本不知道什么时候该调用、参数该传什么。
我最初设计的输入参数是这类结构:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| file_path | string | 是 | 本地文件路径或 HTTP 直链 |
| file_type | string | 是 | video 或 ppt,二选一 |
| output_format | string | 否 | 输出格式,支持 markdown 和 json,默认 markdown |
| language | string | 否 | 提示转写和 OCR 的目标语言,默认自动检测 |
| need_timestamp | bool | 否 | 视频模式是否输出时间戳,默认 true |
这里有一个小经验:file_type 字段其实可以由 Agent 根据文件扩展名自动推断,但后来我发现扩展名是不可靠的。有些文件明明是 PPT 但扩展名是 .pptx 的压缩包改成了 .zip,有些视频是 .flv 后缀。所以我保留了这个参数,并且在实际调用时优先看文件头魔数来判断真实格式,扩展名只做参考。
输出的结构我也做了严格约定。所有提取结果分成元信息和内容块列表两部分,内容块里固定携带 type、position、content 三个核心字段。type 标记文本块来源,position 在视频里是时间戳、在 PPT 里是页码,content 是提取出来的原始文本。这样下游拿到之后可以灵活处理。接口契约稳定了,后面的开发才有章可循。
3.2 第二步:视频提取模块开发实录
视频提取模块的代码结构我拆成了三个文件:audio_extractor负责音频抽取、frame_extractor负责关键帧抽取、video_processor负责编排和输出。这里我用到一个关键的外部工具,负责音频抽取和视频解码。
音频抽取的命令非常简单,但要注意几个参数陷阱。我在实测中遇到过输出文件大小为 0 的问题,排查下来发现是输入视频的音频流编码格式比较特殊,需要在命令里显式指定音频编码器。建议命令写成这样:
ffmpeg -i input.mp4 -vn -acodec pcm_s16le -ar 16000 -ac 1 output.wav参数解释:-vn表示不要视频流,-acodec pcm_s16le强制把音频转成 16-bit PCM 格式,-ar 16000把采样率统一到 16kHz,-ac 1转成单声道。这个格式是大多数语音转写模型的标准输入格式,直接在源头做音频标准化,可以避免后面模型报错。
关键帧抽取我最初用均匀抽帧,比如每 2 秒抽一帧,结果发现一个 1 小时的视频抽出了 1800 张图,绝大多数是无效的,OCR 处理这些图既慢又费资源。后来我改用场景切换得分:先把视频按时间戳切成小段,对每一段的画面做直方图差异计算,只有差异超过阈值的那一帧才保留。这样一小时视频最终通常只抽出来几十到一百多帧,而且每一帧都“有信息量”。
语音转写环节要考虑模型部署方式。我有两种选择:如果有 GPU 机器,直接用本地模型跑;如果只是普通服务器,就调云端 API。实测下来,本地模型用large-v3档位处理一小时音频大约需要 5-10 分钟(取决于显存),用medium档位只要一半时间但准确率略有下降。我最终的策略是提供配置项,让使用者根据自己的算力情况选择档位,默认用medium平衡速度和精度。
3.3 第三步:PPT 提取模块开发实录
PPT 提取模块我用的是 Python 生态里的两个库:一个专门读写 PPT 文件,另一个负责处理 XML 结构。我的处理流程分三步:打开文件、遍历所有幻灯片、逐个页面提取文本块。
核心代码可以浓缩成这样一个流程片段:
from pptx import Presentation from pptx.enum.shapes import MSO_SHAPE_TYPE def extract_ppt_text(file_path): prs = Presentation(file_path) result = [] for page_idx, slide in enumerate(prs.slides, start=1): page_texts = [] for shape in slide.shapes: if shape.has_text_frame: for para in shape.text_frame.paragraphs: text = "".join(run.text for run in para.runs).strip() if text: page_texts.append(text) elif shape.shape_type == MSO_SHAPE_TYPE.TABLE: table = shape.table for row in table.rows: row_text = [cell.text.strip() for cell in row.cells] page_texts.append("| " + " | ".join(row_text) + " |") result.append({ "position": page_idx, "type": "slide_text", "content": "\n".join(page_texts) }) return result这里面有个经验:直接遍历shape.text_frame是效率最高的方式,但你会漏掉嵌套在组合形状里的文本。有些 PPT 会把多个文本块包在一个“组合形状”里,外层遍历拿不到内部文本。解决办法是写一个递归遍历函数,遇到组合形状就进入内部继续找。表格式内容要特判转成 Markdown 表格格式,这样 Agent 后续才能理解表格的行列结构。
图片型 PPT 的兜底方案是渲染。我在服务器上用命令行把 PPT 转成 PDF,再用 PDF 渲染库把每一页变成图片,最后用 OCR 识别。转换命令有一个坑:转换出来的 PDF 文字版式中文字体可能会乱,出现中文方块字的情况。我在实践中发现,必须在服务器上安装对应的中文字体才能保证渲染效果正常,这一点在部署文档里一定要写清楚。
3.4 第四步:视频和 PPT 结果统一封装
两个模块都开发完之后,最重要的一步是封装。我在顶层写了一个summarizer编排器,它根据输入文件的类型自动选择对应的提取器,并统一做文本后处理和格式输出。
后处理环节主要有四件事:清洗噪声文本(比如视频里反复出现的“请点赞关注”这类片头片尾循环)、合并碎片文本(PPT 里同一个文本框被拆成多个段落的要合回一句完整的话)、补充结构化标记(给标题文本加#级标题标记)、生成最终输出(Markdown 和 JSON 两种格式)。
这里我想强调一个容易忽略的细节:清洗噪声文本不能简单用关键词黑名单。视频转写结果里常见的噪声有背景音乐干扰导致的乱码、口头禅重复、以及语音模型对专业术语的误识别。我最终的方案是提供一套可配置的清洗规则,同时保留“原始文本”和“清洗文本”两个字段,这样 Agent 需要较真细节时可以查原始内容,需要精炼输入时用清洗文本。
3.5 Skill 接入 Agent 的方式
模块开发完成只是第一步,接入 Agent 框架才是让它生效的关键。我用的是标准的工具描述方式,向 Agent 声明这个技能的存在,声明方式是一段结构化描述文本。这里有一件很关键的事:工具描述写得越具体,Agent 就越容易在正确的时候调用它。
我的描述大致是这种风格:
技能名称:content_extractor 功能描述:从视频或 PPT 文件中提取结构化文本内容。当用户提到视频、录像、会议记录、PPT、课件、演示文稿等关键词,或需要总结、整理、搜索上述类型文件内容时,调用此技能。 输入要求:需要传入文件路径、文件类型。 输出说明:返回带位置信息的文本块列表,可直接用于总结、问答和检索。
接入好之后要做一个冒烟测试。我的测试用例通常包括:一个 30 分钟的培训视频、一个包含图片型页面的 PPT、一个纯文本型 PPT、一个损坏的 PPT 文件。测试的目的是确认 Agent 能正确识别调用时机、能正确传递参数、能正确处理异常输出。
4. 使用指南:安装、配置、调参与效果优化
4.1 环境准备与依赖安装
这个 Skill 的核心依赖在 Python 生态里可以一站式装齐。建议用 Python 3.10 以上版本,避免老版本的一些类型注解兼容问题。
核心依赖清单我整理成了一张表:
| 依赖 | 用途 | 安装方式 |
|---|---|---|
| python-pptx | 解析 PPT 文件的 XML 结构 | pip install python-pptx |
| opencv-python | 视频关键帧抽取与图像处理 | pip install opencv-python |
| 语音转写模型 | 音频转文字 | 按模型官方文档安装 |
| OCR 组件 | 图像中文字识别 | pip install 对应 OCR 库 |
| ffmpeg | 视频音频抽取与格式转换 | 需单独安装二进制文件 |
安装完成之后,记得要下载语音转写模型的权重文件和 OCR 的语言模型文件,这两个是离线运行的基础。我自己第一次部署时忘了下载中文 OCR 语言包,结果提取英文 PPT 没问题,一提中文就变成一堆乱码,排查了半天才想起来是语言包缺失。
4.2 接入项目的两种方式
接入方式取决于你的使用场景。如果只是自己本地调试,我建议用最简单的直接导入方式,在 Python 脚本里初始化一个 extractor 客户端,然后调用方法。适合快速验证效果和跑测试。
如果是给团队或者线上服务用,我建议封装成 HTTP 服务。我用 FastAPI 包了一层接口,支持文件上传和返回结构化 JSON。这样其他语言写的服务也能调用这个能力,前端也可以直接上传文件然后拿到提取结果。
4.3 核心参数调整与效果优化
参数调整是这个 Skill 使用体验的分水岭,我用一个表格把最常用的参数和它们的实际效果整理出来:
| 参数 | 默认值 | 调整建议 |
|---|---|---|
| 音频转写模型档位 | medium | 显存足够时切 large,转写准确率提升明显,尤其对带口音的语音 |
| 关键帧抽取阈值 | 0.3 | 视频画面切换频繁时调高到 0.5,减少无效帧;画面静止多时调低到 0.2 |
| OCR 置信度阈值 | 0.6 | 识别结果乱码多时调高到 0.8,宁可漏掉也不要错误文本 |
| PPT 渲染兜底开关 | 自动 | 图片型 PPT 占比高的场景,建议强制开启渲染兜底 |
| 输出格式 | markdown | 需要做结构化处理时改用 json,程序消费更方便 |
我实测过一个典型场景:一份 40 页的混合型 PPT,纯 XML 解析只提取到约 60% 的文本内容,剩余 40% 在图片里;开启渲染 OCR 之后,覆盖率提到了 95% 以上,但处理时间从 2 秒涨到了 40 秒。这个取舍要看场景:如果是全文检索,用 95% 覆盖率的模式;如果只是做摘要问答,60% 其实也够用,还更快更准。
5. 常见问题与排查技巧实录
5.1 视频提取结果为空或乱码
这个问题出现频率最高,但原因往往集中在两个地方。一个是音频抽取环节出错,常见的是原始视频是静音录制或者音频轨道有版权保护。这种情况先检查抽出来的 wav 文件大小,如果只有几 KB,基本可以断定原视频没有有效的音频轨道。另一个是语音转写模型的语言参数没设对,中文视频用了默认的英文模型,结果当然是满屏乱码。
我的排查顺序是:先验证音频文件是否正常生成,再验证转写模型是否加载了正确的语言包,最后才看后处理清洗规则是不是误伤了内容。按这个顺序排查,五分钟内能定位九成的问题。
5.2 视频处理速度慢到让人怀疑人生
我自己第一次跑 2 小时视频的时候也等得崩溃,后来做了三件事显著提速。第一是把音频转写模型的量化等级从全精度切到半精度,速度提升近一倍,准确率几乎无损;第二是分批处理,把输入音频切分后再转写,配合多线程并发,总耗时能降到单线程的三分之一;第三是对纯语音类视频做去重判断,识别到长时间静音段就自动跳过,省掉无效计算。
这些优化之后,1 小时视频在我本地一台普通 GPU 机器上的总处理时间从 25 分钟降到了 7 分钟左右。如果你连 GPU 都没有,只能跑 CPU,那就老老实实切成small档位,虽然准确率差点,但不至于等一晚上。
5.3 PPT 提取结果缺少表格和图表内容
只做 XML 结构解析时,这个问题基本无解,因为图表信息大多存成图片或复杂向量图形。我的处理思路是兜底检测:当发现当前页面有“图片型内容占比极高”的特征时,自动切换到“渲染本页 + OCR”模式。实现的时候注意,不要整份 PPT 从头到尾都走渲染 OCR,只挑有问题的页面单独处理,这样整体速度损失最小。
图表部分还有一个进阶玩法:OCR 识别到的图表文字通常是零散的坐标标签,没有语义连带关系。我在后处理里增加了一个规则,把同一张图里的文本按相对位置重组成描述性段落,比如“横轴标签:第一季度、第二季度,纵轴标签:销售额,图例:产品A、产品B”,这样 Agent 拿到之后才能理解图表的含义。
5.4 问题排查速查表
| 现象 | 可能原因 | 解决动作 |
|---|---|---|
| 视频提取结果全空 | 音频轨道不存在 | 检查 wav 文件大小 |
| 文本乱码 | 转写模型语言设置错 | 检查语言参数和语言包 |
| 处理速度慢 | 转写模型档位过高 | 切换 small 档位或开量化 |
| PPT 提取漏内容 | 页面是图片型内容 | 开启渲染 OCR 兜底 |
| 输出结构混乱 | 后处理阶段未合并碎片 | 检查合并逻辑和清洗规则 |
最后分享一个我踩过几次坑之后学到的体会:做 Agent Skill,最核心的部分往往不是提取逻辑本身,而是想清楚输入输出的契约和异常恢复策略。我第一版只考虑了“顺利路径”,结果一遇到大文件、坏文件、格式怪异的文件就崩,后来才补上超时控制、重试逻辑和降级策略。建议你开发任何 Skill 之前,先列一列可能出现的异常情况,设计好兜底方案,这会帮你省去大量后期排障的时间。从实际使用来评价,这个视频与 PPT 提取 Skill 已经在我的多个自动化流程里稳定跑了一个多月,它也证明了:Agent 的能力边界往往不是模型决定,而是工具链和工程化水平决定的。