坚持手写前言

视频的总结很早就有,然而这套方法并不是直接用多模态模型去检测视频内容,这消耗承受不住。现在借助一个SKILL和MiniMax的token plan,我们自己就能本地搭建一个总结视频的workflow,我把他写成了一个SKILL进行了封装,目前在B站小红书抖音都能正常跑通流程。

感谢灵感来源,SKILL可以从media-analyze获取。

关键技术说明

OpenCLI

链接:https://github.com/jackwener/OpenCLIhttps://opencli.co/

1. 它到底是什么

OpenCLI可以理解成两层东西:第一层是一套“浏览器遥控器”,第二层是基于这套遥控器写出来的“网站快捷命令”。

浏览器遥控器负责完成最基础的网页操作,例如打开网页、查看页面内容、点击按钮、往输入框里输入文字、等待页面变化、读取页面文字、抓取网页请求返回的数据、截图或下载文件。无论是B站、小红书、知乎还是其他网站,这些基础动作大体都是通用的。

网站快捷命令则是把某个平台的固定流程封装起来。例如:

1
2
3
opencli bilibili hot --limit 5
opencli zhihu hot -f json
opencli hackernews top --limit 5

这些命令看起来像普通CLI,但背后可能是在打开网页、复用登录态、调用页面里的接口、整理字段,然后把结果输出成表格或JSON。对人来说,它把网页操作变成了命令;对Agent来说,它把不稳定的网页点击变成了更可控的工具调用。

2. 为什么能复用登录态浏览器

OpenCLI不是自己重新模拟一个浏览器,而是在本机Chrome/Chromium里安装一个Browser Bridge扩展。执行浏览器相关命令时,大致流程是:

1
2
3
4
opencli命令
-> 本地小服务
-> Chrome扩展
-> 真实浏览器页面

所以网页请求是在你真实的Chrome里发出去的,会自然带上这个浏览器里已有的cookie、localStorage等登录信息。也就是说,只要你已经在Chrome里登录过目标网站,OpenCLI就可以在这个登录环境里执行操作,而不需要把账号密码或者cookie单独交给脚本。

这点很重要。很多网站的数据只有登录后才能看到,传统脚本往往要自己维护cookie,容易过期,也有安全风险。OpenCLI的思路是让凭证继续留在浏览器里,命令只负责“遥控”这个已经登录好的浏览器。

基本安装和检查流程如下:

1
2
3
npm install -g @jackwener/opencli
opencli doctor
opencli list

其中浏览器型命令还需要安装Browser Bridge扩展,并确保Chrome/Chromium正在运行、目标网站已经登录。

3. opencli browser提供了哪些基础操作

opencli browser可以理解成OpenCLI暴露出来的一组浏览器遥控按钮。比如:

1
2
3
4
5
6
opencli browser demo open https://www.baidu.com
opencli browser demo state
opencli browser demo click 2
opencli browser demo type 1 "OpenCLI"
opencli browser demo wait 2
opencli browser demo screenshot /tmp/opencli.png

这里的demo是一个会话名字,表示接下来这些命令尽量操作同一个浏览器页面。state的作用是让OpenCLI先“看一眼当前网页”,然后把页面上能点、能输入、能读取的地方整理成一个清单。比如它可能看到:

1
2
3
[1] 搜索框
[2] 搜索按钮
[3] 第一条搜索结果

之后执行opencli browser demo click 2,意思就是点击刚才清单里的第2个东西;执行opencli browser demo type 1 "OpenCLI",意思就是往第1个输入框里输入文字。这样Agent不需要只靠截图猜页面,而是可以先拿到一份页面清单,再根据编号一步步操作。

除了点击和输入,OpenCLI还可以读取页面文字、查看当前标签页、监听网页请求、执行页面内的读取脚本、截屏、滚动页面等。它的重点不是替代所有浏览器自动化工具,而是把这些能力整理成Agent容易调用的命令形式。

4. 现成适配器和不同平台的差异

OpenCLI说“把任意网站变成CLI”,并不是说它天生知道所有网站怎么用。真正开箱即用的是那些已经写好适配器的网站,例如B站、小红书、知乎、Twitter/X、Reddit、HackerNews等。

这里需要区分“通用动作”和“具体流程”:

