
做视频问答、视频摘要这类多模态任务时最容易低估的环节是抽帧。很多人以为只要把视频转成图片再交给多模态 LLM任务就算完成了一半。等结果不对时第一反应往往是换一个更强的模型或者反复改提示词。但真正的问题常常发生在更早的位置模型看到的那几帧是不是恰好捕捉到了视频里最关键的信息我最近整理“如何让 LLM 看视频”的相关经验时得到一个很直接的结论frame selection is the whole game帧选择就是整个游戏。这句话听起来有点绝对但它点破了一个被大量教程跳过的事实。多模态模型虽然叫“视频理解”实际处理时大多数情况并不是真的在连续流式地看视频而是接收有限数量的帧序列。给定同样的模型、同样的提示词不同的抽帧方式会产生完全不同的回答。你可以让模型读十段提示词都比不上给它一帧真正包含答案的画面。这篇文章不打算铺开讲所有视频理解技术我只想围绕一个核心问题展开当你需要 LLM 理解一段视频时到底应该选择哪些帧怎么选选完怎么组织以及选错时怎么排查。这个过程看起来是“预处理”实际上是整个任务的胜负手。1. 先把“让 LLM 看视频”翻译成一个具体的输入问题1.1 多模态模型不是真的在看视频首先要明确一个事实绝大多数多模态模型并不会直接吃原始视频文件。视频是一个连续的高帧率信号比如常见视频是 25 到 30 帧每秒一个 10 秒的视频就有 250 到 300 帧。如果每一帧都送进模型token 数量会迅速爆炸视觉特征计算量也不现实。所以工程上最常见的做法是先把视频解码成若干帧图像再把图像作为多模态模型的输入。听起来很直接但这带来一个关键转变模型看到的“视频”已经不再是视频而是一组离散的图片。它看不到帧与帧之间的运动轨迹看不到镜头切换时的动态过程也看不到被跳过的那些瞬间发生了什么。这就解释了为什么很多视频理解任务表现不好。不是模型不够聪明而是模型被“喂”的帧集合本身是残缺的。如果关键动作发生在两帧之间那模型根本没有机会看到它。你要求模型回答“这个人什么时候推倒杯子”但恰好推倒杯子的那一帧没有被抽到模型就只能靠前后帧去猜答案自然不可靠。1.2 帧选择决定模型能获得哪些信息从信息论角度看帧选择本质上是降采样。原始视频的信息量极大但模型能接收的信息量有限。你需要做的是在被选中的少量帧里保留对当前任务最重要的信息。一个 10 秒、30fps 的视频理论上包含 300 个瞬间。如果只选 3 帧相当于用 1% 的信息量来回答 100% 的问题。那这 3 帧应该怎么分布是均匀分布在 0s、5s、10s还是在第 3 秒和第 7 秒各多抽一帧这完全取决于任务。如果任务是“描述视频的整体场景”均匀采样可能就够了。如果任务是“数清视频里出现过几个人”可能需要场景切换时各抽一帧避免同一镜头下重复计数。如果任务是“判断视频里某个动作是否符合规范”那关键动作发生的瞬间必须被覆盖。所以帧选择从来不是一个“随便抽几张图”的步骤而是一个信息取舍的决策过程。它决定了模型的“视野”而视野决定了答案的上限。2. 三种主流的帧选择思路均匀采样、关键帧、语义筛选2.1 均匀采样最容易但也会漏掉关键动作均匀采样是很多教程最先教的方法每隔固定时间抽一帧。比如每 2 秒一帧、每 30 帧一帧或者直接指定抽帧总数。优点是简单、稳定、可预测也容易对比不同参数的效果。但它的问题也很明显它不了解视频内容。如果视频里最重要的信息恰好出现在第 4.5 秒而你的抽帧节奏是每 5 秒抽一帧那这个信息就只可能落在 0 秒或 5 秒的帧附近。如果动作持续时间极短甚至根本不会被任何一帧捕获。在工程实践中我一般会把均匀采样当作“基线方案”而不是最终方案。先用它快速跑通流程确认模型能够理解基本场景再根据效果决定是否需要换用更聪明的抽帧方式。它适合的场景包括监控视频的静态环境描述、风景镜头、PPT 讲解类视频的整体概括、会议录像的段落划分。2.2 场景切换和关键帧提取适合连续事件比均匀采样更进一步的做法是检测场景切换。当画面内容发生剧烈变化——镜头切换、人物进出、画面亮度跳变、字幕出现——就抽取该时刻的帧。这类方法通常使用帧间差异、直方图变化或者现成的场景检测库例如 PySceneDetect 这类工具。场景切换抽帧的优点是能用更少的帧覆盖更多不同场景非常适合镜头频繁切换的短视频、电影片段、新闻视频。它解决了均匀采样最大的痛点不会因为某个镜头持续了 10 秒就疯狂重复抽帧也不会因为某个镜头只有 0.5 秒就被完全漏掉。但需要注意一个概念混淆视频编码中的“关键帧”I 帧和内容理解中的“关键帧”不是一回事。I 帧是编码时为了压缩引入的完整图像帧它不代表语义上重要。如果你用 ffprobe 查看视频流里的关键帧列表得到的可能只是每 2 到 5 秒一个的编码锚点和内容重要性没有必然关系。所以做帧选择时不要直接依赖 I 帧列表需要额外做内容分析。场景切换也有盲区在一个连续长镜头里人物可能在做细微动作没有任何镜头切换但信息密度并不低。比如一个教学视频里老师在镜头前写板书画面没有切换但板书内容逐步变化。此时场景检测默认不抽帧容易漏掉关键信息。这种情况下均匀采样反而更稳。2.3 基于任务语义的筛选才是终局方案如果要追求更高的准确率就要让帧选择跟着任务走。思路是先抽一批候选帧再用一个辅助模型或规则打分选出和任务描述最相关的帧。举例来说任务要找到视频里“红色的车出现的时间”。先均匀抽帧得到 50 张候选图再让一个轻量级图像分类模型或 CLIP 类模型计算每张图和“红色汽车”的相似度最后挑出分数最高的几张送到 LLM。这样做的好处是最终输入给大模型的每一帧都离答案更近。这种“候选帧 语义筛选”的两段式结构在实际项目中非常实用。它不见得需要多么复杂的模型。如果你想判断视频中是否有人举起手可以先用人体关键点检测给出候选区间再抽取该区间附近的帧如果你想读取 PPT 上的文字可以用 OCR 先定位标题和正文再抽对应帧。不过要清楚语义筛选不是免费的。它多了一次模型推理增加了计算延迟。如果视频很短、场景简单均匀采样可能已经足够如果视频很长、答案依赖细节语义筛选的收益会非常明显。不同的视频理解任务需要不同的取舍。下表可以直观看出三种思路的差异方案特点适用场景主要风险均匀采样简单稳定时间覆盖均匀场景变化慢、时长较短关键动作容易落在帧间场景切换检测保留镜头变化减少重复帧多镜头视频、电影、新闻长镜头内的细节信息丢失语义筛选和任务描述对齐命中率高找物体、找动作、条件问答依赖额外模型成本高可能引入噪声3. 从视频文件到 LLM一整套可以落地的帧选择流程3.1 准备环境和依赖要开始实操至少需要这么几样东西视频解码工具最常见的是 FFmpeg。图像处理脚本一般用 Python OpenCV。多模态模型接口支持图片输入。如果需要场景检测或语义筛选安装对应库例如 PySceneDetect、transformers 等。建议先在一个干净的 Python 虚拟环境里验证脚本再搬到服务器或工作流里。如果只是学习和小规模实验默认安装通常够用如果要进入生产环境就需要锁依赖版本、输出目录、日志策略和异常处理。我一般会先用一个非常短的示例视频测试整条链路确认 FFmpeg 抽帧命令没有写错图片能正常生成模型接口能正常接收。不要一上来就批量处理几十个视频。3.2 第一遍先抽帧把视频变成候选图片集抽帧最常用的工具就是 FFmpeg。最简单的均匀采样命令类似这样# 每 2 秒抽一帧输出到 frames/ 目录 ffmpeg -i input.mp4 -vf fps1/2 -q:v 2 frames/out_%04d.jpg说明一下参数含义-vf fps1/2表示每 2 秒输出一帧-q:v 2是 JPEG 质量参数数值越小质量越高输出文件名里的%04d会被替换成四位序号。如果不想全视频抽帧可以用-ss指定开始时间-t指定时长。如果你需要更精确的控制可以用 OpenCV 写脚本import cv2 video_path input.mp4 cap cv2.VideoCapture(video_path) fps cap.get(cv2.CAP_PROP_FPS) total_frames int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) duration total_frames / fps # 每 2 秒抽一帧 interval int(fps * 2) frame_count 0 saved_count 0 while True: ret, frame cap.read() if not ret: break if frame_count % interval 0: out_path fframes/frame_{saved_count:04d}.jpg cv2.imwrite(out_path, frame) saved_count 1 frame_count 1 cap.release()这段脚本是常见的教学结构不是唯一写法。实际生产时建议用流式方式逐帧读取而不是一次性把整个视频读入内存。高清视频单帧分辨率很大长时间运行会占用不少资源。3.3 再按任务策略挑帧组装成模型输入第一步产生的候选帧可能还是太多。如果任务只需要 5 张图你就需要决定怎么从候选帧里挑出这 5 张。如果使用场景检测可以先检测出所有镜头边界再从每个镜头内选择一帧画面变化最平稳的帧。如果使用语义筛选可以用一个轻量模型给候选帧打分。这里要记住挑完帧之后最好把每帧的时间信息保留下来而不是只给模型一堆无标注的图片。一个常见的组装方式是把图片按时间顺序编号并在提示词里标注对应的时间戳。下面是一段视频中抽出的 5 帧分别位于 0s、2s、4s、6s、8s。 请根据这些帧回答视频里一共出现过几个人他们在做什么如果你使用的是 API 接口常见的做法是把图片转为 base64 字符串或者上传到临时存储后传 URL。具体格式取决于平台文档。建议先跑通一张图片再扩展到多张避免接口限制造成的困惑。4. 帧顺序、时间戳和上下文组织比想象中更影响结果4.1 模型经常分不清先后顺序时间戳要显式给很多人以为只要把帧按时间顺序传给模型模型自然知道先后。但实际测试中模型对多张图片的“顺序感”并没有想象中那么强。尤其当两帧画面内容相似时模型可能无法判断哪一帧在前哪一帧在后。更麻烦的是时间间隔。两帧相隔 0.1 秒代表一个“瞬间动作”两帧相隔 10 秒代表一个“过程变化”。如果模型不知道真实间隔它只能按顺序理解无法判断动作发生的快慢。所以在构造输入时我建议显式地提供时间戳信息。可以写在提示词里也可以把时间戳叠加到图片上。对于“这个事件是突然发生还是逐渐变化”这类问题时间戳是必要信息。4.2 多图输入和视频网格各有取舍输入多张独立图片和把所有帧拼成一张网格图是两种不同的常见组织方式。多图输入的优点是每张图保留原始分辨率细节不容易丢适合要看小物体、人脸、文字的场景。缺点是一张图会消耗大量视觉 token如果帧数较多可能超过单次请求的上限也会让推理变慢。视频网格则把多帧缩略图拼成一张 2x3 或 3x3 的图片整体作为一张图输入。优点是减少请求数量适合“全局摘要”类任务。缺点是每一帧的分辨率被压缩得很低细节信息容易被磨掉。我的选择标准是需要读文字、车牌号、人脸表情变化时优先用多图独立输入。只需要理解整体氛围、镜头顺序、场景分布时可以用视频网格。如果 API 限制一次只能传一张图也可以考虑网格但要提前验证分辨率是否足够。如果条件允许可以两种方式都试一次对比模型输出质量。很多时候模型“看起来变聪明了”其实只是输入的组织方式更合理了。4.3 ASR/OCR 是帧选择之外的另一条信息通道帧选择很重要但它不是唯一的信息来源。很多视频里有语音、字幕、背景音乐和音效这些信息无法从一帧画面里直接读出来。如果任务涉及对话内容、旁白、字幕那么 ASR 语音转写和 OCR 字幕识别往往比画面更有效。处理方法也很简单先用 FFmpeg 从视频里提取音频轨道再交给 ASR 系统转成文本对于压硬字幕的视频可以用 OCR 抽取字幕文字然后把这些文本和帧一起作为模型输入。这样做的收益非常大。比如教学视频里老师说的内容很可能就是答案本身“视频里宣布了什么事项”这类问题通过 ASR 文本就能直接得到不需要从帧画面里猜。你也可以先把文本给模型做一次摘要再决定还需要看哪些时间点的帧。这样能进一步缩小帧选择范围。5. 成本、延迟和批量的边界帧选择也是在选预算5.1 图片数量直接决定 token 和费用多模态模型处理图片是有成本的图片越多、分辨率越高token 开销越大响应时间越长。不同平台的定价公式不同但总体趋势一致图片数量是成本的关键变量。实际落地时我建议先建立一个简单的估算表。假设一次任务最多允许 10 张图那么每张图大约对应多少 token算一下最终成本是否可接受。不要凭感觉决定帧数要把它当作预算来控制。初期原型阶段先用 5 张图跑通流程如果答案质量不够再逐步增加到 10 张、20 张。这种从小到大的方式可以快速定位“问题到底是不是帧数不够”。5.2 增量式和多阶段策略先全局粗看再局部放大帧选择不一定要一次性完成。更高效的方式是分成多轮第一轮用低分辨率、少量帧获取视频的全局结构例如 5 张均匀采样的缩略图。第二轮根据第一轮的摘要找出需要重点关注的时间区间。第三轮对重点区间做更密集的抽帧或者对帧中的特定区域做裁剪放大。这种“由粗到细”的策略很像人的观察方式。先扫一眼全局再聚焦细节。它能够用更少的 token 获得更高的准确率因为最终的模型输入里大部分帧都是和任务相关的。如果你有足够长的上下文和更大的成本预算当然可以一次性传 50 帧。但在大多数项目里成本都是有限资源增量式处理往往更可持续。5.3 从原型到生产的长期维护如果只是做实验一个脚本就够了。但如果你要把“让 LLM 看视频”变成一个正式服务还需要考虑视频上传和解码的异步队列避免阻塞接口。抽帧结果缓存策略同一段视频不必每次都重新抽帧。存储策略如果帧图片很多需要考虑磁盘占用和清理策略。失败重试某一张图片解码失败或者模型请求超时不能影响整个任务。日志记录每一条请求用了哪些帧、什么时间、模型输出什么方便后续复盘。这些都不是帧选择本身但会直接决定一个方案能不能长期使用。很多人把注意力放在模型参数和提示词上忽略了抽帧环节的工程化结果上线后到处踩坑。6. 当模型答错时先别急着换模型先排查帧选择6.1 排查顺序现象、输入、策略、输出、边界在实际调试中模型答错有无数种原因。我习惯于按固定顺序排查先把帧选择问题排除掉再考虑模型本身。看现象模型是“完全没提到某个关键信息”还是“描述顺序颠倒”还是“对物体位置判断错误”。看输入帧抽出来的帧是否足够清晰画面是否过暗目标物体是否被遮挡帧是否重复看抽帧策略关键动作发生在什么时间你选的时间点是否覆盖了它间隔是否太大看上下文组织时间戳有没有给帧顺序是否正确图片是否被压缩成网格导致细节丢失看模型能力以上都没问题再考虑是否换模型、调提示词、增加更多帧。一个常见误区是模型给出了一个看似合理的错误答案你以为它是“推理错了”于是疯狂调提示词。但实际上模型根本没有看到关键帧它是在“缺信息”的前提下用常识脑补了一个答案。这种情况下提示词优化解决不了问题。6.2 一个最小调试模板为了快速定位是帧选择问题还是模型问题可以做一个最小化实验准备一段包含明确答案的短视频。用三种方式生成输入均匀采样、场景切换、手工挑选关键帧。保持相同提示词分别让模型回答。比较三种输入下答案的差异。如果三种方式答案都错可能是模型能力或提示词问题。如果只有均匀采样错而手工挑选关键帧对说明问题就出在帧选择策略上。还可以让模型输出“每帧你看到了什么”来检查模型是否真的看到了你期望的内容。比如你选了一张有明显红车的帧模型却描述成“路边停着一辆白色车”那可能是图片压缩、光线、角度或模型识别能力的问题。这个反馈能帮你判断下一步该调整哪里。7. 帧选择不是预处理而是任务设计7.1 把帧选择当成可复用的决策框架我把多次实验后沉淀出来的步骤总结成一个小框架适合大多数视频理解任务定义任务目标你希望模型回答什么需要全局信息还是局部细节拆解信息维度时间范围、空间区域、文字字幕、动作事件、物体位置。生成候选帧先均匀抽帧或场景切换得到候选图集。筛选相关帧结合语义模型、OCR、ASR、规则选出少量关键帧。验证并迭代记录输出不达标的样例回到第 2 步调整策略。这个框架的核心是不要一开始就跳进“用什么模型”的讨论而是先想清楚“模型需要看到什么信息”。很多任务失败是因为我们没有给够信息或者是给了太多无关信息模糊了关键内容。7.2 适合谁、不适合谁帧选择这套方法论适合视频问答、视频摘要、内容审核、教学视频检索、多模态 Agent 的视觉感知等场景。这些任务通常对时间精度要求不极端画面里包含清晰的语义信息且可以通过少量帧表达。但它也有明确边界。如果任务需要逐帧理解比如判断 1 秒内挥拳动作的角度变化、高速运动物体的轨迹、精密仪器的微小位移那基于大模型 抽帧的方案不是最佳选择。此时更应该用传统 CV 算法或专门的动作识别模型而不是勉强让 LLM 从稀疏帧里推理。另外如果对实时性要求极高每一帧都要处理抽帧反而变成瓶颈。这些场景需要专门的视频理解 pipeline。帧选择是“用有限信息做整体理解”的思路它强调取舍和效率不是无限制地追求完整。7.3 长期值得关注的原因即使未来多模态模型的上下文窗口越来越大帧选择也不会消失。模型的推理能力和成本始终是有限资源而视频信息量永远远大于模型能一次吃下的量。关键问题永远是如何在有限的输入预算里保留对任务最有价值的信息。这也是我在文章开头说“frame selection is the whole game”的原因。它不是一次简单的抽帧操作而是决定了模型能看什么、不能看什么最终决定了系统的理解上限。下次再做“让 LLM 看视频”的任务时不妨多花时间研究视频内容、任务目标和帧策略。先搞定帧选择再去谈提示词和模型选型你会发现很多问题其实早已有了答案。