DESIGN.md@research/task-eval · git:20260818.025eeac · 2026-08-18 · sha256 6f41edd229187cb5
DESIGN.md@research/task-eval git:20260818.025eeacA
Immutable. This exact content never changes and is served at /api/v1/blob/6f41edd229187cb5.
# 任务级评测 — 设计与预注册 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`),因为要测的是用户真实在用的系统。代理一律以默认 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-skills` skill | 回查工具的价值 | | `native` | Codex 直连原生多模态模型 | 文字中转的代价(上限) | 四个判断: - `blind → naive`:**有效性检查**,不是结论。见下节。 - `naive → hint`:hint 在没有明确问题时值不值。 - `hint → hint_tools`:**决策日志 #2 第一次被检验**。 - `hint_tools → native`:还差多远。 `native` 需要视觉模型所在中转站支持 Codex 认识的 wire API。**若不支持,该条件记为 未跑,不用任何替代品冒充上限。** 代理变体不改生产代码:与机制层同样的做法,`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 道歧义题教出来的规则,原样搬过来。 - 两条规则**剔除前后的数字都要报**。 ### 第二条通道:本地 OCR(冒烟阶段发现,写在产出数据之前) 第一次冒烟跑就出事:`blind` 通过了 retry-budget——它在被告知「本环境无视觉能力」 之后,去 shell 里找了一圈,发现机器上装着 `tesseract`,直接把截图 OCR 了。 **这条路封不住。** agent 走的是 `/bin/zsh -lc` 登录 shell,PATH 由用户 zshrc 重建, 往前面插桩目录无效(实测);就算封掉 tesseract,macOS 自带 `swift` 和 Vision 框架,几行代码就是一个 OCR。封堵是打不赢的仗,所以改成**如实记录**: 每次运行都记 `local_ocr` 字段,出现即留证。 因此 `blind` 通过要分成两种,只有一种作废题目: | `blind` 通过的方式 | 含义 | 处置 | |---|---|---| | 没用 OCR | 答案能从仓库文本推出来,图不承重 | **该题作废** | | 用了 OCR | agent 绕开了描述通道,与题目承重与否无关 | **题目不作废**,该次运行标记后单列 | **关键在于这是不是全局混淆。** 同批冒烟里 `hint` 全程没碰 OCR——它第一轮就从描述里 拿到了 4500,没有任何理由去找替代通道。也就是说,**伸手去 OCR 是「饿出来的」行为, 不是通用行为**。若正式跑里 `local_ocr` 只在 `blind` 出现,中间三个条件的比较不受影响, 且这一点会用数据说明而不是假定;**若它出现在 `naive`/`hint`/`hint_tools`, 那么本轮比较被第二条视觉通道污染,必须如实报出,不得当作干净结果**。 同理还记 `looked_outside`:命令里出现本次工作目录以外的评测路径就留证。 冒烟里 `hint` 确实翻了一眼隔壁目录(没拿到东西)。运行目录因此改成哈希命名、 verify.sh 与 gold.json 移出 agent 可浏览范围——**第一次冒烟时 `blind` 正是靠 `cat gold.json` 和 diff 隔壁已完成的 `native` 目录拿到答案的**。渲染用的 HTML 源码 (含标准答案字面量)也从 `repo/` 移走了,同样是那次冒烟发现的。 ## 预注册的预测 | # | 预测 | 依据 | |---|---|---| | 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` 里已经开着** (见上文「回查通道在三个条件里都开着」):若 `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。