docs: 归档翻译上下文/字幕审校方案的评审结论与实测数据
- 待办:会话式长上下文方案标记为已技术评审且不实施;补记问题 A 的阶段性结论(暂缓) - 新增 docs/实验数据-字幕审校定位与修复实验.md:LLM 定位触发率/召回、合成正样本、逐条修复前后对照、成本与复现方式 - 新增 docs/实验数据-字幕重生成成本与耗时.md:单价口径、功率画像、全量推算 - decisions:补充两条决策(会话式长上下文否决、审校定位+定向修复暂缓) - scripts:归档一次性探测脚本 probe_subtitle_review_stage0.py(含 rebuild 子步骤) - AGENTS/README:补充实验与改动许可规则、文档索引
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
# 待办:翻译上下文复用与语义纠错
|
||||
|
||||
本文件记录**尚未解决**的问题与用户给出的需求规格,供后续对话接着做。
|
||||
已完成的改动见 git 历史(分支 `master` 上的 `fix/review-improvements` 合并结果)。
|
||||
|
||||
---
|
||||
|
||||
## ⛔ 方案状态:已技术评审,**不实施**
|
||||
|
||||
「一、需求规格」与「五、落地这个需求时需要先想清楚的点」所描述的**会话式长上下文
|
||||
方案经技术评审否决,后续不要再按本方案修改代码**。结论与依据见
|
||||
[decisions.md](./decisions.md#翻译会话式长上下文方案否决):
|
||||
|
||||
1. **前提不成立**:需求 5 假设"长上下文能让模型发现并改掉语义错",但本文件自己
|
||||
记录的两次实验(纠错节点 ±60s 上下文、加强提示词 A/B)全部失败。错因是 ASR
|
||||
听岔、语境里没有声学证据——加长上下文只是增加同类证据,不能修掉问题 A。
|
||||
2. **成本放大 3×~70×**:会话式每批原样重发全部历史(随批数二次增长),该档 Qwen
|
||||
在 SiliconFlow 无 cached-input 折扣(价格表缓存列为 `-`);按实测口径推算,
|
||||
剩余 187 小时素材的 API 费用从 ¥5.5–9.4 涨到约 ¥300–400。
|
||||
3. **压缩阈值踩计费档**:`>150k 触发` 跨过 `[128k,+∞)` 档(输入 ¥0.4→¥1.6、
|
||||
输出 ¥3.2→¥12.8,整请求按 4× 计价),阈值应低于 128k。
|
||||
4. **与现有不变式/机制冲突**:文件夹级可变共享状态(节点只经产物 URI 交换、每
|
||||
run 独立产物目录)、批量非 GPU 阶段并行(共享会话要求按文件夹串行)、"暂停后
|
||||
整节点重跑、不留半成品"的暂停语义,都要新增子系统并改动语义。
|
||||
|
||||
本文件**保留为需求与问题记录**(问题 A/B/C、需要知道的坑、数据现状仍然有效)。
|
||||
问题 A 的可行方向(ASR 侧低置信度 + 文件夹级热词二次解码等)**尚未评审、未决定**,
|
||||
需要修时另行提出方案与代价。
|
||||
|
||||
---
|
||||
|
||||
## 一、需求规格(用户 2026-09-19 明确)
|
||||
|
||||
1. **翻译阶段要复用对话**:不再每批(20 条)都是无状态独立请求,而是把同一视频的
|
||||
多批放进同一个会话上下文里,让模型能看到前面译过的内容。
|
||||
2. **文件夹级共享上下文**:同一文件夹下的多个视频(同番号多集)共用一个上下文,
|
||||
让各集之间复用信息(人名、称呼、场景设定等)。
|
||||
3. **术语稳定**:因为共用上下文,整片/整文件夹的人名、专名、称呼能固定下来,
|
||||
不因批次不同而漂移。
|
||||
4. **上下文压缩规则**(小模型上下文有限):
|
||||
- 上下文占用 **超过 150k** 时触发压缩;
|
||||
- 压缩对象主要是**前 100k**:调用 LLM 对前 100k 做总结,**重点保留名字、场景**等信息;
|
||||
- **后 50k 原样保留**,避免丢失"与当前高度相关"的近期信息。
|
||||
5. 预期收益:模型在长上下文里更容易发现"语义不顺/与前后矛盾"的句子,从而修掉
|
||||
下面的问题 3(ASR 听岔成"成句但语义错")。
|
||||
|
||||
---
|
||||
|
||||
## 二、现状(代码事实,2026-09-19 核对)
|
||||
|
||||
| 事实 | 位置 |
|
||||
| --- | --- |
|
||||
| 翻译按 `CHUNK_SIZE=20` 分块,**每块一次独立请求**:请求体只有 `system` + `user` 两条消息,无历史、无跨批信息 | `nodes/llm.py::translate_lines` / `_translate_batch` / `_call_llm` |
|
||||
| 动态提示词**按批计算**:本批正文命中词表才追加规则;同一视频其它批次命中的词不会带过来 | `nodes/llm.py::_translate_batch` + `nodes/proper_nouns.py::build_proper_noun_rule` |
|
||||
| 一批的"上下文"只有本批 20 条(约 1–2 分钟对话) | 同上 |
|
||||
| 译文**整批返回并入库**(不是只取目标句):`_parse_translations` 要求返回的 id 集合与请求完全一致,缺项/多项/重复/空文本都判失败并重试 3 次 | `nodes/llm.py` |
|
||||
| 纠错节点是**逐条调用**、输出中文译文(不是改日语),未接入任何工作流 | `nodes/subtitle_correction.py`(`workflows/*.json` 中无引用) |
|
||||
|
||||
---
|
||||
|
||||
## 三、问题清单
|
||||
|
||||
### 已解决(供参考,不必再动)
|
||||
|
||||
| # | 问题 | 处理 | 证据 |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | whisper 重复伪影(30 秒被同一单元填满;短时 3.7 秒填 111 个假名) | 清洗规则删除(长条 ≥15s 且重复 ≥6 次;或重复 ≥20 次) | `nodes/subtitle_cleanup.py::remove_repetition_entries` |
|
||||
| 2 | 静音段幻觉(`こんにちは`/`おはようございます`/`東京都交通局8800形電車`…) | 开启 `hallucination_silence_threshold=2.0` + `word_timestamps`(工作流 v3);片头 120 秒由 15 条降到 4 条 | 见 `data/experiments/regen_plan/REPORT.md` 第九节 |
|
||||
| 3 | 批量任务被误标 COMPLETED(明细写入竞态) | 任务先以 `CREATING` 入库,明细写完才置 QUEUED;启动清理遗留 | `src/wov_app/batch.py::create_job` |
|
||||
| 4 | 历史产物损坏:CN 里出现"无正文的 cue",下一条的序号+时间轴被吸进正文(ASS 同源损坏,播放器加载失败) | 全库 112 个:85 个旧字幕随重跑修好;27 个新字幕 + 1 个命名特例已单独重做 | 见本文件"四、数据现状" |
|
||||
|
||||
### 未解决(本次对话的核心遗留)
|
||||
|
||||
**问题 A:ASR 把词听岔成"语法通顺但语义错"的句子,中文照字面直译**
|
||||
|
||||
实例(`kiwvr-886/masex.tv@kiwvr00886_2_8k.mp4`,00:15:45–00:16:20):
|
||||
|
||||
| 产品里的 JA(错) | 复核后的 JA(两个模型一致) | 现译(错) | 实际含义 |
|
||||
| --- | --- | --- | --- |
|
||||
| `じゃあ、ママの声をおなかに入れますね` | `じゃあ、まままんこにおなほに入れますね` | 那我让妈妈的声音进入你肚子里了哦 | 那妈妈用小穴(把它)套进去哦 |
|
||||
| `写真してもこんなにカチカチなんですね` | `射精してもこんなにカチカチなんですね` | 也会变得这么僵硬呢 | 就算射了也还是这么硬呢 |
|
||||
| `あくまで、あくまでください` | `奥まで、奥までください` | 再吃一个,再吃一个吧 | 再深一点,再深一点 |
|
||||
| `あくまで入ってしまいました` | `奥まで入ってしまいました` | 它已经全都进来了 | 已经顶到最里面了 |
|
||||
| `生鼻を使わさせていただきますね` / `口紋かでもご奉仕` / `生おなほ` / `おなほまんこで` | 均为 オナホ/マンコ 一类词的走音 | — | — |
|
||||
|
||||
已实测**失败**的修法(不要再重复试):
|
||||
|
||||
| 尝试 | 结果 |
|
||||
| --- | --- |
|
||||
| 纠错节点(`Qwen/Qwen3.6-35B-A3B` 与 `Qwen/Qwen3.5-35B-A3B`,±60s 上下文) | 均输出"那我把妈妈的声音放进肚子里哦"——**没改对** |
|
||||
| 加强提示词 A:"语义不合常理/与动作链矛盾即判为误听" | 仍保留"声音" |
|
||||
| 加强提示词 B:"上下文反复出现 オナホ/マンコ/チンポ;同位置的怪词应改写" | 仍保留"声音"(只把"身体/肚子"换了个说法) |
|
||||
| 审校节点:LLM 定位问题 cue + 定向修复(输入日文原文 + 现有译文 + ±2 邻句 + 系列词表) | 定位召回 0/3(仅中文)~ 1/3(加日文);修复依次输出"声音传送到身体里""继续吃""已经完全进去了",**仍全部保留错译**,另有脑补改坏 |
|
||||
|
||||
上述失败实验的完整数据(定位触发率/合成正样本召回/逐条修复前后对照)与
|
||||
原因分析见 [实验数据-字幕审校定位与修复实验.md](./实验数据-字幕审校定位与修复实验.md)。
|
||||
|
||||
**问题 B:翻译无跨批/跨视频上下文**(对应上面"需求规格"要解决的对象)。
|
||||
直接后果:一批里同时出现多处坏转写时(`写真しても`、`あくまで`×2),模型既无整片
|
||||
术语线索、也看不到前后动作链,只能按字面翻译。
|
||||
|
||||
**问题 C:`_call_llm` 不重试网络错误**。实测云端 API 偶发"挂住 600 秒读超时"
|
||||
(2/634 批,两批集中在同一分钟),直接把整段翻译判失败、视频白跑一遍。
|
||||
用户明确选择**暂不修**,留待后续决策;全量 349 个约 5000 次调用,按此失败率会有
|
||||
10–20 个视频需要重跑(重跑方式:建库级任务,缺字幕的视频会自动判 PENDING)。
|
||||
|
||||
### 需要知道的坑
|
||||
|
||||
- **任务行的 `updated_at` 会被读操作刷新**:`GET /api/batch/jobs*` 会触发
|
||||
`sync_batch_job_progress` 重算并写回时间戳,统计耗时请用日志的"批量任务 … 完成"行
|
||||
或明细的 `updated_at`,不要用任务行。
|
||||
- **产物损坏的根因**:某一步"只删正文行、留下空 cue",后续解析器把下一条的
|
||||
序号+时间轴当成正文吸走。产出端(当前 pipeline)已验证不会再产生:`serialize_srt`
|
||||
对空正文会写空行,`clean_srt_text` 也能正确处理空文本 cue。
|
||||
- **`savr-1054/…_1_8k` 的产物名曾带 `666` 后缀**(`…_1_8k666.CN.srt`),批量引擎按
|
||||
"文件名含视频主名"仍能匹配,但严格按 `<视频名>.CN.srt` 匹配的脚本/播放器会漏掉。
|
||||
|
||||
---
|
||||
|
||||
## 四、数据现状(2026-09-19)
|
||||
|
||||
- 媒体库:`/mnt/fnOS/123`(NAS `192.168.123.199:/vol1/1000/123`),524 个视频 / 287.27 小时。
|
||||
- 待重生成(CN 字幕早于 2026-09-01):**349 个 / 187.86 小时 / 1417.8 GiB**。
|
||||
- 已按新管线重做:20 个样本 + NKKVR-175 两个 + 28 个损坏修复 = 50 个视频。
|
||||
- 每个视频现有产物:`<视频名>.JA.srt`(ASR 后的日语转写)、`<视频名>.CN.srt`、
|
||||
`<视频名>.CN_dual_eye.ass`;旧字幕备份为 `*.old-20260918` / `*.corrupt-20260918`。
|
||||
|
||||
---
|
||||
|
||||
## 五、落地这个需求时需要先想清楚的点(新对话用;**本节方案已否决,不再作为实施依据**)
|
||||
|
||||
1. **会话形态**:把 `messages` 从"system+user"扩成多轮,是把**上一批的 JSON 原文与译文**
|
||||
作为 assistant/user 消息追加,还是只追加"术语表 + 摘要"?前者上下文增长快(每批 ~800
|
||||
tokens),后者省但信息有损。
|
||||
2. **对齐与重试**:现有实现靠"每批独立、id 对齐、失败重试 3 次"保证不错位;改成会话后
|
||||
某批失败/重试会污染会话历史,需要明确回滚策略(例如失败批不写入历史)。
|
||||
3. **压缩触发与实现**:`>150k` 触发、总结前 100k、保留后 50k。要确定 token 口径
|
||||
(用接口返回的 usage 还是本地估算)、总结用哪个模型(同模型/更便宜的模型)、
|
||||
总结产物如何缓存复用(同一文件夹复用意味着总结要能跨视频复用)。
|
||||
4. **文件夹级共享**:按文件夹串行处理是前提(当前批量引擎是分组的,同组视频可能并行),
|
||||
否则两个视频同时读写同一会话会互相污染;还要定义文件夹内视频的处理顺序。
|
||||
5. **暂停/断点续跑**:run 恢复时上下文是否重建?重建口径(从已有 CN.srt 复原历史?)。
|
||||
6. **成本与限额**:长上下文会显著抬高输入 token(每批都带上历史),要重算
|
||||
`docs/实验数据-字幕重生成成本与耗时.md` 里的单价;注意不少接口对超长输入有倍率价。
|
||||
7. **与现有清洗/词表的关系**:`subtitle_cleanup`(重复伪影/寒暄幻觉/短呻吟)与
|
||||
`proper_nouns`(词表规则)仍然保留,会话上下文是补充而非替代。
|
||||
8. **验收用例**:至少覆盖本次的 `kiwvr-886_2` 00:15:45–00:16:20 那段——目标句应译成
|
||||
"那妈妈用小穴(把它)套进去哦"这类含义,而不是"声音进入肚子";同时不能把正常句
|
||||
改坏(例如呻吟/短句不应被"脑补"成新意思)。
|
||||
|
||||
## 六、问题 A 的阶段性结论:暂缓(模型能力不足)
|
||||
|
||||
已实测过两条路子,均不能解决问题 A:
|
||||
|
||||
1. **翻译侧审校**(LLM 定位问题 cue + 定期修复:输入日文原文 + 译文 + ±2 邻句 +
|
||||
系列词表)。实测:定位召回 0/3(只给中文)~ 1/3(加上日文);修复后仍保留错译,
|
||||
且出现无依据脑补改坏正常句。**有效的只有术语/忠实性类**(如 `阴道`→`小穴`)。
|
||||
2. **硬规则定位**(词表违背 + 近音匹配):严格口径目标召回 0/3,宽松口径命中率
|
||||
48.6% 全是假阳性——硬规则泛化不了,不作为定位手段。
|
||||
|
||||
原因:`字面通顺但语义错`的句子中文本身读得通,模型没有怀疑动机;即使怀疑,
|
||||
可依据的日文原文也是错的,模型只能沿错译换词。**判定为当前 LLM 能力不足,暂缓。**
|
||||
|
||||
实测数据、成本与复现方式:
|
||||
[实验数据-字幕审校定位与修复实验.md](./实验数据-字幕审校定位与修复实验.md)。
|
||||
若将来重开,应把方向挪回 **ASR 侧**(只审日文/给候选读法/先建场景再对照),
|
||||
那里才有声学证据;三个可测方向见该文档第六节。
|
||||
|
||||
## 七、相关代码与文档
|
||||
|
||||
- 翻译节点:`nodes/llm.py`(`translate_lines` / `_translate_batch` / `_call_llm` / `_system_prompt`)
|
||||
- 审校实验脚本(一次性,已归档):`scripts/probe_subtitle_review_stage0.py`
|
||||
- 词表规则:`nodes/proper_nouns.py`(`PROPER_NOUNS` / `ONOMANOPOEIA` / `ADULT_EUPHEMISMS`)
|
||||
- 纠错节点(原型,未接入):`nodes/subtitle_correction.py`
|
||||
- 清洗规则:`nodes/subtitle_cleanup.py`
|
||||
- 批量引擎:`src/wov_app/batch.py`、资源门控 `src/wov_app/resources.py`
|
||||
- 决定性样本与提示词快照:`data/experiments/regen_plan/prompt_dump/`
|
||||
- 全量实测记录:`data/experiments/regen_plan/REPORT.md`
|
||||
- 成本与耗时:`docs/实验数据-字幕重生成成本与耗时.md`
|
||||
Reference in New Issue
Block a user