Skip to content
Back to skills

Video Distill

ASecurity

把教学类视频(YouTube / Bilibili / 本地文件)沉淀成结构化、带时间戳、可回查的 Obsidian 笔记与操作手册。只要用户提到把视频「整理成笔记 / 沉淀下来 / 记到 Obsidian / 写成操作手册 / 做成文档 / 蒸馏知识点 / 看完做个总结存起来」,或者丢来一个教程、课程、 技术分享、软件演示视频并希望留下可复用的产物,就使用本 skill —— 即使他们没说出 「笔记」这个词。产出是分层的三件套:带时间戳的主笔记、可脱离视频复现的 PLAYBOOK、 与视频原文严格分离的扩展阅读。 **判断只看一件事:用户要的是「落盘、可回查、能复现」的产物,还是一个答案。** 要答案 ⇒ 不用本 skill。 **以下情形一律不要用本 skill**(实测这些会被误触发,逐条排除): - 问「这视频讲了啥 / 帮我总结一下 / 大概说说」—— 那是要答案,直接调 watch-skill CLI 回答 - 问某个片段、某一刻发生了什么、某个按钮是什么 —— 定点回答,不建笔记 - **会议录像出会议纪要 / 访谈整理 / 播客摘要** —— 本 skill 只做...

  • 2 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 19, 2026
ai-agentspythongobashnodeapibackend

Works with

  • claude code
  • cli
  • api
  • mcp

Security analysis

A92/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 10 files and shows the line behind each finding

Scanned September 27, 2026

