---
name: transcription-corrector
homepage: https://github.com/cat-xierluo/legal-skills
author: 杨卫薪律师（微信ywxlaw）
version: "1.0.7"
license: MIT
description: 转录稿纠错与轻度优化。本技能应在用户需要按用户词典纠正 ASR 转录稿同音字与英文专有名称漂移时使用。不要用于：重写为课程章节、报告、总结，或完全空白的素材创作。
---

# Transcription Corrector

> 首次使用流程见 [references/first_use.md](references/first_use.md)。工作流中的判断准则见 [references/correction_patterns.md](references/correction_patterns.md)。

## 概述

把 raw 转录稿里"听得对但写不对"的同音/形近/拼写错误按用户词典统一改对，并按需做轻度润色。**不做**：改写、总结、删减、改事实、生成课程章节。

| 模式 | 触发 | 输出 |
|---|---|---|
| **纠错模式（默认）** | 拿到 raw 转录稿，要先做"校对" | `archive/.../{原文件}_corrected.md` + 校对对照日志 |
| **纠错 + 轻度润色** | 还要顺手把发言人合并/标点整理 | 在纠错基础上再润色，输出到 `archive/.../{原文件}_polished.md` |

**与下游处理工作的边界**：
- 本 skill 不输出课程大纲、不重组章节、不改写为书面课程；只做"读起来对、不再丢脸"这一步。
- 用户词典 YAML 格式（`version` + `terms` 列表）已成为本 skill 公开的接口约定；其他下游处理工作可以按需读取同一份词典文件。

## 工作流程

工作流按 **5 个 Phase** 组织，每个 Phase 含 1-3 个 Step。默认开启 Phase 1-3，Phase 4 默认关闭（需要用户明确开启）。

```
Phase 1 准备
  Step 1.1  读取配置（词典）
  Step 1.2  TXT → MD 转换（如需要）

Phase 2 识别
  Step 2.1  识别文件结构
  Step 2.2  通读识别高置信误转写

Phase 3 修正（默认开启）
  Step 3.1  词典统一替换（改字）
  Step 3.2  基础空白清理（改空白）
  Step 3.3  口语词精简（删字）

Phase 4 润色（默认关闭）
  Step 4.1  发言人合并
  Step 4.2  标点规范
  Step 4.3  段落切分

Phase 5 输出
  Step 5.1  主归档（必出）
  Step 5.2  源文件目录镜像（必出）
```

**为什么这样分组**：
- **Phase 1 准备** vs **Phase 2 识别** vs **Phase 3 修正**：准备不接触文本内容；识别是"看"；修正是"改"。三者性质分明
- **Phase 3 内部三个 Step** 改的是三类不同对象：3.1 改字（语义）、3.2 改空白（格式）、3.3 删字（语言字符）。三类操作各自独立，可单独审计
- **Phase 3 vs Phase 4**：Phase 3 是"读起来对"（无损 / 轻损），默认开启；Phase 4 是"看起来专业"（结构调整），默认关闭。两者泾渭分明
- **Phase 5 输出** 与前 4 个 Phase 解耦：无论前 4 步做了什么，输出阶段都按相同策略双写

---

## Phase 1：准备

### Step 1.1：读取配置

1. 词典文件查找顺序（找到第一个存在的即用）：
   - 命令行/调用参数传入的 `dictionary` 路径
   - `config/user_dictionary.yaml`（本 skill 自带）
   - 若都不存在，提示用户复制 `config/user_dictionary.example.yaml` 为 `config/user_dictionary.yaml`

2. 词典 YAML 格式：

```yaml
version: 1
terms:
  - "WorkBuddy"
  - "Claude Code"
  - "Codex"
```

