# 2026-05-16 Agent健身房复盘
一句话概括:**这次发现的不是已经自动修复的问题,而是 5 类以后会反复浪费时间的操作摩擦 / 工具缺口。**
| 优先级 | 发现的问题 | 真实含义 | 计划怎么解决 |
| --- | --- | --- | --- |
| 1 | 英文歌词卡没有制卡前对齐门禁 | 音频来源、完整 MP3、LRC 时间轴和卡面文本只要有一处错,用户就会学到“前一句音频 + 后一句歌词”的坏卡。 | 做 `lyrics_anki_alignment_gate.py`:导入前检查权威 MP3、LRC 行号、切片来源、Anki media 引用和多端播放风险。 |
| 2 | Anki 的 live 状态和本地构建状态经常不一致 | `.apkg` 导入不一定更新 note type;字段、模板、flag、排期、媒体都必须查 live Anki,否则容易误以为已修好。 | 做统一 `anki_live_maintenance` 工具:备份、字段审计、模板同步、红旗清理预览、新卡打乱和媒体扫描。 |
| 3 | 歌曲 MP3 下载 skill 还缺机器可读验收链 | 下载 55 首时已经出现首轮只中 22 首、缺号、短音频、错候选等问题;没有门禁会把错误素材带进制卡。 | 硬化 `song-mp3-download`:manifest、candidate audit、缺号/时长/失败原因 QA JSON 和非零退出码。 |
| 4 | Get笔记 URL 抓取失败点太多但还没 doctor | 同一链路里会卡在登录、会员权限、平台路由、短链异步、重复创建、note_id 类型和正文回读。 | 给 `crawl-hub` 加 `doctor getnote-url`:分阶段检查 auth、quota、provider、save、poll、readback 和重复笔记。 |
| 5 | 订阅源治理需要先快照再审计的固定模式 | Reddit 操作涉及账号状态、当前总数、join/leave 接口差异和 7 天后复盘;没有审计很难知道到底改了什么。 | 沉淀 `subscription-hub-audit`:before/after 快照、变更 CSV、对象级验收和 Reddit API 注意事项。 |
## 下一步
| 顺序 | 先做什么 | 为什么 |
| --- | --- | --- |
| 1 | 先做英文歌词制卡对齐验收器 | 这是最直接的学习质量风险,昨天已经出现多次音频/文字错位和来源用错。 |
| 2 | 抽出 Anki live 维护工具 | 钢琴、英语概念、英文歌词都在用 Anki;统一工具能复用备份、审计和复核逻辑。 |
| 3 | 把歌曲 MP3 下载 skill 补成可复跑门禁 | 它是英文歌项目的上游供应链;先保证源 MP3 正确,再进入歌词制卡。 |
| 4 | 给 crawl-hub 增加 Get笔记 doctor | Get笔记已经接入多个平台 URL,doctor 能减少以后每次平台抓取失败时的排障成本。 |
| 5 | 把订阅源治理写成轻量工作流 | 这是低风险高复用模式,适合先写 AGENTS/skill 约定,再按需要补脚本。 |
## 证据详情
### 1. 英文歌词制卡对齐验收器
这个主题有效,不是噪音:多个片段都指向同一个根因链路,即音频来源不权威、MP3 不是完整歌曲、缺少带时间戳歌词,导致切片音频和卡面歌词整体错位。后续 AnkiWeb 媒体同步问题说明它不只是一次制卡 bug,而是需要进入英文歌 Anki 制卡流水线的验收门禁。
| 证据 | 片段 |
| --- | --- |
| `019e311d-8c32-7302-ba70-8c49a17df074` | 用户把卡型简化成“背景音乐是那个人唱的那一句,正面同时多挖几个空”,说明核心体验依赖音频片段和正面歌词严格一致。 |
| `019e311d-8c32-7302-ba70-8c49a17df074` | 用户追问“的音频对应的就是那个正面的文字吗?”随后指出“你大概整体错位了一下,音乐还是前一句,卡片是后一句”。 |
| `019e311d-8c32-7302-ba70-8c49a17df074` | 用户判断根因:“这个是因为我的MP3文件不是完整的歌的原因吧?你是不是只要拿到完整的歌和带着时间戳的歌词,就能比较准的做切分了?” |
计划改动:
- 在 `/Users/bytedance/Documents/learning-bu/english/04-projects/英文歌项目/tools/lyrics_anki_alignment_gate.py` 新增 CLI 工具入口:`python tools/lyrics_anki_alignment_gate.py --source-dir <权威MP3目录> --lrc <song.lrc> --deck <cards.csv|apkg解包目录> --media-dir <collection.media>`;输入来源包括用户指定的权威 MP3 目录、完整 `song.mp3`、带时间戳的 `song.lrc`、生成后的卡片表和 Anki 媒体目录。
- 核心检查步骤写进 gate:解析 LRC 得到 line_id/time/text;解析卡片正面 cloze 文本和 `[sound:xxx.mp3]`;对每张卡计算卡面歌词与 LRC 行的文本相似度,再用音频切片的起止时间或文件名 metadata 回查它来自哪一行;检测 `audio_line_id == text_line_id`,并显式标出 `audio_line_id = text_line_id - 1` 这种“音乐前一句、卡片后一句”的整体错位。
- 成功/失败信号落地为 `out/lyrics_alignment_report.json` 和可打开的 `out/lyrics_alignment_report.html`:PASS 条件是 MP3 来源命中 manifest、每张卡音频行与文本行一致、媒体文件存在且大小合理、无同名冲突;FAIL 条件包括缺完整歌、缺 LRC、来源目录不匹配、前后句错位、最后一句无对应音频、Anki media 引用缺失或多端同步风险。
### 2. Anki实时牌组维护工具箱
这个主题不是噪音:多个片段都指向同一类问题,即 Anki 的真实状态不等于本地 .apkg/脚本状态,必须通过 AnkiConnect 对 live Anki 做字段、模板、卡片排期、媒体引用和清理结果的闭环验证。价值在于把反复出现的手工排障动作沉淀成一个统一维护工具,降低误以为导入成功、误删、误改复习排期或漏检媒体缺失的风险。
| 证据 | 片段 |
| --- | --- |
| `019e30c6-955f-7aa1-a607-53ed363ea232` | 给钢琴五线谱认音 deck 加倒计时时,`.apkg` 导入保留了 88 张卡,但 Anki 没有自动更新现有 note type 的字段和模板。agent 必须直接走 AnkiConnect 的 note type 更新接口,把字段、正反模板和样式写入 live Anki。 |
| `019e30c6-955f-7aa1-a607-53ed363ea232` | 用户要求倒计时从 6 秒改成 2 秒。agent 发现抽样卡的 `TimeLimitSeconds` 没读到值,不能只改文件,需要重新跑模板/字段同步,并最终复核 88 张卡、抽样 10 张字段都是 `"2"`。 |
| `019e3098-f3e2-7971-81b5-312a07c4dc2d` | 英语概念卡红旗清理:用户以为 context 为空,agent 备份后发现 Anki 里的 `Context` 不是字面空值,而是 `<mark>单词</mark>` 或 URL 参数片段。最终删除 10 个 note,并复核 `deck:"英语概念卡" flag:1` 为 0。 |
计划改动:
- 在 `/Users/bytedance/Documents/learning-bu/tools/anki_live_maintenance/` 新增一个 CLI 工具,入口建议为 `python -m anki_live_maintenance doctor --deck <deck>`;统一封装 AnkiConnect 连接检查、备份导出、note/card 查询、字段抽样、模板读取和媒体扫描。
- 给工具增加 `sync-notetype` 子命令:输入为目标 deck、note type、字段定义、card template 和 CSS 文件;执行前读取 live note type 状态并生成 diff,执行后用 AnkiConnect 复核字段存在、模板版本和样本 note 字段值,失败时输出需要重跑的具体步骤。
- 给工具增加 `field-audit` 和 `cleanup-preview` 子命令:专门处理类似 `Context` 非字面空值、flag 清理、字段值缺失的问题;默认先导出备份和 dry-run 清单,再允许按 note id 删除或更新,最后复核查询条件为 0 或字段命中率达到预期。
### 3. 歌曲MP3下载 skill 验收链
这是一个高价值主题,不是噪音:同一任务里已经出现了页面点击、接口逆向、跨平台候选补齐、短音频替换、缺号校验和最终 skill 沉淀。现有 `song-mp3-download` skill 已覆盖基础下载和 `--check-only`,但验收链仍需要硬化为机器可读、可复跑、能解释失败原因的交付门禁。由于音乐来源、LRC 和站点接口会反复用于学习素材供应链,值得把这套经验固化为稳定工具。
| 证据 | 片段 |
| --- | --- |
| `019e316d-d6eb-7a21-8b46-1940e21069a1` | 用户要求按 `抖音-sdhdxh` 歌名逐个去 Tonzhon 下载 MP3,并提醒 `你要不browseruse点击`。agent 先从页面 JS 找到 `/api/ss?keyword=...` 和 `/api/p/{newId}`,又用浏览器确认下载入口会弹登录框。 |
| `019e316d-d6eb-7a21-8b46-1940e21069a1` | 第一轮只下载到 22 首,失败项包括站点搜不到正确歌或候选不给音频源。随后发现站内并行搜歌接口 `/api/s/{q\|m\|n\|k}/...` 覆盖 QQ/咪咕/网易/酷我,才补齐更多候选。 |
| `019e316d-d6eb-7a21-8b46-1940e21069a1` | 校验阶段发现主层少了 54 号,还发现 5 首音频小于 45 秒;agent 继续探测候选真实时长,用更长同名音源替换,最后验收为 55 首、缺失 0、小于 45 秒 0、总大小 239M。 |
计划改动:
- 改 `/Users/bytedance/Documents/learning-bu/.agents/skills/song-mp3-download/SKILL.md`:新增 `Mandatory Acceptance Gate` 小节,把最终交付定义为 `expected_count == final_mp3_count`、期望序号缺失 0、`missing_or_unmatched.tsv` 只有表头、`short_under_45s == 0`、manifest 行数等于成功文件数;明确没有过门禁前不能宣称完成。
- 改 `/Users/bytedance/Documents/learning-bu/.agents/skills/song-mp3-download/scripts/download_tonzhon_mp3.py`:增强 `--check-only`,增加 `--source-dir` 或 `--expected-count/--expected-indices`、`--min-duration`、`--qa-json` 参数;缺号应基于源歌单序号而不是仅基于输出文件数量推断,并输出 `qa_report.json`/非零退出码作为自动验收信号。
- 改同一脚本的候选记录链路:为每首歌保存 `candidate_audit.tsv`,记录 `/api/ss` 与 `/api/s/{q,m,n,k}` 的候选数量、被过滤原因、最终 `newId`、远程时长、bytes、source_url host;失败时能区分 `no_search_result`、`no_audio_source`、`short_audio`、`ambiguous_artist`、`download_error`。
### 4. Get笔记 URL 抓取路由诊断
这个主题有效:片段显示 Get笔记链路已经从账号权限、OpenAPI smoke、异步 URL 处理、crawl hub provider 路由到真实小红书短链抓取形成了完整问题面。最值得沉淀的是一个 crawl hub doctor,用来区分账号权限、CLI 登录、provider 路由、异步任务等待、note_id 类型和内容回读等失败点。
| 证据 | 片段 |
| --- | --- |
| `019e30fa-c9d1-7d32-b234-f589d8e90c31` | Get笔记登录后第一次真实 OpenAPI 读操作被服务端拒绝,notes、kbs、quota、search、save 都返回 403 / code 10201 / reason: not_member。 |
| `019e30fa-c9d1-7d32-b234-f589d8e90c31` | 用户开通会员后,agent 重新 smoke:getnote auth status、notes、kbs、quota、search、创建临时笔记、读回、删除都成功,并特别记录 save 返回有数字型 id 和字符串型 note_id。 |
| `019e30fa-c9d1-7d32-b234-f589d8e90c31` | B 站 URL 保存时出现异步等待:Get笔记正在处理这个普通 URL... 再等一轮;如果继续无响应,我会中断这次保存并用 task/最近笔记确认有没有实际创建,避免重复写入。 |
计划改动:
- 新增工具入口:在 crawl hub CLI 或 scripts 中增加 `crawl-hub doctor getnote-url <url>`,输入来源为用户传入 URL、当前 getnote auth 配置、crawl hub provider registry、最近一次 task/note 查询结果;输出一份分阶段诊断报告。
- 核心检查步骤:先运行 `getnote auth status`,再依次检查 `quota`、`kbs`、`search`、临时笔记 create/read/delete;如果出现 403 / 10201 / not_member,直接判定为账号 OpenAPI 权限问题,而不是继续重试 URL provider。
- provider 路由检查:根据 URL 域名识别公众号、抖音、小红书/xhslink、小宇宙、B站等平台,确认命中 `getnote-url` provider;对短链先记录解析/等待状态,对普通 URL 记录 save 返回的数字 id 与字符串 note_id,并统一以后续 string note_id 回读。
### 5. 订阅源治理先快照再审计
这个主题有明确复用价值:它不是一次性 Reddit 操作,而是一套适用于订阅源、信息源、知识源治理的变更闭环。关键模式是先用真实登录态刷新当前快照和账号,再做待变更清单、执行变更、记录接口细节,最后用数量和具体对象双重验收。
| 证据 | 片段 |
| --- | --- |
| `019e309d-19ce-77f0-a554-d9b0c9937045` | Reddit 当前订阅先从 Chrome 登录态刷新 `reddit.com/subreddits/mine`,可见账号 `Exciting_Radio8947`,页面标题显示 `HOME FEED SUBREDDITS (51)`;agent 把这次实时页面刷新落成当前快照。 |
| `019e309d-19ce-77f0-a554-d9b0c9937045` | 用户要求取关 8 个泛科技/低信号源并加入 10 个实践者社区。agent 先验证账号、当前 51 个社区和 modhash,再执行变更,最终验收为取关 8/8、加入 10/10、Home feed 51 -> 53。 |
| `019e309d-19ce-77f0-a554-d9b0c9937045` | 执行中踩到旧 Reddit API 细节:加入可以用名字,取关第一次接口调用没有生效;后来发现取关必须传 subreddit 内部 `t5_...` id,才补做成功。 |
计划改动:
- 修改 `/Users/bytedance/Documents/info-bu/AGENTS.md`:新增“订阅源/信息源治理”工作约定,要求所有加入、取关、迁移、清理操作先记录账号、来源页面、当前总数、当前清单快照,再执行变更和验收 delta。
- 新增 skill `/Users/bytedance/.codex/skills/subscription-hub-audit/SKILL.md`:入口为“治理 Reddit、RSS、YouTube、Newsletter、GitHub watch/star 等订阅源”;流程固定为登录态确认、快照导出、变更清单审计、执行、数量+对象验收、7 天复盘。
- 新增工具脚本 `/Users/bytedance/Documents/info-bu/tools/subscription_audit/reddit_subscriptions.py`:输入 Chrome 登录态 cookie 或手动导出的当前订阅 JSON、目标 join/leave CSV;核心逻辑包含 modhash/CSRF 获取、name 到 `t5_...` fullname 解析、join/leave 执行、before/after JSON 审计报告。