npx -y skills add vinsunfeng/learning-video-skills --skill video-distill --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Video Distill?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Video Distill
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/vinsunfeng-video-distill/badge)](https://www.skillsdirectory.com/skills/vinsunfeng-video-distill)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: video-distill
description: |
  把教学类视频(YouTube / Bilibili / 本地文件)沉淀成结构化、带时间戳、可回查的
  Obsidian 笔记与操作手册。只要用户提到把视频「整理成笔记 / 沉淀下来 / 记到 Obsidian /
  写成操作手册 / 做成文档 / 蒸馏知识点 / 看完做个总结存起来」,或者丢来一个教程、课程、
  技术分享、软件演示视频并希望留下可复用的产物,就使用本 skill —— 即使他们没说出
  「笔记」这个词。产出是分层的三件套:带时间戳的主笔记、可脱离视频复现的 PLAYBOOK、
  与视频原文严格分离的扩展阅读。
  **判断只看一件事:用户要的是「落盘、可回查、能复现」的产物,还是一个答案。**
  要答案 ⇒ 不用本 skill。
  **以下情形一律不要用本 skill**(实测这些会被误触发,逐条排除):
  - 问「这视频讲了啥 / 帮我总结一下 / 大概说说」—— 那是要答案,直接调 watch-skill CLI 回答
  - 问某个片段、某一刻发生了什么、某个按钮是什么 —— 定点回答,不建笔记
  - **会议录像出会议纪要 / 访谈整理 / 播客摘要** —— 本 skill 只做**教学类**
    (教程、课程、技术分享、软件演示);会议纪要要的是决议与 owner,不是可复现步骤
  - 视频**剪辑 / 压缩 / 转码 / 提取音频 / 字幕翻译 / 生成 srt** —— 那是 ffmpeg 的活
  - 屏幕录像**排错定位**(「看看我这 bug 出在哪一步」)—— 那是调试,不是沉淀
  - 把**文章 / PDF / 网页**整理成笔记 —— 本 skill 的输入必须是视频
---

# video-distill

## 第 0 步 · 先判断该不该走这套流程(30 秒,别跳过)

**问一句:用户要的是「一个答案」,还是「一份能回查、能复现的落盘产物」?**

要答案 ⇒ **立刻退出本流程**,直接用 watch-skill CLI 回答,例如:

```bash
watch-skill ask <engine_video_id> "<用户的问题>"     # 已索引过
watch-skill watch "<url>" --transcript-only        # 没索引过,先拿转录再回答
```

然后一句话告诉用户:「这个只要答案,我就不建笔记了;想留档我再走完整流程。」

### 为什么把这条放在正文第一句,而不是只靠 description

**因为它拦不住的是一部分 agent,而不是全部。** 这一节的措辞我改过两次 ——
第一版写「写在 description 里被实测证明拦不住」,**那句话是错的,只在 Hermes 上成立。**

2026-08-08 实测「这个视频讲的啥?我不想看完,你就跟我说个大概」:

| agent | 结果 | 判据 |
|---|---|---|
| **Claude**(Claude Code 2.1.226) | **正确不触发** | 抓 `stream-json`,`"name":"Skill"` **0 次**;同一台机器同一时刻的正例是 **2 次** |
| **Hermes + deepseek-v4-pro** | **误触发,重复 3 次 3/3** | 同轮正对照 3/3、负对照 0/3,仪器可靠 |

Hermes 那边的理由每次都类似:「video-distill 正是做 YouTube 摘要的」——
它看到「视频 → 结构化」就点着了,排除句压不过这个正信号。
而 Claude 那次转头调了 26 次 Bash 直接去回答 ——
**恰好就是上面这一节要求的做法**。

> **所以「排除项无效」是个只在特定 agent 上成立的结论,
> 而我第一版把它写成了普适的。**
> 一个只在一种环境里验过的结论,写成普适的那一刻就变成了错的。

⇒ description 的排除清单**要留着**(Claude 侧靠它就够了);
而正文这个出口也**要留着** —— 它是给触发判断较弱的 agent 兜底的。
两者不是替代关系。

> 误触发的代价,因此从「白做一整套三件套」降到「多问一句话」。

**其余数字(Hermes 侧,20 条正负样例,`scripts/trigger_test.py`)**:

| description 版本 | 该触发 | 不该触发 |
|---|---|---|
| 末尾一句「不适用」 | 9/9 | 4/11 |
| 排除项列成 6 条清单 | 9/9 | 10/11 |

---

把教学视频变成「不看视频、只凭文档就能复现」的知识资产。

这是一份操作清单。每条规则背后都有源码核对和实测支撑,**看起来多余想精简某一条之前,
先读 `references/engine-internals.md` 对应小节** —— 有几条(索引清空、静默付费、
字幕轨误选)不遵守不会报错,只会安静地产出坏数据。

---

## 固化配置

> ⚠️ **换机器部署先本地化这两行**(2026-09-08 标注):`WATCH_SKILL_BIN` 与 `VAULT`
> 是**本机**的绝对路径,别的机器必须改成自己的(`watch-skill` 的实际位置用
> `command -v watch-skill` 查;vault 目录不存在就先建,含 `视频笔记/` 子目录)。
> 后文所有命令只引用这里的变量——改这里即可,别处没有硬编码。

```bash
WATCH_SKILL_BIN=/Users/vdev/.local/bin/watch-skill   # 绝对路径:subagent 的 PATH 不保证含 ~/.local/bin
VAULT=/Users/vdev/notes                              # 已确认,支持 Bases
NOTES_ROOT="$VAULT/视频笔记"
```

**所有 watch-skill 调用用这个包装形式,不要精简:**

```bash
env -u ANTHROPIC_API_KEY -u OPENAI_API_KEY -u GEMINI_API_KEY -u OPENROUTER_API_KEY \
    WATCHSKILL_SUBTITLE_LANGS='zh.*' \
    WATCHSKILL_WHISPER_MODEL=large-v3-turbo \
    WATCHSKILL_CLOUD_STT_ENABLED=false \
    WATCHSKILL_COST_POLICY=offline_only \
    "$WATCH_SKILL_BIN" <subcommand> ...
```

| 项 | 不加会怎样 |
|---|---|
| `env -u ...KEY` | 带索引的 watch 会用 Haiku 描述最多 24 帧且**不检查 cost_policy**,有 key 就静默付费 |
| `SUBTITLE_LANGS='zh.*'`(不带 en) | 多数视频 info.json 的 `language` 为 None,字幕轨按字母序回落,`media.en.vtt` 会压过 `media.zh.vtt`,拿机翻轨当原文 |
| `WHISPER_MODEL` 显式指定 | 内存探测失败会落到 `base`,中文错字密集(「多参考图」→「多餐口圖」),不能用于笔记。`large-v3-turbo` 是 **Apple Silicon(mlx)实测档**;**非 CUDA 的 Linux/CPU 机器改 `medium`**(large-v3-turbo 在 CPU 未测,medium 实测简体准确但 RTF 0.62x),见 AGENT-START §3 |

英文视频临时改 `WATCHSKILL_SUBTITLE_LANGS='en.*'`。详见 references 第 2、3、5 节。

---

## 机械契约(写入前必读)

正文怎么组织、小节怎么起名、行文风格 —— **这些你自己判断,按内容实际结构来写更好**,
不要被模板的示例小节束缚。第一版实测就是这样:自创的 11 个小节比模板示例贴合得多。

但有 6 处是**字面契约**:`validate.py` 按精确形式 grep 它们,写法不同就过不了闸门。
它们的存在不是为了统一风格,是为了让「这份笔记可回查、来源可分辨」这件事**可机器验证**——
否则质量只能靠人逐份读。

| 契约 | 精确形式 | 为什么必须是这个形式 |
|---|---|---|
| 时间戳锚点 | **markdown 链接**:`[01:23](url&t=83s)`,区间也可以 `[02:38–02:51](url&t=158s)` | 可点击跳回原片是「这句话是讲者说的」的凭据。`〔02:38–02:51〕` 全角括号不是链接,点不动,等于没有凭据 |
| 主笔记锚点小节 | 必须有一个 `## 视频要点`,其下每条以时间戳链接开头 | 这是唯一被逐条校验的小节。**你可以自由增加任意其他小节**(背景、结构、坑…),只要这一节存在 |
| PLAYBOOK 步骤 | 每个 `### ` 步骤块内出现至少一个时间戳链接 | 操作手册最易错的是顺序和参数值,跳回原片是唯一纠错手段 |
| EXTEND 条目 | 每条以 `- ` 开头的条目里出现字面串 `[扩展]` | 这个标记是给机器读的。文件开头声明「本文件是扩展层」对人足够,但校验器只能逐条看。少了它,视频原文和补充内容在机器眼里无法区分 |
| `engine_video_id` | frontmatter 必填,16 位十六进制,且**必须等于 `sha256(source.strip())[:16]`** | 事后 `ask` / `search` 全靠它。校验器会用同一份 frontmatter 里的 `source` 重算并比对 —— 填个占位串过不了闸 |
| `content_hash` | frontmatter 必填 = **frontmatter 之后的正文,`.strip()` 后 sha256 十六进制前 16 位** | 重跑保护靠它判断文件是否被人工改过。算法不一致就永远误报「被改过」,保护机制自我失效。只对正文取 hash,否则 hash 会自指 |

```python
# content_hash 的唯一正确算法
import hashlib
body = 文件内容[frontmatter 结束的 "---\n" 之后 :]
content_hash = hashlib.sha256(body.strip().encode("utf-8")).hexdigest()[:16]
```

阶段 3 跑完 `validate.py` 就能确认这 6 条,且**每条都是真检查而非存在性检查**:
`engine_video_id` 用 `source` 重算比对,`content_hash` 重算比对(不一致是 ERROR,
不是提醒 —— 刚写完就对不上只可能是算错了),时间戳锚定行首,`[扩展]` 与小节名逐条 grep。

**闸门不过就不算交付完成**,不要贴着错误清单说「内容质量很好」——内容好和可验证是两件事,
这份 skill 要的是两者都有。

---

## Preflight(会话内首次运行做一遍)

```bash
"$WATCH_SKILL_BIN" doctor
```

`python`(3.11.x) / `ffmpeg` / `yt-dlp` / `js-runtime`(deno,YouTube 需要) 必须 ok。
`memory: warn` 可忽略(doctor 自身探测的 cosmetic 问题)。失败就停下报告,不要降级硬跑。

---

## 阶段 0 · 预探测与计划(第一个确认点)

1. **元数据**:`yt-dlp --skip-download --dump-single-json` 取 title / uploader /
   duration / `language` / `subtitles` / `automatic_captions` / `chapters` / 源分辨率。
2. **查重**:用平台 video_id grep `$NOTES_ROOT` 下的 frontmatter。命中就问
   「更新 / 跳过 / 另存版本」,不要静默覆盖 —— 用户可能已经手工补充过内容。
3. **分类初判**:`ls "$NOTES_ROOT"` 枚举现有分类,从中选;要新建就问一次。
   `$NOTES_ROOT` 为空(首次使用)时没有可选项 —— 这时**直接提出一个分类名**放进阶段 0
   的那次确认里,不要因为「只能从现有里选」而卡住。这条规则的目的是防止分类无节制增殖,
   不是在空目录上制造死锁。
4. **清晰度预判**:源高于 720p 且含代码/界面演示 → 此处就告诉用户「引擎硬编码
   `height<=720` 且不接受 cookie,要看清代码请给本地高清文件」。等下载完才发现会白费一次下载。
5. **打包成一次确认**:字幕来源、分段方案、抽帧分辨率、预计耗时、是否启用 WebSearch 扩展。
   ≥20 分钟且有章节 → 给章节地图让用户选精看范围。
   转录耗时按 RTF 0.05x 估(Apple Silicon mlx 实测值;CPU `medium` 实测 0.62x,
   约 12 倍,按本机档位换算);不要报「转录费用」,本地转录免费。

---

## 阶段 1 · 全片转录(要不要索引,在这里定)

**先说实测事实(2026-08-28 源码核对 + 实测)**:引擎只有拿到 perception(抽帧+OCR)
才会写索引 —— CLI 源码是 `if index and result.perception is not None`。
**`--transcript-only` 恒无 perception ⇒ 这条路径上 `--index/--no-index` 开关是死的,
加不加都不写索引**(实测:跑完 `list` / `search` 都找不到该视频)。
本节早期版本称「`--transcript-only` 是唯一索引写入点」——**那是错的**,
它基于「会写转录段落进索引」的错误认知。详见 references 第 1 节。

所以按内容类型二选一:

**路径 A · 口播 / 理论型(快)**:

```bash
env -u ... "$WATCH_SKILL_BIN" watch "<source>" --transcript-only --out-dir "$WORK"
```

只拿转录,不下载视频画面。**不写索引** —— 阶段 2.1 走指示语 + 章节边界降级定 cue。

**路径 B · 操作型 / 界面密集(语义定 cue 的前提)**:

```bash
env -u ... "$WATCH_SKILL_BIN" watch "<source>" --out-dir "$WORK"
```

(即:**不 带 `--transcript-only`**。)转录 + 场景帧 + OCR 文本 + 嵌入索引一次拿到;
阶段 2.1 的 `search` / `ask` 从此可用,且 OCR 行让英文界面词能直接命中
(2026-08-28 实测:真实索引上英文查询 0.71、中文词组 0.82–0.88)。
**代价**:全片下载 + 抽帧 + OCR(13.7 分钟视频数分钟 CPU)。
**纪律**:从此刻起到阶段 2 结束,任何再跑的 watch 一律加 `--no-index` ——
索引写入前会 `DELETE` 该 video_id 的全部派生行,第二次带索引 watch 会把第一次清空。

完成后:

- 核对字幕轨确实是原生语言(看 `media.*.vtt` 的语言后缀与内容)。不符就显式设
  `WATCHSKILL_SUBTITLE_LANGS` 重跑。不要用机翻英文轨当原文——它是翻译,不是讲者说的话。
- 转录存档到 `$WORK/transcript.md`(阶段 4 蒸馏的前提,清理 work dir 后不可恢复)。
- **取 `engine_video_id`**。路径 B 下 watch 输出里有 `**Indexed:** video_id` 一行,直接取用;
  路径 A 下这行**不存在**(没写索引就不打印,实测 grep 不到)。
  两条路径通用的方法是自算:

  ```bash
  python3 -c "import hashlib,sys;print(hashlib.sha256(sys.argv[1].strip().encode()).hexdigest()[:16])" "<source 原样字符串>"
  ```

  必须和你传给 watch 的 source 字符串**逐字节一致**(引擎就是 `sha256(source.strip())[:16]`,
  URL 少一个参数就是另一个 id)。路径 B 下可用 `"$WATCH_SKILL_BIN" list` 交叉核对;
  路径 A 下 `list` 里**不会有它**(不在索引里),别误判成「没跑成」。
  这个值是六条机械契约之一:不落盘、work dir 一清,事后 `ask` / `search` 就只能重跑整条流水线。

---

## 阶段 2 · cue 定位 + 定点抽帧 + 分段理解

### 2.1 生成 cue 时间戳表

**前提:索引存在。** 只有阶段 1 走了路径 B 才有索引。不确定就先 `"$WATCH_SKILL_BIN" list`
看有没有该视频;没有而内容又确实需要语义定 cue(界面演示、节点操作)⇒ 回去补一次
阶段 1 路径 B 的全片 watch —— 此时补是**安全的**(路径 A 从没写过索引,没有派生行可被
DELETE 清掉,下载还有缓存);纯口播内容直接降级指示语,别为 cue 白跑全片抽帧。
索引不可用时降级为纯指示语匹配,记入 `degradations`。

索引在,就对它做语义检索,命中的 hits 自带时间戳:

```bash
env -u ... "$WATCH_SKILL_BIN" search "操作步骤 点击设置 菜单路径"
env -u ... "$WATCH_SKILL_BIN" ask <engine_video_id> "代码示例 终端命令 报错信息"
```

**中文查询写成「空格分隔的、3 字以上词组」**:

```
✗ "如何配置代理服务器超时"
✓ "代理服务器 超时配置 网络设置"
```

引擎的 `_fts_query` 和 `lexical_anchor` 都按空白切分,且后者丢弃长度 < 3 的词。
中文整句会退化成一条要求逐字相邻的短语查(几乎零命中),同时把置信度锚点压成 0,
导致升级阶梯过度触发、白耗算力。所以双字词并成四字:`超时配置`、`环境变量`、`常见错误`。
详见 references 第 4 节。

**同一语义也试一遍英文词组。** 实测同一视频上英文查询命中率 **0.72 vs 中文 0.34** ——
原因不在模型偏好,在于索引里有大量英文:界面标签、节点名、参数名、文件名,以及不少
教学视频带的中英双语硬字幕(OCR 会把两条都读进索引)。嵌入模型本身是跨语言的
(实测中↔英余弦 0.59),所以 `LoRA loader node`、`resolution selector`、`API key setup`
这类查询往往比中文词组更能命中界面演示的时刻。**两种都发一遍,合并 hits。**

辅以转录里的指示语(「你看这里 / 打开设置 / 输入这个 / 如图 / 注意」)与章节边界。
索引不可用时降级为纯指示语匹配,记入 `degradations`。

**读输出前先过滤日志噪音**,否则帧路径和 OCR 文本会被冲没:

```bash
... | grep -v -e E5RT -e '^objc\[' -e RapidOCR
```

三个来源分别是 CoreML EP(本地补丁 2 的副作用)、cv2 与 av 各带一份 libavdevice、
以及 RapidOCR 对空白帧的例行报告。都不是错误。

### 2.2 分段观看

分段判据是**信息密度,不是时长**。实测一个 13.7 分钟的界面演示视频抽出 88 帧、
83 个场景切换 —— 按时长它「不用分段」,按实际负载它必须分。看这几个信号:

- 阶段 1 的 watch 报告里场景数 / 帧数(>60 帧就该分)
- cue 表的规模(cue 多到超过 `--max-frames` 就必须分)
- 内容形态:界面演示、逐节点讲解、代码走查 → 密;口播、幻灯片朗读 → 疏

分段就按 10~12 分钟切,每段派一个 subagent;密度低且总时长短才单遍处理。

```bash
env -u ... "$WATCH_SKILL_BIN" watch "<source>" \
  --start <t0> --end <t1> \
  --timestamps <该段 cue,逗号分隔> \
  --resolution 1280 --max-frames 60 --no-index --out-dir "$WORK"
```

- **必须加 `--no-index`**(理由同阶段 1)。
- **cue 数 ≤ `--max-frames`**:引擎对 cues 做 `_even_sample(cues, cap)`,超量会被抽稀,
  等于白定位,而且不报错。cue 多就提高 max-frames 或缩短分段。
> ### ⚠️ 你可能读不了图 —— 先确认,再决定怎么读帧
>
> 下面写的 `Read` 每个帧路径,**前提是你能直接接收图片输入**。
> **别按 agent 名字假设能力,按配置实测**——同一个 Hermes,配没配视觉是两个物种:
> 未配视觉时跑完 29 分钟教程产出满分四件套而 `assets/` 0 张帧(2026-08-08),
> 或自述「没有视觉模型」只靠 OCR(2026-09-08);配了 `auxiliary.vision` 后直接读帧,
> 面板/字幕分层、连字幕残影都识别,质量经主代理亲读对答案验证(2026-09-08)。
>
> | 你的情况 | 怎么读帧 |
> |---|---|
> | 能直接吃图(Claude;或配了 `auxiliary.vision` 的 Hermes) | `Read` 帧路径 / 直接读图 |
> | Hermes 未配视觉 | **先配再跑**:profile config.yaml 加 `auxiliary.vision`(做法与实测可用的模型名见仓库 `HERMES-INSTALL.md` §〇——`deepseek-v4-flash-vision-exp` 可用,`deepseek-v4-vision-exp` API 不认) |
> | 不便改配置时的绕路 | 视觉 MCP,如 `mcp__minimax__understand_image`(已实测:逐字读出画面三行文字、认对颜色与形状) |
> | 真的什么都没有 | **必须写进 frontmatter 的 `degradations`**,并且不要产出操作型 PLAYBOOK —— 纯字幕的步骤不可复现(2026-09-08 一次纯 OCR 路线的观察:GUI 步骤可走但整体未达盲测验收,n=1,规则维持不变) |
>
> **「能读图」的判据是仪器检查,不是自述**:拿一张内容已知的帧考自己
> (比如已验收笔记里的证据帧),读得出版面结构和已知文字才算配通——
> hermes 自己报「能/不能」都作不了数(2026-09-08 两个方向都实测过)。
>
> **抽帧本身不需要任何 key** —— OCR 是本地 RapidOCR。
> 缺 key 只影响引擎的「场景描述」(`scene descriptions skipped (vision.no_api_key)`),
> 而**画面文字照样读得到**。别把「没有视觉模型」误当成「不能抽帧」。

- subagent 内 `Read` 每个帧路径(帧只进子代理上下文,用完即弃),返回**纯文本段落笔记**
  加该段证据帧路径。prompt 带上前一段的 running summary(术语表 + 进行中的主题),
  否则段间指代会断。
- 段落笔记**立刻落盘** `$WORK/.drafts/segment-N.md`,注明覆盖的时间范围。
- 证据帧**同步** `cp` 到 vault 的 `assets/`(命名 `mm-ss-描述.jpg`),不要攒到最后——
  会和临时目录清理产生竞态。
- 每段完成给用户一行进度。

**断点续跑**:开工前先看 `$WORK/.drafts/` 有哪几段,只补缺失的。

### 2.3 转写规则

| 画面类型 | 转写成 |
|---|---|
| 图表 | 数据表或 Mermaid,保留轴、单位、数值、结论 |
| 操作演示 | 可复现步骤:菜单路径、点击对象、输入值、预期反馈 |
| 代码/终端 | 完整文本 |
| 讲解/字幕 | 时间戳对齐的要点 |

> ### ⚠️ 命令与版本约束:**逐字复制,并把画面原文一起留下**
>
> 2026-08-08 实测的一次真实错误。画面上是:
>
> ```
> pip install -U "triton-windows>=3.7,<3.8"
> ```
>
> 而 agent 写进 PLAYBOOK 的是 `-U "triton-windows<3.7"` ——
> **丢掉 `>=3.7,` 之后,约束整个反了**:照它装会拿到 3.7 **以下**的旧版本。
> 而正确答案就在**它自己引用的那张帧**里。
>
> **占位符是诚实的空白;抄错的命令是自信的错误。后者更糟** ——
> 占位符会让人去查,错命令让人在别处排错。
>
> 所以两条硬规则:
>
> 1. **命令、版本号、参数值一律逐字复制,不要重述、不要"简化"。**
>    版本约束尤其危险:少一个边界就是另一个意思。
> 2. **把画面原文以引用块留在紧邻位置**:
>
>    ```markdown
>    > 画面原文([15:55] 帧,逐字):
>    > `pip install -U "triton-windows>=3.7,<3.8"`
>    > `Collecting triton-windows<3.8,>=3.7`
>    ```
>
>    **引用块的覆盖范围必须不小于正文的断言。** 2026-08-08 第二次盲测
>    在这个机制里抓到了我自己的错:正文写
>    `python.exe -m pip install -U "triton-windows>=3.7,<3.8"`,
>    而引用块只从 `pip install` 起抄 —— **「用哪个解释器装」那一点没有画面支撑**,
>    可正文看起来整条都有。同样,正文断言「无报错」时,
>    引用块就得抄到 `Successfully installed ...` 那一行。
>
>    > **一个覆盖不全的引用块,比没有引用块更容易骗人** ——
>    > 它把「部分有据」包装成「整条有据」。
>
>    这样**抄错能被发现** —— 而 `validate.py` **查不出这类错**:
>    它能校验结构、时间戳、hash,**不能校验你有没有读对画面**。
>    留下原文,是把不可自动检查的东西变成可人工核对的。

**专有名词、命令、参数值以 OCR 为准。** 这是实测结论:同一批帧上 OCR 正确读出
「多参考图」「真人 AI 短剧」,而 whisper 写成「多餐口圖」「真人短距」。换成
large-v3-turbo 后同音词「短距/短剧」依然错 —— 声学模型解决不了同音,画面文字才是
专名的可靠来源。

- OCR 有该词就用 OCR 的写法,冲突处标 `[OCR 与转录不一致 @mm:ss]`;
- OCR 未覆盖才采信转录;
- 两者都不可辨 → 走免模型回补:`ask <engine_video_id> "<画面文字 具体内容>"`,
  引擎会自动 `dense_resample`(高分辨率密集重抽 + OCR)→ `crop_and_reocr`(按 OCR box
  裁剪 2× 放大重读),两步都不调模型,恢复的证据还会 merge 回索引。

  **对它的正确预期**:它经常回答「视频没有清楚显示」,而这**就是它的价值** ——
  把「我读不出来」升级成「已确认视频里确实没有」。前者是你的失误,后者是一条有据可查的
  边界,可以放心写进「未覆盖 / 存疑」。别指望它总能变出答案,指望它帮你区分这两种情况。
- 仍不可辨才写 `[画面文字不可读 @mm:ss]`。不要猜测补全 —— 一个编造的参数值会让整份
  手册失去可信度。

OCR 自己也会错(「拆解」→「折解」、「剧本」→「刷本」),两者是互补关系。有疑问时
以你自己读帧所见为最终裁决。

**低清源(源视频 ≤480p,帧常只有 512x288)的四条实测纪律**(2026-09-08 hermes 跑 360p 源
中文双语硬字幕视频时发现,经主代理亲读帧复核与独立盲测确认):

1. **OCR 会把画面 UI 文字与硬字幕(尤其中英双语硬字幕)混在同一行输出**——
   引用块必须标注「含硬字幕层」,且要能区分哪些 token 是界面文字(菜单、路径、数值)、
   哪些是字幕(整句口播)。否则读者会把口播/字幕当界面原文,盲测直接报「一段单帧 OCR
   不可能同时以逐字身份含两种来源」。
2. **同一画面多次扫描(普通抽帧 + `ask` 触发的 dense_resample)结果冲突时,
   多数一致的那组优先**;单次出现的异常 token(例:目录名 `models/unet` 只出现一次,
   而三列复扫都读 `models/Diffusion model`)按误读写进正文,但保留为「若…再试」的
   备选说明,别把话说死。另注意 OCR 会吞下划线:`diffusion_models` 常读成
   `Diffusion model`,正文给可执行目录名时要补回下划线并说明依据。
3. **PLAYBOOK 引用块里的帧时间戳必须落在该步骤的区间内**(validate.py 查不出
   这条)——盲测实测抓到把 [02:55] 的启动器帧引文放进标称 [02:16–02:26] 的步骤 1:
   内容对得上主题、对不上步骤,手册的「可回查」承诺当场破功。
4. **源分辨率要先查 formats 再定预期**:帧分辨率可能远低于引擎的 720p 上限
   (360p 源 → 512x288 帧),抽帧前看 `yt-dlp --dump-single-json` 的 formats,
   最高只有 360p 就提前告诉自己要密集复扫小字,别等帧出来才发现糊。

---

### 2.4 盲测(操作型必做,不是可选的质量加分)

写完 PLAYBOOK **就做这一步**,不要留到最后。派一个 subagent,只给它 PLAYBOOK
(不给转录、不给帧),让它复述操作并列出卡住的地方。

实测这一步在一份看起来完整的手册里揪出 3 处硬伤,包括「验证」小节里一条基于算术错误的
诊断公式(`10×24+1=241`,而实际 `frame_count` 是 65),会把读者引向去改 fps ——
正是手册本身明令禁止的操作。这类错误你自己读不出来,因为你知道视频里是怎么做的;
盲测代理不知道,所以它会卡住,而卡住的地方就是缺口。

缺口回补优先 `ask <engine_video_id> "<缺口词组>"`;`ask` 解决不了才定点重抽。

**完成判据**:盲测代理能一路走到最后一步,剩下的疑问全部落在「未覆盖 / 存疑」小节里。

---

## 阶段 2.4 · 可复现盲测(操作型必做)

> 质量控制那节写着「见阶段 2.4」,而**这一节此前根本不存在** ——
> 一个被列为必做、却从没被定义过的步骤。2026-08-08 补。

```bash
python3 <skill_dir>/scripts/blind_prep.py "<笔记目录>" video-distill-workspace/blind
# 隔离出一份看不到答案的副本(只留 PLAYBOOK.md、移除截图嵌入),并打印标准提示词
# 隔离目标别放 /tmp —— §固化配置外的纪律:中间产物放 /tmp 会被系统清掉(2026-08-08 丢过整轮数据)
```

把隔离目录交给一个**干净的 subagent**,用脚本打印的提示词。
**必须禁止它上网、禁止它读隔离目录以外的文件** ——
**一个能偷看的盲测,测的是偷看能力。**

### 首次实测的威力(对象是一份 `validate.py` 打满分的手册)

| 盲测报出 | 我的复核 |
|---|---|
| Triton 版本约束「像是编的」 | ✅ **正是我故意种进去的已知错误** ⇒ 仪器灵敏度过关 |
| 步骤 12/13 时间区间重叠、拼不成时间线 | ✅ 真的重叠 **124 秒**,已落成检查 |
| 「根目录**不是** python_embeded」与后面三步互相打脸 | ✅ 真的自相矛盾 |
| 装 xformers 再卸载会动到 torch,手册零提示 | ✅ 真实风险 |
| 手册里残留一个空代码块 | ✅ **是我修笔记时留下的垃圾** |
| 结论:**不能**独立完成,硬停在步骤 11 | 缺 workflow 来源 / 模型文件名 / 访问地址 |

它一次报出 **21 条缺信息 + 18 条可疑**。

> **`validate.py` 满分 ≠ 手册可用。**
> 它查结构、时间戳、hash;**查不出你有没有读对画面、有没有把话说全**。

### 两条纪律

1. **盲测发现的东西,凡是能机械判定的就落成 `validate.py` 检查。**
   盲测昂贵(要派一个 agent),不该让人在同一个坑上发现第二次。
2. **盲测报的「可疑」要逐条复核,不要照单全收。** 它也会错 ——
   但它错的成本是你多查一次,而漏报的成本是一份坏手册出厂。

## 阶段 2.5 · 类型判定

| type | 判据 | 产出 |
|---|---|---|
| 操作型 | 有可复现的软件/工具操作 | 产出 PLAYBOOK |
| 理论型 | 只讲原理、观点、方法论 | **不产出 PLAYBOOK**,改为「要点卡 + 自测题」并入主笔记 |
| 混合 | 兼有 | PLAYBOOK 只覆盖实际演示的部分 |

不要为了凑齐三件套而编造操作步骤 —— validate.py 会检查 type 与实际产出一致。

短视频(<10 分钟且知识点少)允许三层合并为单文件,不建目录三件套。

---

## 阶段 3 · 写入 Obsidian(第二个确认点)

### 目录与命名

```
$NOTES_ROOT/<分类>/<slug>/
├── <清洗后标题>.md      # 主笔记,入口
├── PLAYBOOK.md          # 条件产出
├── EXTEND.md
├── transcript.md
└── assets/              # mm-ss-描述.jpg
```

- `slug`:`yt-<视频ID>` / `bili-<BV号>` / `local-<文件名hash>`(可读,与引擎 id 不同)
- 文件名清洗:替换 `/ \ : # ^ [ ] |`,上限 80 字符,不含 emoji
- 互链用**完整路径 wikilink**:`[[视频笔记/编程开发/yt-xxx/PLAYBOOK|操作手册]]` ——
  各视频目录下 PLAYBOOK/EXTEND 同名,短链接会指向错的文件
- 时间戳锚点:YouTube `&t=<秒>s`;Bilibili `?t=<秒>`(多 P 加 `p=N`);本地文件降级为
  纯文本 `[mm:ss]`

### 步骤

1. 基于实际内容最终确认分类与标题(与阶段 0 初判不符就在此修正),连同 slug、
   是否覆盖一并确认。这是最后一个计划内确认点。
2. 用 `templates/` 三件套填空,合并各段草稿,检查段间术语与编号一致,拷入 `transcript.md`。
3. EXTEND 默认精简模式(自身知识 + 官方文档链接);WebSearch 仅在阶段 0 勾选时启用。
   扩展内容一律标 `[扩展]`,且不带时间戳 —— 时间戳是「视频里说过」的凭据,混进扩展层
   就分不清哪些话是讲者说的了。
4. 语言:正文中文,术语/命令/代码保留原文,首次出现给中译;非中文视频的关键论断附原文引述。
5. **重跑保护**:写入时把正文 hash 存进 frontmatter `content_hash`。重跑时重算,
   不一致即视为被人工改过 → 写 `*.regen.md` 列出差异交用户裁决,不要直接覆盖。
   (不要用 mtime 判断,Obsidian 插件会改 mtime。)
6. **运行校验并贴出结果**:
   ```bash
   python3 <skill_dir>/scripts/validate.py "<笔记目录>"
   ```
   有 ERROR 就修到通过再交付;WARN 逐条说明为何可接受。
7. 逐项自报 checklist 完成状态。

---

## 阶段 4 · 可选蒸馏(默认不执行,征询用户)

处理完成后由用户决定。分流按阶段 2.5 的类型判定:**操作内容走 PLAYBOOK 固化,方法论内容
走 cangjie**——两条路线不混用,也不必都跑(cangjie 与本 skill 是上下游关系,各自独立迭代,
经 transcript 契约衔接,勿把它的流程并入本文档)。

- **方法论型 / 混合型的方法论部分** → cangjie-skill 蒸馏成技能包。交接契约
  (2026-09-08 对全新视频全流程实测,记录见仓库 `docs/experiments/cangjie-stage4-2026-09-08.md`):
  1. 输入只有 `transcript.md` **原始转录**,不是笔记 —— cangjie 的 V1 验证要求「原文至少
     2 处独立佐证」,笔记是二次压缩产物:两处「佐证」可能是同一时刻的两次转述(V1 假阳性),
     笔记的遗漏会被当成原文的完整(覆盖率门失效)。时间戳转录正好充当能力卡
     `source_evidence` 的定位凭据。
  2. 随转录交三样元信息:**标题 + 作者 + 发布日期**(目录命名与审计用)。
  3. 环境契约:cangjie 脚本依赖 PyYAML 且文档未声明——系统 python 下连 `doctor` 都起不来;
     本机用 watch-skill venv 的 python(自带 yaml)执行 `scripts/cangjie.py`。
  4. 编译产物装机到 `~/.claude/skills/<name>/`(Hermes 则带 category 层)。编译器硬闸门
     会拦断链产物;`also_read` 写 slug 或 capability_id 均可(上游 2026-09 已修复
     双形态兼容,含 impact_analysis;旧版本地仍建议 slug)。
  5. 装机后必补触发测试(`scripts/trigger_test.py`,双对照纪律不变)——
     这是整条「视频 → skill」链路目前唯一未闭环的一环。
- **操作型** → PLAYBOOK 固化为项目内 skill(写 SKILL.md frontmatter + 带排除清单的触发
  描述,装机后同样补触发测试。此路线尚无实测记录,首个试点可用任一现有 PLAYBOOK)。

**清理时序**:证据帧已拷 assets、transcript 已存档、用户无追加问题 → 才允许清理
`$WORK`。引擎自己的下载缓存由 LRU 管理,不要手动删。

---

## 质量控制

1. **证据规则**:每条视频知识点必须有语音或画面证据并附时间戳;辨认不清必须标注。
2. **可复现盲测**:见阶段 2.4 —— 操作型视频的必做步骤,不在这里重复。
3. **降级透明**:任何降级写进 frontmatter `degradations` 与文首信息块 —— 字幕缺失走
   whisper、纯视觉、源被降采样到 720p、跳段、OCR 关闭、索引不可用。

---

## 错误处理

| 场景 | 处理 |
|---|---|
| 拿到机翻英文轨 | 核对 info.json `language`,重跑并显式指定原生语种 |
| 完全无字幕 | 本地 mlx whisper(无 key、无体积上限)。这是常态而非异常 |
| 源 >720p 且含代码/界面 | 阶段 0 就要本地高清文件。**没有 cookie 方案,引擎硬性不支持** |
| 需登录 / 地区限制 | 提示提供本地文件,不绕过 |
| 帧文字不可读 | OCR 交叉校验 → `ask` 免模型回补 → 定点重抽 → 仍不可读则标注 |
| 会话中断 | `.drafts/` 断点续跑,只补缺失段 |
| mlx 权重缺失 | 回退 `WATCHSKILL_WHISPER_MODEL=medium WATCHSKILL_WHISPER_BACKEND=ctranslate2`,记入 degradations |
| 引擎异常 | 记录复现命令;必要时按 README 的退路切回 claude-video |

---

## 典型调用

```
用 video-distill 把这个视频沉淀成笔记:https://www.bilibili.com/video/BVxxxx
```

阶段 0 确认一次 → 阶段 1 全片转录(13 分钟视频约 40 秒)→ 阶段 2 cue 定位 + 定点抽帧
→ 阶段 3 确认一次后写入 + 校验。

计划内确认 2 次;查重命中、需新建分类、需本地高清文件会各追加一次,最坏约 5 次。

---

## 附带资源

- `templates/NOTES.md` · `templates/PLAYBOOK.md` · `templates/EXTEND.md` — 产出模板,填空用
- `scripts/validate.py` — 分层校验,阶段 3 必跑
- `scripts/blind_prep.py` — 盲测隔离器(阶段 2.4),只留 PLAYBOOK 并打印标准提示词
- `scripts/trigger_test.py` — 触发准确性(阶段 4 装机后必跑,强制已知对照)
- `evals/trigger-evals.json`(9 正 / 11 负)· `evals/evals.json` — 触发与执行评测样例
- `references/engine-internals.md` — 引擎内部行为与实测数据。想改动上面任何一条规则前先读它

Files in this skill

  • SKILL.md34.7 KB
  • evals/evals.json752 B
  • evals/trigger-evals.json3.3 KB
  • references/engine-internals.md11.7 KB
  • scripts/blind_prep.py3.4 KB
  • scripts/trigger_test.py11.6 KB
  • scripts/validate.py24.6 KB
  • templates/EXTEND.md1.8 KB
  • templates/NOTES.md3.1 KB
  • templates/PLAYBOOK.md1.9 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…