1
2
通用动作:打开、点击、输入、等待、读取、截图、抓请求
具体流程:B站热门怎么拿、小红书笔记怎么拿、知乎热榜怎么拿

通用动作在不同平台上大体一致,但具体流程并不一致。B站热门可能是打开B站后调用热门视频接口,再整理标题、作者、播放量、bvid;小红书搜索可能是进入搜索页、输入关键词、等待结果加载,再从页面或接口里提取笔记标题、作者、链接。它们都使用OpenCLI的浏览器能力,但每个平台的适配器都需要单独写。

所以OpenCLI更准确的定位是:它提供一套通用的网页操作能力,并把常见平台的稳定流程封装成命令。有适配器的网站可以直接用;没有适配器的网站,就需要先探索页面,再把稳定下来的流程写成新的命令。

5. 如何把一个新网站变成OpenCLI命令

如果只是自己本机使用,最简单的方式是写一个私人adapter。OpenCLI会自动发现~/.opencli/clis/<site>/<command>.js下面的命令文件,因此所谓“注册新网站”,本质上不是去某个中心平台登记,而是把适配器文件放到约定目录里。

一个大致流程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 1. 先检查浏览器桥接是否正常
opencli doctor

# 2. 用浏览器命令探索目标网站
opencli browser demo open https://example.com
opencli browser demo state
opencli browser demo network

# 3. 生成本机私人adapter骨架
opencli browser init example/top

# 4. 编辑生成的文件
# ~/.opencli/clis/example/top.js

# 5. 验证这个adapter能不能稳定返回数据
opencli browser verify example/top

# 6. 像普通命令一样调用
opencli example top

写adapter时,通常不是从零硬写,而是找一个相似网站或相似功能的已有适配器复制过来,主要改三类东西:入口网址、数据来源、字段映射。一个极简的结构大概类似这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { cli, Strategy } from '@jackwener/opencli/registry';

cli({
site: 'example',
name: 'top',
access: 'read',
description: 'Example热门内容',
domain: 'example.com',
strategy: Strategy.COOKIE,
args: [
{ name: 'limit', type: 'int', default: 10, help: '返回数量' },
],
columns: ['title', 'url'],
func: async (page, args) => {
await page.goto('https://example.com');
const limit = Number(args.limit) || 10;
return page.evaluate((limit) => {
return Array.from(document.querySelectorAll('a'))
.slice(0, limit)
.map((a) => ({
title: a.textContent.trim(),
url: a.href,
}));
}, limit);
},
});

这里的sitename决定最终命令是opencli example topargs定义命令参数,columns定义输出列,func定义具体执行逻辑。真实网站一般会比这个复杂:有些适合直接调用网页接口,有些需要从页面里读数据,有些需要先登录,有些还要处理反爬或字段缩写。因此更稳妥的做法是先用opencli browser stateopencli browser network看清楚页面数据从哪里来,再写adapter。

如果这个命令只是自己临时用,放在~/.opencli/clis/就够了;如果希望长期维护、用Git管理、给别人安装,推荐做成plugin:

1
2
3
opencli plugin create my-site
cd my-site
opencli plugin install file://$(pwd)

后续也可以发布到GitHub,让别人通过opencli plugin install github:user/repo安装。这样OpenCLI就不仅是一个“网页遥控器”,也逐渐变成一个可扩展的网站命令集合。

MiniMax的TokenPlan

MiniMax是最先推出TokenPlan而不是CodingPlan的,它的订阅不仅支持语言模型/编程模型,还支持不少多模态的模型,例如文生图、图片理解、语音生成,可以安装mmx工具在终端使用这些模型,并查看用量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
> mmx

███╗ ███╗███╗ ███╗██╗ ██╗
████╗ ████║████╗ ████║╚██╗██╔╝
██╔████╔██║██╔████╔██║ ╚███╔╝
██║╚██╔╝██║██║╚██╔╝██║ ██╔██╗
██║ ╚═╝ ██║██║ ╚═╝ ██║██╔╝ ██╗
╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝

Usage: mmx <resource> <command> [flags]

Resources:
auth Authentication (login, status, refresh, logout)
text Text generation (chat)
speech Speech synthesis (synthesize, voices)
image Image generation (generate)
video Video generation (generate, task get, download)
music Music generation (generate, cover)
search Web search (query)
vision Image understanding (describe)
quota Usage quotas (show)
config CLI configuration (show, set, export-schema)
update Update mmx to a newer version

