独立产品 — 设计、开发与发布 — 2026年7月 →
Moodle
Agent
一个无人值守跑完整件事的 agent:每一份课件、习题和作业说明被归进正确的周,每一节录播被读成文字,成绩一发布就被记下 —— 于是等着你的,是一个语言模型可以直接拿来干活的文件夹。
课程材料总是 来得晚,而且 从不集中在一处。
每门课都把文件发布在十几个层层嵌套的板块里,而且很少一次性发完 —— 课件在上课前、习题在本周内、答案在几天之后。想在本地保留一份干净的副本,就意味着每周重新点开每门课,还得记住哪些已经下过了。
现有的浏览器插件只是把点击变少了:学生仍然要打开每一个课程页面,自己决定抓哪些东西。真正的问题从来不是下载速度 —— 而是这件事必须靠人记得去做,而且每节课有一半内容被锁在一段没有任何工具读得了的视频里。
- 01分批发布
- 答案和补充材料在课后几天才出现 —— 一门课只扫一遍永远不够。
- 02深度嵌套的结构
- 「周」是某个父板块下的子板块,其下还有更深的子板块;课程主页上什么都没有。
- 03认证摩擦
- 任何自动化都必须扛住单点登录和多因素认证,同时绝不持有密码。
- 04机器读不了
- 最有价值的内容是讲出来的,藏在录播里 —— 在它变成文字之前,对任何工具都没用。
先读懂系统, 再去自动化它
第一版爬虫什么也没抓到。课程主页上根本没有文件链接:这套 Moodle 用的是自定义版式,「周」是 Learning 板块下的子板块,而每一周下面还有更深的子板块,材料真正放在那里。
把结构摸清楚,靠的是真的去抓页面、读 HTML。现在的爬虫按广度优先遍历板块链接,构建父子树,让子节点继承父节点的周次。课程发现则复用了 Moodle 面板自己调用的那个 AJAX 接口 —— 它顺便还暴露了学生标星了哪些课,所以工具可以直接列出清单,而不是让人去复制课程 ID。
假设中 — 扁平
抓到 0 个文件
实际上 — 嵌套
板块编号并不连续。子节点继承父节点的周次。
把讲出来的那一半 变成文字
课件只承载了一节课的一半,剩下的一半是讲出来的。每一份录播都会被读成一份文档 —— 全程不下载视频,只取它的字幕 —— 而正是这一步,让后面所有事情成为可能。
难点从来不是下载。老师发布录播有四种不同方式,而且四种都有人在用,所以只处理最显眼那一种的程序,会悄无声息地漏掉其余三种。Panopto 还会对每一份录播 单独 授权 —— 一份从未被打开过播放器的录播,会报告「没有字幕」,而不是报错。正是这一个行为,导致那些明明标着「含字幕」的视频被判定成没有字幕。
一份录播出现的四种方式
- 01
板块页面上的一个链接
- 02
直接写在页面正文里的裸 URL
- 03
嵌在页面中的 iframe
- 04
包着以上任意一种的 page 或 url 活动
抓不到的时候 —— 说明原因
- 01没有字幕
- 会写进当周的说明里,让你知道它存在。
- 02被限流
- 会在之后的同步中重试。
- 03需要登录
- 只多要一次登录,且只要一次。
- 04已排队
- 刻意押后,以免超出接口限制。
产出的东西, 是模型 读得懂的
一份文字稿不是终点,而是学生真正想做的那件事的输入:问一个概念、拼一份复习提纲、找某个知识点讲在哪儿。这个 agent 真正的产物,是一整周已经处理成「可以直接粘给模型」的材料。
用哪个模型,刻意不由工具替你决定。不填密钥就不生成摘要,八家服务商任选,而且不填密钥整条管线照样跑 —— 你拿到的只是文字稿而不是摘要。工具里不内置任何人的密钥,所以没人替别人付账;而一个完全不想让模型介入的学生,手上仍然是一个能用的工具。
谁的模型,谁的账单
- 01自带密钥
- 支持八家服务商;不内置、也不转售任何额度。
- 02默认关闭
- 没有配置密钥时,不会有一个字节被发给任何模型。
- 03只降级,不罢工
- 没有密钥就没有摘要 —— 文字稿照样到位。
- 04用人会粘贴的格式
- Word 和纯文本,因为那才是聊天工具真正接受的东西。
完整的一圈
- 01
收集
遍历每一个嵌套板块;只抓新增的部分。
- 02
读取
取出每份录播的字幕,写成一份文档。
- 03
摘要 — 可选
你的密钥、你的服务商、你说了算。默认关闭。
- 04
交付
一个装着纯文本和 Word 文件的周文件夹,可以直接粘进任何模型。
两屏设置, 然后不用再管
分发方式被当成设计的一部分,而不是事后才考虑的事。整个产品就是一个 75 MB 的文件:不装运行时、不要管理员权限、不碰命令行。设置过程只问两个问题,并给出一份它自己找到的课程勾选清单;之后这个窗口存在的唯一意义,就是回答「它还在跑吗」。其余的事 —— 收集、读取、记录成绩 —— 都发生在没人盯着的时候。
现状 · 人工
- 01记得去看 Moodle
- 02登录,逐门课打开
- 03展开每一个周板块
- 04和本地文件夹比对
- 05下载新增文件
- 06拖着看 47 分钟视频
每周、每门课 · 很容易忘 · 录播始终读不了
目标 · agent 化
- 01应用自行唤醒
- 02静默恢复会话
- 03遍历每一个板块
- 04比对清单差异
- 05录播被读成文字
- 06归档、记录,随时可喂给模型
每 3 小时一次 · 什么都不用记 · 材料到手即机器可读
不需要持有的 东西,就别 持有
向学生索要学校密码,会让这个工具变得非常好写,同时变得不可能被信任。所以登录被放回它该在的地方:一个真实的浏览器窗口,打开学校自己的登录页,多因素认证照走不误。应用自始至终看不到任何凭据。
它保留的是登录之后的会话,存放在项目目录之外的本地位置,因此绝不会被提交进仓库或同步到云端。除非你自己明确配置了模型密钥,否则没有任何东西离开这台机器:没有服务器、没有埋点、没有账号。控制台输出的是相对于下载目录的路径,所以随手分享的截图也不会泄露用户名。
- 01
学校 SSO + MFA
跑在真实浏览器里 —— 用户自己输入,应用只负责等待完成。
- 02
会话 Cookie
存在本地,位于仓库之外,也位于云同步目录之外。
- 03
静默无头同步
下次运行时重新注入。没有窗口、没有密码、没有服务器。
- 04
模型调用需手动开启
除 Moodle 之外唯一的外发流量,是你自己用密钥打开的那一条。
以及基于清单追踪的增量同步,跨多次运行零重复下载
交付物
这个项目真正教会我的东西 —— 而不是它交付了什么。
要消灭的是任务,不是点击
下载得更快,这件苦差事依然留在学生身上。只有无人值守地跑起来,才真正解决了这件苦差事所代表的问题 —— 这是产品决策,不是技术决策。
有用的产出必须是机器可读的
把一段视频归好档,什么也没改变;把它读成文字,才改变了学生接下来能做什么。让 AI 工作流成为可能的是文字稿,而不是下载。
先读懂系统
第一版爬虫失败,是因为我自动化了一个自己假设出来的结构。真的去抓 HTML、把周次的嵌套关系画清楚,才让后面的一切成为可能。
把模型的选择权交给用户
内置一个密钥,意味着替陌生人付账、还替他们选了服务商。自带密钥只多花一个设置页,却同时消掉了这两个问题。
信任是一条设计约束
把凭据挡在工具之外让开发变难了,也正是因为这一点,它才能放心交给一个陌生人。是安全决定了架构,而不是反过来。
静默跳过会藏住 Bug
失败的录播被悄悄略过,于是一整类故障连续几周都没被发现。现在每一次跳过都会说明原因,并标明它是最终结论还是会重试 —— 其中好几个问题正是这样才被找出来的。