# 3.9 自我调优、留出集与门禁

> 关于模型名：代码里请求的是 `deepseek-v4-flash`（AI Builder Space 接受的名字，见 `lib.py`）。DeepSeek 在 2026-09-10 发布 V4.1 Flash 时退役了 V4 Flash，旧名字 `deepseek-v4-flash` 的请求由 DeepSeek-V4.1-Flash 处理（DeepSeek API 文档的 Change Log）。本实验在 2026-10 运行，所以文中一律写作 deepseek-v4.1-flash。

> 状态（2026 年 10 月）：中文版完成。设计见 `CONTRACT.md`。

## 问的是什么

- 3.9：让一个强模型对着一份小评估集，自动改便宜模型的纠错提示词。它在评估集上的进步，有多少能延续到没见过的数据上？
- 门禁（原 3.11，2026-10-19 并入 3.9）：给这个循环加一道门禁，门禁应该怎么设？门禁会不会挡掉真正的进步？

## 数据和指标

- `items_zh.json`：164 条，每条是原始转写（`raw`，Grok 识别、不给词表）和标准答案（`truth`）。38 条来自模块 2 的合成备忘录（`experiments/corpus/`），126 条来自 3.7 合成例会的台词（每句单独转写，`build_items.py`）。
- `names_zh.md`：人名术语表，和纠错 skill 一起交给纠错模型。
- 指标（`lib.py` 的 `score_item`）：只看人名术语表里的 21 个词。一个词在标准答案里出现几次，输出里就应该出现几次；写对的数量（按出现次数封顶）记为写对，多出来的记为乱改。分数 =（写对 − 乱改）/ 标准答案里应写对的总数。不区分大小写，忽略空格。

## 基线与噪声（3.2、3.4 用到的数字）

- `baseline.py` → `baseline_zh.json`：原始转写 94/269，分数 0.35；`skill_v0_zh.md`（名单加一句话）+ deepseek-v4.1-flash：写对 254/269，乱改 40，分数 0.80。这次运行里扣分最多的是 M053（模型把一句英文台词当成提问，用英文回答并列出了全部 21 个人名术语）和 M025（模型回了一段中文分析，把 Priya 写了 7 次）。
- `noise.py` → `noise_zh.jsonl`：同一份 skill 在 164 条上连跑三遍。v0：0.870、0.744、0.881；调优器第 2 轮写出的版本（`runs/zh_ungated_1/skill_r02.md`）：0.933、0.929、0.933。

## 自我调优（3.9）

- `autotune.py`：纠错模型 deepseek-v4.1-flash（AI Builder Space，temperature 0）；调优器 gpt-6.1-sol（ChatGPT 订阅 OAuth，推理强度 high）。元提示是 `meta_prompt_zh.md`：给出当前 skill、人名表、调优集分数和调优集上每一条失败（原始转写、输出、正确答案、漏写和乱改的词），要求写出新的 skill 全文。没有提醒它不要过拟合。
- 每个种子把 164 条随机分成调优集 24 条（调优器看得到）、留出集 60 条、测试集 80 条（调优器都看不到）。正文把留出集和测试集合在一起称为没见过的 140 条。
- 不设门禁（`runs/zh_ungated_{1,2,3}/`），每轮都接受，跑 8 轮。每一轮的 skill 在调优集和没见过的 140 条上各跑三遍（第一遍来自 `log.json`，另两遍由 `curve_reeval.py` 补跑，`curve_reeval_zh.json`），取平均后再对三个种子平均（`curve_ungated_zh.json`）：

| 轮 | 调优集 | 没见过的 140 条（三种分法的最低–最高） | 单次运行的最低–最高 | 提示词长度（字） |
|---|---|---|---|---|
| 0 | 0.874 | 0.820（0.800–0.839） | 0.702–0.877 | 72 |
| 1 | 0.975 | 0.879（0.838–0.912） | 0.798–0.913 | 1,138 |
| 2 | 0.997 | 0.904（0.874–0.923） | 0.855–0.926 | 1,727 |
| 3 | 0.994 | 0.912（0.903–0.921） | 0.903–0.922 | 2,095 |
| 4 | 0.997 | 0.911（0.903–0.923） | 0.895–0.926 | 2,405 |
| 5 | 0.997 | 0.907（0.892–0.921） | 0.886–0.922 | 2,641 |
| 6 | 0.984 | 0.906（0.884–0.917） | 0.877–0.918 | 3,027 |
| 7 | 0.994 | 0.907（0.897–0.922） | 0.881–0.922 | 3,294 |
| 8 | 1.000 | 0.907（0.892–0.919） | 0.890–0.922 | 3,371 |