Global Flags:
--api-key <key> API key (overrides all other auth)
--region <region> API region: global (default), cn
--base-url <url> API base URL (overrides region)
--output <format> Output format: text, json
--quiet Suppress non-essential output
--verbose Print HTTP request/response details
--timeout <seconds> Request timeout (default: 300)
--no-color Disable ANSI colors and spinners
--dry-run Show what would happen without executing
--non-interactive Disable interactive prompts (CI/agent mode)
--version Print version and exit
--help Show help

Getting Help:
Add --help after any command to see its full list of options, defaults,
and usage examples. For example: mmx text chat --help
MINIMAX ~/.mmx/config.json | Region: cn (file) | Key: sk-c...5Qoo (file)

╭─────────────────────────────────────────────────────────────────────────╮
│ MINIMAX TokenPlan 配额面板 周期: 2026-05-17 — 2026-05-24 │
├─────────────────────────────────────────────────────────────────────────┤
│ MiniMax-M* 0 / 4,500 0% │
│ └ 每周 0 / 0 重置于 4h 6m │
├─────────────────────────────────────────────────────────────────────────┤
│ coding-plan-search 0 / 450 0% │
│ └ 每周 0 / 0 重置于 4h 6m │
╰─────────────────────────────────────────────────────────────────────────╯

yt-dlp和faster-whisper

链接:

1. 它们在这个workflow里分别负责什么

如果说OpenCLI负责“找到网页上的内容入口”,MiniMax负责“后续总结和生成文本”,那么yt-dlpfaster-whisper负责的就是中间最关键的一步:把视频变成可以交给大模型处理的文本。

这两个工具的分工很清楚:

1
2
yt-dlp:负责把视频、音频、字幕、元数据下载下来
faster-whisper:负责把音频转写成带时间戳的文字稿

所以整个视频总结流程大致是:

1
2
3
4
5
视频链接
-> yt-dlp下载字幕或音频
-> faster-whisper把音频转成文字
-> LLM根据文字稿总结
-> 生成Markdown笔记

这里的关键点是:我们并不是直接把整段视频丢给多模态模型理解。那样成本高、速度慢,也很难做批量任务。更合理的方式是先把视频压缩成文本信息,保留标题、作者、发布时间、分段时间戳、字幕或转写文本,再让大模型处理这份文本。

2. yt-dlp:视频下载和信息提取工具

yt-dlp可以理解成一个很强的视频站点下载器。它不只是支持YouTube,也支持大量视频、音频和内容平台。它的作用不是“理解视频”,而是尽可能稳定地把视频相关资源取出来,包括视频文件、音频文件、字幕、封面、标题、作者、发布时间、简介等。

在总结workflow里,我一般会优先尝试拿字幕,因为字幕已经是文本,处理成本最低。如果目标平台没有字幕,或者自动字幕质量很差,再下载音频并转写。

常用命令大概如下:

1
2
3
4
5
6
7
8
# 查看视频元数据,不下载视频
yt-dlp --dump-json --skip-download "视频链接" > meta.json

# 优先下载字幕,不下载视频本体
yt-dlp --write-subs --write-auto-subs --sub-langs "zh-Hans,zh-CN,zh,en" --skip-download "视频链接"

# 只下载音频,并转成mp3
yt-dlp -x --audio-format mp3 --audio-quality 0 -o "downloads/%(id)s.%(ext)s" "视频链接"

如果遇到需要登录后才能访问的视频,可以让yt-dlp读取浏览器里的登录信息:

1
yt-dlp --cookies-from-browser chrome "视频链接"

这和OpenCLI复用登录态的思路有点像,区别是OpenCLI主要是遥控浏览器页面,yt-dlp则是把浏览器里的cookie拿来请求视频资源。实际使用时,有些平台可以直接用yt-dlp解决,有些平台则需要OpenCLI先帮忙打开页面、找到真实链接或提取页面信息,再交给yt-dlp下载。

另外,yt-dlp经常依赖ffmpeg处理音视频,例如合并音频和视频、从视频里抽取音频、转码成mp3等。因此本地最好先安装ffmpeg

1
2
brew install ffmpeg
python -m pip install -U yt-dlp

3. faster-whisper:把音频转成文字稿