3. 词典的角色：**目标值 + 置信度权重**，不是触发器
   - 词典项是"正确写法"——告诉 AI 目标值是什么
   - 词典项**不直接触发替换**：AI 仍然必须先做上下文判断（这个词在当前上下文里是否指向词典项所代表的对象）
   - 词典项**提高候选替换的胜出权重**：当 AI 在多个候选写法中二选一时，词典登记的写法优先级更高
   - 也就是说：词典让"workbody / work body / Workbuddy"在竞争中更倾向被改写为"WorkBuddy"，但前提仍然是上下文明显指向 WorkBuddy 这个产品；脱离上下文的同形词不会被词典"硬拉"过去
   - **不要**把词典当作"错误词 → 正确词"映射表来使用
   - **不要**为了使用词典而强行替换普通词
   - 模糊或低置信场景一律保持原文

### Step 1.2：TXT → Markdown 转换（如需要）

当输入是 `.txt` 文件时，先做格式转换再进入 Phase 2。

**触发条件**：输入文件扩展名是 `.txt`。

**转换规则**（保守——只做格式包装，不改内容）：

1. **发言人 + 时间戳行**（如 `发言人 1  00:33:09`）：
   - 识别正则：`^(发言人|说话人|Speaker|S)\s*[\d一二三四五六七八九十]+[\.、]?\s*(\d{1,2}:\d{2}(?::\d{2})?)$`
   - 转成 Markdown 加粗行：`**发言人 1  00:33:09**`
2. **段落间空行**：连续的非空行视为同一段（保留原始换行），段落之间补一个空行
3. **不删除任何文字**：空行、空白、ASCII 装饰线（`---`、`===`）等全部保留
4. **不识别标题层级**：不主动把某段升级为 `#`/`##`——下游做章节重组时再处理
5. **不识别列表**：不把 `- xxx` 改成 markdown 列表——保持原样

**输出**：
- 中间产物：`{原文件 basename}_converted.md`，保留在 archive 子目录
- 后续 Step 2.1~5.2 在 converted 副本上进行
- 原始 `.txt` 文件保持不动

**示例**：

输入（`raw.txt`）：

```
发言人 1  00:33:09
我先说一下比较好的部分，就是整个最终的报告篇幅是比较充分的。
然后大家在一开始不知道怎么样一个报告是比较完善的，也知道怎么样去借鉴他山之石。
从这个阿尔法 gpt里面的这报告相当于蒸馏他的一个一个想法啊。
这个这个在前期一开始搭基建的时候确实是很有必要的一个措施。

发言人 1  00:33:57
呃然后。我注意到咱们在最终生成法律服务意见书的时候...
```

输出（`raw_converted.md`）：

```markdown
**发言人 1  00:33:09**
我先说一下比较好的部分，就是整个最终的报告篇幅是比较充分的。
然后大家在一开始不知道怎么样一个报告是比较完善的，也知道怎么样去借鉴他山之石。
从这个阿尔法 gpt里面的这报告相当于蒸馏他的一个一个想法啊。
这个这个在前期一开始搭基建的时候确实是很有必要的一个措施。

**发言人 1  00:33:57**
呃然后。我注意到咱们在最终生成法律服务意见书的时候...
```

**不识别的格式**（保持原文）：
- 没有时间戳的"发言人 1："→ 保留为正文
- "Speaker A:" → 保留为正文
- 纯文本无发言人标记 → 整段视为正文

---

## Phase 2：识别

### Step 2.1：识别文件结构

通读 raw 稿，识别组织方式：

- **按发言人 + 时间戳分块**（如 `**发言人 1  00:33:09**`）— 多数 ASR 输出
- **自由段落**（无显式分块）
- **混合**（标题 + 段落 + 引用）

识别目的：决定 Phase 4 润色时是否合并同发言人连续发言。**不要改写分块结构**，保留原貌。

### Step 2.2：通读识别高置信误转写

**必须完整通读全文**，以 Agent 视角扫描。**不列静态错误表**——ASR 错误无穷无尽（大小写漂移、空格、漏词、错位、同音字、形近字、断词重连、音节吞并…），任何预设列表都会漏判。

**核心原则**：
> **仅在上下文明确指向某个词典术语时，才将近似误转写替换为该术语。**
> **模糊或低置信场景保持原文，不做猜测式替换。**

**启动扫描的高频易错类别**（不是错误表，是判断启动点）：