- 解读：起点 v0 很不稳定（单次 0.70–0.88，原因是偶尔把转写当成提问来回答）；前三轮把没见过数据上的分数从 0.820 提到 0.912，并把单次波动收窄到 0.903–0.922；第 4 到 8 轮停在 0.906–0.911，提示词从 2,095 字涨到 3,371 字。
- 更正：初稿用的是每轮单次运行的数字，起点恰好落在 v0 的高位（0.87），因此一度把提升写成 4 个点，并把种子 3 第 1、2 轮的单次结果读成倒退。三遍平均后两点都不成立。
- 抄题：先从文本里去掉人名术语本身（避免术语名撞上），再看调优集条目的原文或标准答案里，有没有任意连续 10 个字符原样出现在第 8 轮的 skill 里。脚本 `copy_check.py zh`：种子 1 有 5 条，种子 2 有 2 条，种子 3 有 2 条；没见过的条目 0 命中。英文版 `copy_check.py en`（连续 8 个词）：2 / 3 / 2 条，没见过的条目 0 命中。

## 门禁（3.9 后半）

同样的种子和切分，每轮的提议要过门禁才生效；没通过时保持原版本，并告诉调优器提议被拒（不透露留出集内容）；连续 3 次被拒就停。

| 门禁 | 规则 | 种子 1 | 种子 2 | 种子 3 |
|---|---|---|---|---|
| 严格（`gatedstrict`） | 留出集分数不降，且留出集里原来全对的条目一条都不能变错 | 3 轮全拒 | 3 轮全拒 | 3 轮全拒 |
| 单次基准（`gated`） | 留出集分数至少高 0.01，新改错的条目不多于新改对的 | 接受第 1、2 轮，第 5 轮停，1,537 字 | 3 轮全拒（起点在这份留出集上偏高：4 次 0.907–0.944，见下） | 接受第 1、3、4 轮，第 7 轮停，2,310 字 |
| 平均基准（`gatedavg`） | 同上，但留出集每次跑两遍取平均 | 接受第 1、2 轮，第 5 轮停，1,906 字 | 接受第 1 轮，第 4 轮停，803 字 | 接受第 2、4 轮，第 7 轮停，1,245 字 |

## 最终版本的公平比较

`final_eval.py` → `final_eval_zh.json`：每个种子下，把各种做法最终停在的 skill 在测试集（80 条，整个过程不参与任何决定）上各跑三遍取平均。

| 版本 | 种子 1 | 种子 2 | 种子 3 | 平均分 | 平均长度（字） |
|---|---|---|---|---|---|
| 起点 v0 | 0.878 | 0.682 | 0.882 | 0.814 | 72 |
| 不设门禁第 2 轮 | 0.911 | 0.896 | 0.912 | 0.906 | 1,727 |
| 不设门禁第 8 轮 | 0.906 | 0.888 | 0.902 | 0.899 | 3,371 |
| 严格门禁 | 0.817 | 0.706 | 0.872 | 0.798 | 72 |
| 单次基准门禁 | 0.824 | 0.565 | 0.952 | 0.781 | 1,306 |
| 平均基准门禁 | 0.924 | 0.893 | 0.942 | 0.920 | 1,318 |

门槛 0.01 的来历：每个种子的留出集里有 95 到 108 处人名术语，错一处分数变化约 0.01，要求至少涨 0.01 等于要求至少多改对一处。单次基准门禁在种子 1 停下的版本不稳定（测试集三遍为 0.687、0.893、0.893）；在种子 2 停在 v0：v0 在种子 2 的留出集上 4 次运行是 0.907、0.944、0.926、0.926，始终偏高，而测试集上 12 次都不超过 0.80。原因是划分：基线运行里扣分最多的 M053（多写 21 处）和 M025（7 处）都落在种子 2 的测试集，v0 在留出集上只多写 4 处、测试集上 33 处，留出集对 v0 偏简单。平均两遍的门禁在种子 2 上基准是 0.926，第 1 轮提议 0.954 过线；平均能抹平单次波动，抹不平划分偏差。（2026-10-20 核对，见 `runs/zh_*_2/log.json`、`final_eval_zh.json`、`baseline_zh.json`。）

## 文件

- `build_items.py`、`items_zh.json`、`meeting_lines_raw_zh.json`：数据。
- `lib.py`：打分和调用纠错模型。
- `baseline.py`、`noise.py`、`autotune.py`、`final_eval.py`：实验脚本。
- `runs/<做法>_<种子>/`：每一轮的 skill（`skill_rNN.md`）、打分明细（`results_rNN.json`）、日志（`log.json`）、切分（`split.json`）。

## 成本

纠错模型每轮 164 到 224 次调用（平均门禁多跑一遍留出集），全部实验加起来两万多次调用，按 deepseek-v4.1-flash 的单价估算，费用在几美元的量级。调优器走订阅，不计费。
