# Benchmark Eval Harness — 运行说明 > v1.9.0 起使用的模型实跑入口;2026-07-11 起改盲测口径(见下节)。 > Prompt 本体见 `./rewrite-prompt.md` 和 `./judge-prompt.md`。 > 这份 README 只解决"具体怎么跑一次"。 ## 盲测口径(2026-07-11 起) 旧口径的问题:被测模型直接读 `evals/benchmark.md`,每条用例的 `预期` / `理由` 就在原文旁边,编号前缀(SF / SNF)和标题也暴露该改还是不该改——测出来的是 instruction-following,不是规则在陌生文本上的泛化。 现口径: - 被测模型只读 `evals/benchmark-blind.md`:匿名编号(B-xx)、顺序打乱、只含场景和原文。 - judge 用 `evals/benchmark-map.md` 把 B-xx 映射回 SF/SNF 编号,再按 `benchmark.md` 的预期判分。 - 两个盲测文件由 `python3 automation/eval/make_blind.py` 生成(固定种子,可复现);`benchmark.md` 用例增删后必须重跑,手改生成文件无效。 - 隔离靠 prompt 路径纪律约束,不是硬隔离;如需硬隔离,可在干净目录只放 `SKILL.md`、`references/`、`benchmark-blind.md` 再跑(v2.2.0 起 hard_metrics 需要 `evals/benchmark-blind.md` 解析原文,硬隔离目录须包含它)。 ## 文件约定 工具本体(committed): | 角色 | 路径 | |------|------| | 被测模型改写 prompt | `automation/eval/rewrite-prompt.md` | | 交叉判分 prompt | `automation/eval/judge-prompt.md` | | 盲测生成脚本 | `automation/eval/make_blind.py` | | 硬判脚本 | `automation/eval/hard_metrics.py` | | 盲测输入(生成物) | `evals/benchmark-blind.md` | | 盲测映射表(生成物) | `evals/benchmark-map.md` | | 运行说明 | `automation/eval/README.md`(本文件) | 运行实例(local-only,`tasks/` 在 `.gitignore` 内): | 角色 | 路径 | |------|------| | Codex 改写输出 | `tasks/current/eval-runs/-codex/rewrite-.md` | | Claude 改写输出 | `tasks/current/eval-runs/-claude/rewrite-.md` | | Claude 判 Codex | `tasks/current/eval-runs/-judge/claude-judge-codex-.md` | | Codex 判 Claude | `tasks/current/eval-runs/-judge/codex-judge-claude-.md` | 第一次使用前先建目录: ```bash mkdir -p tasks/current/eval-runs/2026-06-18-codex \ tasks/current/eval-runs/2026-06-18-claude \ tasks/current/eval-runs/2026-06-18-judge ``` ## 批次划分 默认按 5 批跑(盲测编号连续切段,每批 SF/SNF 天然混排): | batch | 区间 | |-------|------| | `B01-16` | B-01 到 B-16 | | `B17-32` | B-17 到 B-32 | | `B33-48` | B-33 到 B-48 | | `B49-64` | B-49 到 B-64 | | `B65-82` | B-65 到 B-82 | 新增或补跑用例可以单独成批:targeted 补跑先查 `benchmark-map.md` 找到对应 B 编号,按 B 编号下发给被测模型(不要把 SF/SNF 编号透给被测模型),输出命名可用 `targeted-vX.Y.Z`。历史批次(v1.9.x 的 `SF01-14` 等命名)是盲测前的旧口径,归档不改。 如果模型或供应商的上下文 / 输出限制跑不下 5 批之一,可以继续细拆,例如把 `B01-16` 拆成 `B01-08` 和 `B09-16`。文件名保持区间可读即可,最终汇总时按原区间合并。 交叉判分固定为: - Codex 改写 → Claude 判 - Claude 改写 → Codex 判 ## 硬判(v2.2.0 起) 改写输出落盘后、跑判分前,先对每个运行目录跑一遍硬判脚本,把 judge 不再自己数的判定项(字数留存率、破折号密度、protected spans 粗核)批量算出来: ```bash python3 automation/eval/hard_metrics.py --run tasks/current/eval-runs/-final/ ``` - 扫 `/` 下所有 `rewrite-*.md`(按 `codex/`、`claude/` 子目录区分模型),自动配对 `evals/benchmark-blind.md` 原文逐条计算;旧口径批次(v1.9.2 的 `rewrite-SF43-45-SNF34-35.md` 命名)自动配对 `evals/benchmark.md` 的 SF/SNF 用例。 - 输出 `/hard-metrics.md`(可读报告)和 `/hard-metrics.json`(机器可读),两者都是运行产物,不入 commit。 - 长文留存率只对 `public-writing / long / in-place` 用例判定(目标 ≥ 0.90、硬下限 0.85);bounded 长文与 no-op(保留原文)不适用留存率判据。任一用例低于硬下限时脚本退出码为 1。 - no-op 校验:声明保留原文的用例会核对「判定链有力度=no-op 证据」或「正文≈原文」;两者都没有(假 no-op)标 `noop_unverified` 并按实际留存率判,不让一句「保留原文」吞掉长文硬失败。正文附原文的 no-op 按 100% 记(包装字如「处理结果:/保持原文:」不计入分子)。 - 退出码:0 = 全部批次解析完整且无硬下限失败;1 = 有硬下限失败;2 = 自身错误或报告不可信(路径缺失、零用例批次、缺输出、单条缺文件等)。 - 破折号密度对单段 ≥ 4 处 `——` 或输出首句仍以 `——` 起手报警(SF-43 信号)。 - protected spans 粗核逐字检查数字、版本号、路径、反引号片段等(中文紧贴如 `耗时20ms`、`版本v1.8.0` 也能命中),缺失只报警不判死,交给 judge 复核(bounded 删除清单内的无源论断按规则删掉不算漂移)。 单条对照(调 prompt 或 debug 时用): ```bash python3 automation/eval/hard_metrics.py --pair <原文文件> <改后文件> python3 automation/eval/hard_metrics.py --stdin <原文文件> < 改后.txt python3 automation/eval/hard_metrics.py --pair <原文> <改后> --report-json --scene "public-writing / long / in-place" ``` 单条模式自动剥模型输出里的 `## B-xx` 标题和「处理结果:」前缀,只对正文判;`--scene` 带上 `long / in-place` 标签时才会输出留存率判据(没有场景标签时留存为 `null`,只算破折号与粗核)。 判分时把 `hard-metrics.md` 的对应数字提供给 judge(见 `judge-prompt.md`),judge 不再自己数长文留存。 ## 改写批 Codex 改写一批: ```bash codex exec -C . -s read-only --ephemeral \ -o tasks/current/eval-runs/-codex/rewrite-B01-16.md \ '你正在执行说人话 benchmark 盲测改写实跑。 请完整读取 ./automation/eval/rewrite-prompt.md,按其中 text 代码块里的 prompt 行事。 只使用当前工作目录下的 ./SKILL.md、./references/ 和 ./evals/benchmark-blind.md;禁止读取 ./evals/ 下的其他文件,不要读取全局安装的 shuorenhua skill 副本。 本轮只处理 ./evals/benchmark-blind.md 中 B-01 到 B-16。 请直接输出最终结果,不要附加过程叙述。' ``` Claude 改写一批: ```bash claude --print --model opus \ --name shuorenhua-eval-rewrite-B01-16 \ --disallowedTools Edit Write \ > tasks/current/eval-runs/-claude/rewrite-B01-16.md <<'EOF' 你正在执行说人话 benchmark 盲测改写实跑。 请完整读取 ./automation/eval/rewrite-prompt.md,按其中 text 代码块里的 prompt 行事。 只使用当前工作目录下的 ./SKILL.md、./references/ 和 ./evals/benchmark-blind.md;禁止读取 ./evals/ 下的其他文件,不要读取全局安装的 shuorenhua skill 副本。 本轮只处理 ./evals/benchmark-blind.md 中 B-01 到 B-16。 请直接输出最终结果,不要附加过程叙述。 EOF ``` 其余批次只替换区间和输出文件名。 ## 判分批 Claude 判 Codex 改写: ```bash claude --print --model opus \ --name shuorenhua-eval-judge-codex-B01-16 \ --disallowedTools Edit Write \ > tasks/current/eval-runs/-judge/claude-judge-codex-B01-16.md <<'EOF' 你正在执行说人话 benchmark 交叉判分。 请完整读取 ./automation/eval/judge-prompt.md,按其中 text 代码块里的 prompt 行事。 只使用当前工作目录下的 ./evals/、./SKILL.md、./references/ 和被测输出文件,不要读取全局安装的 shuorenhua skill 副本。 盲测区间:B-01 到 B-16 被测输出:./tasks/current/eval-runs/-codex/rewrite-B01-16.md 请直接输出判分表和汇总,不要重写被测输出。 EOF ``` Codex 判 Claude 改写: ```bash codex exec -C . -s read-only --ephemeral \ -o tasks/current/eval-runs/-judge/codex-judge-claude-B01-16.md \ '你正在执行说人话 benchmark 交叉判分。 请完整读取 ./automation/eval/judge-prompt.md,按其中 text 代码块里的 prompt 行事。 只使用当前工作目录下的 ./evals/、./SKILL.md、./references/ 和被测输出文件,不要读取全局安装的 shuorenhua skill 副本。 盲测区间:B-01 到 B-16 被测输出:./tasks/current/eval-runs/-claude/rewrite-B01-16.md 请直接输出判分表和汇总,不要重写被测输出。' ``` 其余批次只替换区间、被测输出和输出文件名。 ## 小样试跑 调 prompt 时先跑小样,不要直接上全量: ```bash mkdir -p tasks/current/eval-runs/-smoke codex exec -C . -s read-only --ephemeral \ -o tasks/current/eval-runs/-smoke/rewrite-B01-08.md \ '请完整读取 ./automation/eval/rewrite-prompt.md,按其中 text 代码块里的 prompt 行事。 只使用当前工作目录下的 ./SKILL.md、./references/ 和 ./evals/benchmark-blind.md;禁止读取 ./evals/ 下的其他文件,不要读取全局安装的 shuorenhua skill 副本。 本轮只处理 ./evals/benchmark-blind.md 中 B-01 到 B-08。 请直接输出最终结果,不要附加过程叙述。' claude --print --model opus \ --name shuorenhua-eval-smoke-judge \ --disallowedTools Edit Write \ > tasks/current/eval-runs/-smoke/judge-B01-08.md <<'EOF' 请完整读取 ./automation/eval/judge-prompt.md,按其中 text 代码块里的 prompt 行事。 只使用当前工作目录下的 ./evals/、./SKILL.md、./references/ 和被测输出文件,不要读取全局安装的 shuorenhua skill 副本。 盲测区间:B-01 到 B-08 被测输出:./tasks/current/eval-runs/-smoke/rewrite-B01-08.md 请直接输出判分表和汇总,不要重写被测输出。 EOF ``` 小样只看格式是否可对照: - 每条改写输出都有 `## <编号>`。 - 每条都有固定判定链。 - judge 只输出固定三列表格。 - 汇总里有 SF 通过、SNF 误杀、⚠️ / ❌ 清单。 如果格式不顺,最多改 prompt 后再跑一轮;第二轮仍不顺就停下,不要继续全量。