1. **人名**：律师、当事人、证人姓名是否首次出现 + 后续引用是否一致
2. **英文产品/工具/平台名**：是否在工具使用、命令行、平台介绍等场景
3. **机构/活动/品牌名**：律协、青训营、训练营、赛题
4. **法律术语同音/形近**：代理 vs 带理、抵押 vs 抵压、知情 vs 至清
5. **数字/单位/时间戳**：1/7、0/6、中英文逗号混用；**保守原则**

**形式漂移识别**（参考但不穷举）：

- 大小写漂移（WorkBuddy vs workbuddy vs WORKBUDDY）
- 空格漂移（work body / Work Buddy）
- 连字符（Claude-code / Claude-Code）
- 拆分被识别为中文（"克劳德 code"）
- 漏字残字（"body" 残留在"让，如果 body帮我们"）
- 同音/形近字（"张律师 / 张老师 / 章律师" 类推）
- 断词重连（"然后让" 被拆成"让，如果"）

**禁止**：
- 只用 grep/正则匹配清单（必然漏）
- 把"我"改成"我们"等无明确对照的"风格化"改写
- 替换词典外的术语
- 强行补全"看上去缺字"的句子——除非能确定是组合错误

---

## Phase 3：修正（默认开启）

> Phase 3 三个 Step 改的是**三类不同对象**——Step 3.1 改字（语义）、Step 3.2 改空白（格式）、Step 3.3 删字（语言字符）。三类操作各自独立、可单独审计、单独计日志。

### Step 3.1：词典统一替换

对 Step 2.2 识别出的高置信误转写：

1. **三重确认**：
   - 词典里有对应目标值
   - 上下文明确指向该目标值所代表的对象
   - 形式漂移证据成立（大小写/空格/连字符/漏字/同音/形近/断词）
2. 三重任一不满足 → **不替换**，保持原文
3. 替换完成后在 correction_log.md 记录：`{原文}` → `{改后}`，并标注行号和上下文片段
4. **绝不修改原始文件**，所有输出写到 archive/ 下的新文件

### Step 3.2：基础空白清理（默认开启，无损）

**为什么独立于 Phase 4 润色**：基础空白清理是"格式标准化"，不改变原文语义、不删减任何信息；与 Phase 4 发言人合并 / 标点规范 / 段落切分那种"风格调整"性质不同，所以默认开启（用户不需要为此做开关决策）。

**清理动作清单**（仅做以下五类，不做任何超出此范围的事）：

| 类别 | 动作 | 触发条件 |
|---|---|---|
| 行首/行尾空白 | 删除 | 任意行 |
| 连续空行 | 压缩为单个空行 | 任意位置 |
| 全角/半角空格 | 统一为半角空格 | 出现在英文单词之间或英文标点旁 |
| 专有名称内部断裂空格 | 合并 | 上下文明确指向词典中的专有名称（如"Work Buddy" → "WorkBuddy"） |
| 中文数字 + 空格 + 级/章/节 | 合并 | 模式：`[一二三四五六七八九十百千]+ +级/章/节` 合并为 `[一二...]+级/章/节`（如"二 级" → "二级"） |

**标点周围空白规则**：
- 中文标点 `，。、；：？！""''「」（）` 前后不留空格（若出现则删除）
- 英文标点 `, . ; : ? ! " ' ( )` 后空一格（中文段落中保留）
- 半角空格夹在中文之间 → 删除

**严格不做**（避免越界）：
- 不删除任何文字、标点、字母、数字
- 不改变段落结构（不合并段落、不切分段落——这是 Phase 4 范畴）
- 不修改数字、时间戳、金额、日期
- 不改发言人分块标记（如 `**发言人 1  00:33:09**`）
- 不重排、重组、归纳

**与 Step 3.1 的关系**：基础空白清理在 Step 3.1 词典替换之后执行；遇到"Work Buddy" → "WorkBuddy" 这类专有名称合并时，优先走 Step 3.1（词典替换路径），Step 3.2 仅做 Step 3.1 不覆盖的"无词典目标的纯格式"清理。