faster-whisper是Whisper模型的一个高效实现。它的目标不是下载视频,而是接收一个音频文件,然后输出一段段文字,并且每段文字带有开始和结束时间。

一个最小示例如下:

1
2
3
4
5
6
7
8
from faster_whisper import WhisperModel

model = WhisperModel("large-v3", device="cpu", compute_type="int8")
segments, info = model.transcribe("downloads/audio.mp3", beam_size=5, vad_filter=True)

print("language:", info.language)
for segment in segments:
print(f"[{segment.start:.2f} -> {segment.end:.2f}] {segment.text}")

这里需要注意两点。第一,segments不是一次性返回的完整列表,而是一个可以逐段读取的结果,所以要通过for segment in segments真正触发转写。第二,模型大小和设备选择会明显影响速度和内存占用。

如果是CPU环境,可以先用:

1
model = WhisperModel("large-v3", device="cpu", compute_type="int8")

如果有NVIDIA GPU,可以用:

1
model = WhisperModel("large-v3", device="cuda", compute_type="float16")

对于视频总结这种任务,转写不一定必须追求最高精度。很多时候mediumlarge-v3distil-large-v3之类模型都可以试,关键是看本机速度、显存和可接受的错字率。如果只是想快速跑通流程,可以先用小一点的模型;如果是正式归档,再用更大的模型重新转写。

安装方式也比较直接:

1
python -m pip install -U faster-whisper

4. 为什么需要把二者串起来

单独使用yt-dlp只能拿到视频资源,不能保证拿到可直接总结的文字。单独使用faster-whisper又要求你已经有音频文件。两者组合起来,才形成了比较完整的视频转文本流程。

我比较推荐的优先级是:

1
2
3
4
5
1. 先尝试下载人工字幕
2. 没有人工字幕,再尝试自动字幕
3. 字幕不可用,再下载音频
4. 用faster-whisper转写音频
5. 将字幕或转写结果统一整理成Markdown

这样做的好处是成本可控。字幕如果已经存在,就不需要跑语音识别;只有在没有字幕时,才使用本地模型转写。对于长视频,这个差别很明显,因为语音识别会消耗大量时间,而字幕解析几乎是瞬间完成。

整理文字稿时,最好保留时间戳:

1
2
3
4
[00:00:03] 开场介绍
[00:01:20] 第一个观点
[00:05:42] 案例说明
[00:12:10] 总结

这样后续大模型总结时,不仅可以生成普通摘要,还可以生成“带时间轴的笔记”。如果某段总结有问题,也能根据时间戳回到原视频核对。

5. 一个最小可跑的处理流程

如果不考虑复杂的平台适配,一个最小流程可以拆成三步。

第一步,用yt-dlp下载音频:

1
2
3
4
mkdir -p downloads
yt-dlp -x --audio-format mp3 --audio-quality 0 \
-o "downloads/audio.%(ext)s" \
"视频链接"

第二步,用faster-whisper转写音频。可以写一个简单的transcribe.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pathlib import Path
from faster_whisper import WhisperModel

audio_path = Path("downloads/audio.mp3")
out_path = Path("downloads/transcript.md")

model = WhisperModel("large-v3", device="cpu", compute_type="int8")
segments, info = model.transcribe(str(audio_path), beam_size=5, vad_filter=True)

with out_path.open("w", encoding="utf-8") as f:
f.write(f"# Transcript\n\n")
f.write(f"- language: {info.language}\n")
f.write(f"- probability: {info.language_probability:.2f}\n\n")

for segment in segments:
start = int(segment.start)
end = int(segment.end)
f.write(f"[{start // 60:02d}:{start % 60:02d} - {end // 60:02d}:{end % 60:02d}] {segment.text.strip()}\n\n")

第三步,把transcript.md交给LLM总结。这里可以要求模型输出几类内容:

1
2
3
4
5
1. 一句话概括
2. 分段摘要
3. 关键观点
4. 值得回看的时间点
5. 可执行的行动项

在真正的自动化workflow里,这三步会被封装进SKILL中。用户只需要给一个链接,SKILL负责判断有没有字幕、是否需要下载音频、是否需要调用faster-whisper、如何切分长文本、最后如何调用LLM总结。yt-dlpfaster-whisper本身并不神秘,但它们把“视频”变成了“可被大模型稳定处理的文本”,这是整个流程里非常关键的一层。