git:20260804.852ee11 to git:20260804.4bf5d7a

30 added, 4 removed. Audit A to A.

# 任务级评测 — 设计与预注册
2026-08-04 · 在产出任何数据之前写完并提交。预测写在下面,跑完不改。
机制层的结果见 `research/2026-08-04-focus-hint-eval.md`:230 道单图问答,
五个条件,全部 p ≥ 0.227,零结果。那一层的结论**不外推到本层**,本层也不复用它的题库。
## 为什么换一层测
机制层测的是「同一张图、同一个问题下,换 prompt 能让描述好多少」。它有一个内建的
让步:**每道题都自带一个明确的问题**,问题本身就替代了 hint 和转写条款的一部分
作用——描述侧被告知要找什么之前,答题侧已经知道了。
真实使用不长这样。用户粘一张 CI 失败截图说「修一下」,没人说「请注意第 87 行的
Expected: 4500」。**agent 必须自己决定看什么、看几次、什么时候承认没看清。**
本层测的就是这个,且它能测到机制层测不到的三件事:
1. 描述漏掉的东西,agent 会不会**察觉**并回查(决策日志 #2)。
2. 逐字转写条款防的**静默遗漏**,在没有明确问题时是否真的发生(决策日志 #4)。
3. 任务成败本身。
## 五个条件
Codex 用 `codex exec` 非交互驱动,每个条件一个独立 `CODEX_HOME`
(`~/cdv-task-eval/homes/<condition>/`),**生产配置 `~/.codex/config.toml` 全程只读,
不修改**。除代理端点与 skill 外,配置逐字复制生产设置(模型、reasoning effort、
- `disable_response_storage`、`--codex-header-compat`),因为要测的是用户真实在用的系统。
+ `disable_response_storage`),因为要测的是用户真实在用的系统。代理一律以默认
+ flag 启动(`--codex-header-compat` 与 `--inject-reasoning-summary` 保持关闭)。
+ 密钥经 `env_key` 由环境传入,不落盘。
| 条件 | Codex 指向 | 隔离出的变量 |
|---|---|---|
| `blind` | 代理变体,图片一律替换为固定占位文字 | 视觉通道整体的价值(下限) |
| `naive` | 代理变体,`DEFAULT_PROMPT`("describe this image in detail") | 普通转接方案 |
| `hint` | 生产代理(`_ROLE_PROMPT` + hint + 转写条款) | **线上实际行为** |
| `hint_tools` | 生产代理 + 已发布的 `vision-tools` skill | 回查工具的价值 |
| `native` | Codex 直连原生多模态模型 | 文字中转的代价(上限) |
四个判断:
- `blind → naive`:**有效性检查**,不是结论。见下节。
- `naive → hint`:hint 在没有明确问题时值不值。
- `hint → hint_tools`:**决策日志 #2 第一次被检验**。
- `hint_tools → native`:还差多远。
`native` 需要视觉模型所在中转站支持 Codex 认识的 wire API。**若不支持,该条件记为
未跑,不用任何替代品冒充上限。**
代理变体不改生产代码:与机制层同样的做法,`codex-vision-proxy.py` 与
`vision_client.py` 从 `main` 现取副本再改常量,副本里对被改的原句加断言,
生产 prompt 措辞一变就报错退出,不会静默退化成另一个条件的副本。
+ ### 一处必须写在前面的更正:回查通道在三个条件里都开着
+
+ 读生产代码时发现的,写在这里是因为它改变第 4 条预测该怎么读。
+
+ 代理在每次对话第一张图处注入一段 `_CHANNEL_NOTE`,大意是:图片是以文字形式到达你
+ 这里的,你从来收不到视觉 token;**只要描述里缺你要的东西,就说出你在找什么并调用
+ `view_image`,下一份描述会照着这个问题写。**
+
+ 也就是说,**「发现描述不够 → 回查」这条路径 `hint` 条件本来就有**,不是
+ `hint_tools` 才带来的。因此:
+
+ - `hint → hint_tools` 隔离出的是**那四个 CLI 工具**(`glance`/`ground`/`detect`/`trace`)
+ 的增量,**不是「能不能回查」本身**。预测 #4 说的「增益很小或为零」也只能读作
+ 「工具相对已有的回查通道增益小」,不能读成「回查没用」。要单独检验回查通道,
+ 得再加一个删掉 `_CHANNEL_NOTE` 的条件,本轮不加。
+ - `_CHANNEL_NOTE` 在 `naive` 里**原样保留**。`naive → hint` 要隔离的是视觉侧 prompt,
+ 两个条件之间只准差这一样东西;顺手把 channel note 也删掉,得到的差值就无法归因了。
+ - `blind` 是例外,它不在这条链上。该条件不发起任何视觉调用,就把 note 换成一句
+ 诚实的「本环境无视觉能力,再看也拿不到」——邀请模型去回查一个答不了的通道,
+ 只会白烧回合。有效性检查不需要是受控臂。
+
## 题目:为什么必须自己生成
CaptionQA 两种题面都失败了,失败方式值得记住:四选一饱和;去掉选项后,
**连直接看着图的 `native` 都答不出的题从 1 道涨到 10 道**——题面本来就是配合选项
才完整,抽掉选项不是变难,是变含糊。教训是一句话:
> **标准答案必须来自生成源,不能来自标注。**
因此每道任务题由 HTML 源码渲染成截图(headless Chrome),标准答案就是源码里的
那个字面量。判分零歧义、零 LLM judge。
每道题包含:
```
tasks/<name>/
repo/ agent 的工作目录(一个能跑测试的小仓库)
evidence.html 截图源码(含标准答案的字面量)
evidence.png 渲染产物,放进 repo/
prompt.txt 交给 agent 的话,措辞像用户,不像题目
verify.sh 退出码 0=通过,非 0=失败;不调用任何模型
gold.json 源码里的字面量,供 verify.sh 与人工核对
```
三条硬要求:
1. **图必须是承重的**:答案在仓库文本里任何地方都查不到。由 `blind` 条件实测保证。
2. **判分是脚本**:`verify.sh` 跑测试或解析产物做精确比较,绝不用 LLM 判定。
3. **prompt 不能剧透**:说「构建挂了,截图在 ci.png,修一下」,不说
「请读出第 87 行的 Expected 值」。剧透就退回成机制层。
### 两类任务
**A 类·单点精确值**(例:CI 日志截图里 `Expected: 4500`,仓库里常量是 3000,
数字 4500 全仓不存在)。测的是精确值能不能穿过文字通道。
**B 类·双故障,其中一处不显眼**(例:截图里既有醒目的红色报错,也有一行不起眼的
弃用警告,两处都必须修,`verify.sh` 两项都查)。**这是本轮的重点**——它是唯一能测
到「静默遗漏」的形态:agent 不知道第二处存在,就不会回查,转写条款要么在这里
兑现,要么不兑现。A 类在机制层已经间接测过,B 类没有。
pilot 出 4 道题,**至少 2 道是 B 类**。
## 指标
- **主指标**:`verify.sh` 通过率。二元,脚本判定。
- **B 类拆开报**:显眼故障修没修 / 不显眼故障修没修。总通过率会掩盖后者,
而后者才是被检验的主张。
- **过程指标**(从 `codex exec --json` 事件流数):`view_image` 调用次数、回合数、
墙钟耗时、token。`hint_tools` 额外记它**有没有真的调用** `glance`/`ground`——
如果它从不调用,那么 `hint_tools ≈ hint` 说明的是工具没被触发,不是工具没用,
两者结论完全不同,必须区分。
- **不设 LLM judge。** 一个都没有。
## 噪音与重复
agent 循环有随机性,单次运行不能归因。每个 (任务, 条件) 跑 **k=3** 次,
报 3 次里通过几次。配对分析以任务为单位。
温度、reasoning effort 与生产一致,不为降噪而调——降噪调出来的数字不是产品的数字。
## 有效性检查(写在看到数据之前)
- **`blind` 必须几乎全败。** 某道题 `blind` 通过了,说明答案能从仓库文本推出来,
图不承重,**该题作废并单独列出**,不进配对集。这条规则的地位等同于机制层的剔除规则。
- **`native` 全败的题也作废**:连原生多模态直接看图都做不成的任务,测的是任务设计,
不是描述通道。这是 CaptionQA 那 10 道歧义题教出来的规则,原样搬过来。
- 两条规则**剔除前后的数字都要报**。
## 预注册的预测
| # | 预测 | 依据 |
|---|---|---|
| 1 | `blind` ≈ 0/12 | 有效性检查;不为 0 就是题设计错了 |
| 2 | `naive` 在 A 类上接近 `hint` | 机制层已显示单点值提取上两者打平 |
| 3 | **`naive` 在 B 类不显眼故障上明显落后 `hint`** | 本轮主假设:无 hint 时描述按图片自身结构组织,不显眼的东西被写没 |
| 4 | **`hint_tools` 相对 `hint` 增益很小或为零** | **对决策日志 #2 的反向预测**(见下) |
| 5 | `native` 高于全部条件,但差距小于机制层的 2–3 pp | 任务层错误来源更多,描述通道不是唯一瓶颈 |
**第 4 条是故意押的反向预测,且赌的是本项目自己的主张。** 决策日志 #2 说「首轮描述是
地图,深度由主模型重查」。但回查有一个前提:**agent 得先意识到自己缺东西。**
如果描述静默漏掉了一处故障,agent 手里没有任何触发回查的线索——它不会去问一个它
- 不知道存在的问题。若 `hint_tools` 在 B 类不显眼故障上并不优于 `hint`,那么决策日志 #2
- 的适用范围就要收窄成「只对 agent 已经知道自己要什么的情况成立」,而这恰恰**加强**
- 决策日志 #4(转写条款)的地位:工具救不了的,只能靠首轮不漏。
+ 不知道存在的问题。这一点在本轮尤其干净,因为**回查通道在 `hint` 里已经开着**
+ (见上文「回查通道在三个条件里都开着」):若 `hint_tools` 仍不优于 `hint`,
+ 差的就不是工具或通道,而是**触发信号**。若 `hint_tools` 在 B 类不显眼故障上
+ 并不优于 `hint`,那么决策日志 #2 的适用范围就要收窄成「只对 agent 已经知道自己
+ 要什么的情况成立」,而这恰恰**加强**决策日志 #4(转写条款)的地位:
+ 工具救不了的,只能靠首轮不漏。
反过来,若第 3 条不成立(`naive` 在 B 类上也不落后),那 hint 在任务层同样没有可测
价值,README 的相应措辞必须改。**两个方向都写在这里,不留事后选择的余地。**
## 规模与代价
pilot:4 题 × 5 条件 × 3 次 = **60 次 agent 运行**。
冒烟测试实测:一次琐碎任务 9.7k token。真实任务估 40–80k,60 次约 3–5M token,
走用户 DeepSeek 官方 API;视觉调用另计,走评测自己的 env(**不动生产 env**)。
按当前定价量级约合数美元。墙钟按 2 并发估 1.5–2.5 小时。
**pilot 的目的不是出结论,是验仪器**:4 题的配对检验没有统计功效,这一点现在就写明,
免得事后拿 4 道题的 p 值说事。pilot 的成功标准只有两条:
1. `blind` 全败、`native` 大多通过 → 题是承重且可做的。
2. 中间三个条件**至少在某些题上不同** → 题库有区分度。
两条都满足才扩到 15–20 题。**这一步是上一轮花了 230 道题才学到的:先验区分度,
再上规模。**
## 已知局限(写在前面)
- 一个 agent harness(Codex 0.146.0)、一个答题模型、一个视觉模型,均与生产一致。
- 题由我生成,存在出题人偏好风险。缓解:标准答案来自渲染源码不来自判断;
`native` 作上限对照——**若某条件超过 `native`,几乎必然是题出歧了**,当作红旗。
- 合成截图比真实截图干净。这是真实局限,不在本轮解决。
- k=3 只能分辨「几乎总是」与「几乎从不」,分辨不了 50% vs 65%。
## 产物
代码与数据在 `~/cdv-task-eval/`(**不放 `/tmp`**,macOS 会清理,上一轮吃过一次)。
长跑挂 screen,不挂在 assistant 宿主进程下,中间结果勤 commit。