**校对日志记录**：所有 Step 3.2 的清理动作也写到 `correction_log.md`，在"基础空白清理"小节集中记录（与 Step 3.1 高置信替换区分开），便于审计。

### Step 3.3：口语词精简（默认开启，AI 上下文判断）

**为什么独立于 Phase 4 润色**：与 Step 3.2 基础空白清理性质相同——属于"读起来对"的范畴，不改变原意（口语词不携带信息）；与 Phase 4 发言人合并 / 标点规范 / 段落切分那种"风格调整"性质不同，所以默认开启（用户不需要为此做开关决策）。

**白名单（可删的纯填充词）**——AI 通读时识别"作为填充词 vs 作为实义"，仅删独立出现且无语义负担的：

| 词 | 典型位置 | 删除条件 |
|---|---|---|
| 呃 | 段中独立 / 句首 | 认知停顿，不构成回答 |
| 啊 | 段中独立 / 句末 | 感叹停顿 |
| 哦 | 段中独立 | 过渡停顿（不作"明白了"回应） |
| 哎 | 段中独立 | 过渡停顿 |
| 那个 | 独立使用 | 纯指代填充（不指代具体名词） |
| 就是说 | 独立使用 | 纯连接填充 |
| 然后呢 | 段末 | 纯过渡填充 |
| 对吧 | 段末 | 纯反问填充 |
| 你知道吗 | 段中 | 纯引导填充 |
| 怎么说呢 | 段中 | 纯思考填充 |
| 这样子 | 独立使用 | 纯总结填充 |
| 其实呢 | 段首 | 纯转折填充 |
| 但是呢 | 段首 | 纯转折填充 |

**保留规则**（不删）：

- **表态类**："嗯"/"对"/"是的"/"不是"/"好的"/"是" 作肯定 / 否定 / 回应 → 保留（删了会丢失说话人态度）
- **逻辑连接**："然后"作逻辑连接词（"先 A 然后 B"）→ 保留（删了破坏时序）
- **认知停顿后接完整内容**："呃……这个怎么解释呢" 整段保留——"呃"虽属白名单，但"认知停顿 + 完整内容"是说话人思考过程的真实记录，整段保留比逐字删更尊重原文
- **段尾的语气停顿**（"嗯"/"啊"/"呃"出现在段末）——保留（标记说话节奏收束）
- **紧邻关键名词 / 动词**——保留（可能是说话人强调）
- **实义词**（名词 / 动词 / 形容词 / 副词）——一律不删

**段首 vs 段尾 vs 段中 决策树**：

| 位置 | 判定标准 | 处理（v2 激进版起）|
|------|----------|---------------------|
| **段首** | 紧跟 `**发言人 X HH:MM:SS**` 之后第一个非空行的第一个词 | **删除**（v2 起激进）|
| **段中独立** | 句中位置、不是紧邻关键名词/动词 | **删除** |
| **段中并列停顿 啊** | 两个名词/动名词之间 + 顿号/逗号 | **保留**（删除会破坏并列结构）|
| **段尾** | 一段内容末尾的最后一个词 | **保留**（标记节奏收束）|

详见 `references/correction_patterns.md` §11 段中并列停顿 啊 的识别模式。

**判断原则**：
- 与 Step 3.1 一样遵循"通读全文 + 三重确认"思路
- 三重确认：① 该词在当前上下文是否属于白名单词类；② 在当前位置是否独立使用、是否承担实义；③ 删后不破坏说话人态度 / 时序 / 强调
- 任一不满足 → **不删**，保留原文
- 模糊或低置信场景一律保留原文

**严格不做**（避免越界）：
- 不删整句、不删段落
- 不删实义词（即使重复）
- 不删关键信息（数字、人名、专有名、术语）
- 不改写为书面语、不补全、不改语气
- 不删"呃 / 啊"作认知停顿后接完整内容的版本
- 不删"段尾"的关键节奏标记（v2 激进版起，段首节奏标记默认删除）

**校对日志记录**：所有 Step 3.3 的精简动作写到 `correction_log.md` 的"口语词精简"小节，格式：

```
| 行号 | 原文片段 | 被删词 | 理由 |
|------|----------|--------|------|
| L207 | "呃 这个怎么说呢，我们今天来" | "呃" | 段首认知停顿，后接"怎么说呢"+完整内容，整段保留——本行不删（认知停顿后接完整内容的"呃"按 §3.3 保留规则例外）|
| L312 | "对，所以呢，我们" | "所以呢" | "所以呢" 不在白名单，保留 |
| L451 | "然后呢我们看一下" | "然后呢" | 段首过渡填充，可删 |
```

**与 Step 3.2 的关系**：Step 3.2 动空白字符，Step 3.3 动语言字符。两者都是"读起来对"操作，都默认开启，都在 correction_log.md 单独小节集中记录。

**必检（防止漏跑整节）**：跑完必须 grep 自检（详见 `references/correction_patterns.md` §12）：
- `correction_log.md` 必须包含 `## 口语词精简` 小节
- `correction_log.md` 必须包含 `## 高置信替换` / `## 基础空白清理` / `## 口语词精简` / `## 未处理` 四个小节
- `meta.json` 必含 `summary` / `process_time` / `dictionary_source` / `polish_enabled` 字段
- v1.0.2 漏跑 Step 3.3 整节无日志——本必检项是那次 bug 的复盘产物

---

## Phase 4：润色（可选，默认关闭）

润色开关由用户决定。开启后做以下三类最小动作：

| Step | 类别 | 动作 | 边界 |
|---|---|---|---|
| Step 4.1 | 发言人合并 | 同一发言人连续多段、可合并为一段时，合并 | 仅去重分块，**不删任何原话** |
| Step 4.2 | 标点规范 | 中英文标点统一、句末补全 | 不改语气词、不删"呃/啊"等自然语流标记 |
| Step 4.3 | 段落切分 | 极长段（>500字）按语义边界切 | 不重组、不重排、不总结 |

**严格不做**：
- 改写为书面语
- 总结、提炼、删除"啰嗦"内容
- 补全或推测说话人意图
- 改事实、改数字、改时间戳

---

## Phase 5：输出

输出采用 **双写** 策略：主归档在 skill 内部，源文件目录同步一份易访问副本。原始文件保持不动。

### Step 5.1：主归档（必出）

输出位置：`{skill 目录}/archive/{YYYYMMDD_HHMMSS}_{原文件 basename}/`

文件：
- `{原文件}_corrected.md` — 纠错后的完整文本（保留原始分块结构）
- `{原文件}_polished.md` — 仅在用户开启润色时生成
- `correction_log.md` — 校对对照日志
- `meta.json` — 处理时间、词典来源、是否润色、原始文件路径

### Step 5.2：源文件目录镜像（必出）

输出位置：原始文件所在目录（与原文件同目录）。

文件：
- `{原文件 basename}_corrected.md` — 与 5.1 内容完全一致，仅是易访问副本
- 命名规则：原文件名后追加 `_corrected` 后缀，扩展名改为 `.md`（原文件是 `.md` 时，输出仍为 `.md`；原文件是 `.txt` 时，输出为 `.md`）

**为什么双写**：
- 主归档承担"可追溯 + 校对日志 + 元数据"的完整档案职责
- 源文件目录副本让用户在日常文件管理器中能直接看到"已校对版"，免去每次去 skill 内部目录翻找
- 双写的内容是字节级一致的 `_corrected.md`（polished 副本与 log 不镜像——它们的主归档位置就在 skill 内部）

**冲突处理**：
- 源文件目录已存在同名 `_corrected.md` → 用时间戳后缀区分（`_corrected_20260608_153022.md`），避免覆盖历史校对结果
- 源文件目录只读 / 不可写 → 静默跳过源文件目录镜像，仅输出主归档；在 `meta.json` 记录 `source_mirror: "skipped"`
- 源文件路径无法解析（如 stdin 输入）→ 同样静默跳过源文件目录镜像

**原始文件保持不动**——双写策略只生成"新文件"，绝不就地修改原文件。

### Step 5.3：稳定版标记（可选）

当某次跑出的 `_corrected.md` 经用户确认无问题、视为该转录稿的"稳定版"时，在该 archive 子目录下加 `STABLE.md` 标记文件：

```markdown
# Stable Version Marker

**v3 (2026-06-08 12:00) 标记为该转录稿的稳定版本。**

## 为什么 v3 是 stable

- v1.0.0 (2026-06-07 14:30) — 7 处，仅 Step 3
- v1.0.2 (2026-06-08 00:41) — 42 处，Step 3 + 3.5，漏跑 Step 3.6
- v2 (2026-06-08 11:00) — 170 处，补跑 Step 3.6（84 处）
- v3 (2026-06-08 12:00) — 226 处，激进版段首删除（+52 处）

## 锁定本版本

- 后续不再对 `260606_AI技能创新大赛_corrected.md`（v3）做改动
- 源文件目录三个版本并列保留供对比
- 如发现新的误转写需要补判，新建 `archive/<新时间戳>_*` 目录重跑，不就地修改 v3
```

**为什么需要 STABLE.md**：
- archive 目录会累积多轮迭代产物（v1.0.0 / v1.0.2 / v2 / v3 ...），未来 agent / 用户 / 下游 skill 进来不知道哪个是终版
- 源文件目录的镜像文件（`_corrected_v3_20260608_120000.md`）按时间戳命名，本身是"稳定"暗示，但 archive 内部 `260606_AI技能创新大赛_corrected.md` 没 STABLE 标记会被误认成"最新版"
- STABLE.md 让"哪个是终版"显式可查

**什么时候不写 STABLE.md**：
- 一次性试跑、用户没确认 / 校对量少 / 转录稿本身还要后续处理——不必强行标记
- 已经有更新的版本稳定了——避免给旧版加 STABLE 误导下游

### Step 5.4：旧版本清理策略

archive 目录会保留每次跑的全量产物（主归档 + correction_log + meta.json），不主动清理历史版本。但当 archive 下子目录数 ≥ 5 时，建议在 STABLE.md / DECISIONS.md 备注保留策略：

- **保留**：每次的 `_corrected.md` / `correction_log.md` / `meta.json`（记录完整迭代轨迹）
- **可清理**：当 archive 累积 ≥ 5 个目录时，旧的 `analysis_report.md` 等中间产物可手动归档
- **禁止清理**：被 STABLE.md 标记的稳定版目录的 `_corrected.md`（用户可能要从源文件目录镜像之外的路径找回终版）

#### 校对对照日志格式（correction_log.md）

```markdown
# 校对对照日志

- **原始文件**：/path/to/raw.md
- **处理时间**：2026-06-07 14:30:22
- **词典来源**：`config/user_dictionary.yaml`（含 18 项术语）
- **润色开关**：关闭

## 高置信替换

| 原文 | 改后 | 出现次数 | 上下文示例 |
|------|------|----------|------------|
| workbody | WorkBuddy | 3 | "通过第二版呢进行测试..." |
| work body | WorkBuddy | 2 | "我们把这个实践中办案..." |
| claude-code | Claude Code | 1 | "...重新调回那个 claude-code 里面..." |

## 未处理（保留原文）

- "智能件" — 上下文不足以判断是否为"智能体"
- "代理" — 同上

## 润色变更（如开启）

- 合并发言人 1 连续 3 段为 1 段
- ...
```

## 适用场景 / 不适用

见 [references/scope.md](references/scope.md)。

## 配置示例 / 配置解耦原则

见 [references/config-decoupling.md](references/config-decoupling.md)。

## 参考文档

- [references/scope.md](references/scope.md) — 概述 / 适用边界
- [references/config-decoupling.md](references/config-decoupling.md) — 配置示例 / 配置解耦原则（评价规范相关）
- [references/first_use.md](references/first_use.md) — 一次性配置引导（复制 example.yaml、跑试跑、多用户软链）
- [references/correction_patterns.md](references/correction_patterns.md) — 工作流判断准则（误转写识别、口语词精简、并列停顿、必检清单、ASR 高频模式）
- [config/user_dictionary.example.yaml](config/user_dictionary.example.yaml) — 词典公开模板
