Closed
[V1111-BENCH0] [P0·core] 拆除 benchmark 分支:评测的胜负判据已回流成产品完成定义,且评测环境下主动关闭质量闸(含 SWEBENCH_CACHE 隐蔽通道) #61
kemengAdd on  8 days agoClosed at  2 days ago
kemengCollaborators
8 days ago Create

一 复述

用户裁定:bench 是手段不是目的,产品里不应保留评测专用选项与分支。
Claude Code / Codex(公开 CLI 参数面)都没有评测档——评测由外部 harness 用产品本来就有的
通用旋钮(prompt / 超时 / 沙箱 / 权限)组合出来,产品不关心自己是否在被打分。

本 issue 不是「修 bench 的某个缺陷」,而是请求拆除 benchmark 这一档本身,并把其中真正
有价值的部分上收为产品通用能力。

关联诊断:docs/BENCH_BRANCH_REMOVAL_DIAGNOSIS_20261101.md。

先说清与既有 issue 的关系:现有 bench 类 issue(#34 #35 #36 #37 #38 #39 #53 #54)全部在
「让 bench 更好用」,没有一条问过「bench 该不该有」。过去一年为 bench 修的东西已经形成了
沉没成本,这个 issue 要求先回答那个没问过的问题。


二 影响面(10 处行为分叉 · 3 条激活通道)

2.1 三条激活通道,语义互不同步

# 通道 位置 说明
1 --benchmark xwkernel v1.4.38 kernel-host/src/args.rs:305-308 正路,help 第 132 行可见(v1.10.9 实测)
2 --scenario benchmark 同上 :302-303;xwrepl 0.2.56 contract.rs:97-98 deprecated 别名
3 SWEBENCH_CACHE 环境变量 xw-tools 0.1.32 file_edit.rs:1018 绕过 CLI 与配置,只影响 file_edit,零可观测性

附带缺陷:--mode benchmark 静默成功但不生效——AgentMode::from_name("benchmark")
(xwcore 0.1.59 config.rs:127-131)返回 Default,oneshot.rs:388-396 只校验名字合法性,
于是它变成一个合法的 Default,不报错、不警告、不启用 bench。xwtui/src/app/input.rs:478
的提示语还在教用户这个写法是合法的。

2.2 行为分叉清单(★ = 改变质量属性,不只是话术)

# 位置 非 bench bench
1 ★ xw-tools file_edit.rs:906(:1233 再跳一次) 编辑后 cargo check,新错误 > baseline 则回滚 整面跳过(零检查零回滚)
2 ★ xwcore stages/check_exit.rs:26-35 —— task_complete 仅在 has_patch 时算完成,否则 ignored
3 ★ xwcore runtime/mod.rs:742-747 默认档没有 task_complete 工具 有
4 xwcore prompt_kernel.rs:892-897 组装 12 段 use_bench 时提前 return,只留 3 段
5 同上 :400-408 —— 注入 8 行 [Benchmark Mode](英文)
6 同上 :410-416 通用诊断 32 行 换成 compact 5 行
7 xwcore stall_manager.rs:409-412 只读阈值 30 / 连续 10 10 / 5
8 ★ 同上 :651 保留强制干预 禁用强制干预
9 ★ 同上 :813 abandon 可用 禁用 abandon
10 xwcore runtime/init.rs:237-252 无 强制 pre-flight,失败即 Err 退出

2.3 提前 return 砍掉的 6 个通用段

prompt_kernel.rs:892-897 在只组装了 mbase + benchinject + benchdiag 后 return,
:900-916 这些段永远进不了 bench 的 system prompt:

  1. "修复类请求才需要产出 patch,问答类请求直接回复即可" ← 区分「答题」与「施工」的唯一一句
  2. PromptMutate 3. PromptLangVerify 4. PromptDiagnostic(32 行)
  3. PromptDispatch 6. # 项目语言: {lang} + PromptLangGuidance

三 实测读数

3.1 我们自己的评测从没开过 bench

  • DeepSWE:dswe_agents/xwcode_agent.py:132 use_benchmark: bool = False;
    :322-329 注释说明因 1.10.2 的 HTTP 400 duplicate tool name 而关闭。
  • Terminal-Bench:tests/benchmark/terminal_bench/xwcode_agent.py:229-239 无该参数。
  • ⇒ R2 / R3 / R4 四轮全部跑在非 bench 路径。

3.2 而那个「修复条件」在 v1.10.4 已满足,注释已过期

关的理由 现状 证据
task_complete 重复注册 已修(根因+兜底双修) xw-tools 0.1.32 executor.rs:1136 单测 ac_1a_1_task_complete_def_not_unconditionally_exposed;xwcore runtime/request.rs:139-146 最终 tools[] 按名去重
注释写于 2026-10-29 50868c00a(1.10.2 期) git log -S "duplicate tool name"

⇒ 为评测写的全部能力,我们一次都没验证过;而它的副作用已经在影响真实用户。

3.3 旁路被测试锁死(这是「手段变目的」的标本)

xw-tools tests/v1105_p16_cargo_check.rs:203-220:

/// `AC-A4` `bench` 复现面零回归: `SWEBENCH_CACHE` 在场 ⇒ **零** `cargo check`, 编辑仍成功。
fn ac_a4_benchmark_bypass_keeps_zero_checks() {
    std::env::set_var("SWEBENCH_CACHE", "1");
    assert_eq!(spy.checks(), 0, "AC-A4: 旁路在场时 cargo check 调用须为 0");

file_edit.rs:906 的原注释更直白:「the eval harness (not the compiler) determines correctness」。

好消息:DeepSWE / TB 都没设 SWEBENCH_CACHE(它只出现在 tests/benchmark/swebench/{Dockerfile:66, run_host.py:595,1500}),所以 R3/R4 的归因不受影响。坏消息:走 SWE-bench 链路的评测,
测的不是用户拿到的东西,分数不构成产品证据。

3.4 引用量(改动面可控)

生产引用(排除测试):xwcore 35 · xwkernel 14 · xwrepl 10 · xw-tools 7 · xw-subagent 1 ≈ 67 处;
测试侧断言 xwcore 15 · xwkernel 10。

3.5 已有一个先例:配置键层已去过一次

xwcore config.rs:928:assert!(!m.contains_key("benchmark"), "benchmark key removed per user decision")
——用户此前已决定去掉 benchmark 配置键。只去了配置键,代码层没去。


四 为什么必须拆,而不是留着

4.1 评测的胜负判据,已经变成了产品的完成定义

check_exit.rs:26-35:task_complete 只在 has_patch 时生效。在 SWE-bench 语境里
「完成 = 有 patch」是判分器的定义;搬进产品后:

用户请求 has_patch 结果
「查下 xwcode 占多少内存」 false task_complete 被 ignored ⇒ 无法以「完成」收尾
「解释这段代码」 false 同上
「改一下这个函数」 true 正常

纯信息型任务在产品里没有合法的完成路径。 唯一出口「不调工具、输出纯文本」又被
plan_detected 挡住(stages/mod.rs:341)。两条路都堵死,行为上就是「答完还要继续干」。

⇒ 这是 #59 的机制源头:#59 说「完成判据缺『这次不用施工』一档」,本 issue 指出
那一档为什么缺——它被 bench 的判分口径占用了。两者应同批设计。

4.2 矛盾已被察觉,但选择的是「再造一个开关」

xwcore config.rs:212-226 给 batch_mode 的字段注释:

为什么需要独立字段(禁复用下列既有信号):…… benchmark_mode:与 benchmark prompt 注入/模型覆盖耦合,语义不同;

今天 benchmark_mode(评测档)与 batch_mode(无人值守档,detect_batch_mode = !stdin_is_terminal)
并存,后者才是评测真正需要的那一档,前者已被架空。

4.3 这不是野生行为,是制度化的

#30(已 closed)标题即「benchmark 场景系统提示加 API 形状硬约束」——为一次评测失败
(E0283、17 断言全灭)在提示词里加一条针对隐藏测试的规则。要拆 bench,需要同时停止这类加法。


五 修法(分四步,每步可独立验收)

P0-1 删 SWEBENCH_CACHE 旁路(先止血)

  • 删 file_edit.rs:1018(判定源)与 :906/:1233(两处消费);
  • v1105_p16_cargo_check.rs:203 改为反证:断言「旁路已不存在 ⇒ 高错误编辑必被回滚」。
  • 理由:唯一一条静默降低质量属性、激活方式不可见的通道。

P0-2 完成判据去评测化(与 #59 合并)

  • check_exit.rs:26-35 的 has_patch 前置改为「任务目标达成」,信息型任务(无 patch)也可正常收尾;
  • task_complete 暴露面(runtime/mod.rs:746)从「Plan ∪ bench」改为全档可见。

P1 提示词合并 + 停止判据统一

现有 bench 段 处置
「不要泛化公开 API(Into<T>/AsRef<T>)」 上收进通用段(对任何用户都对)
「先定位再编辑、编辑后验证」 通用段已有,删 bench 版
compact 5 行诊断协议 删(通用 32 行更强)
「Fix the bug described in the issue」 删(假定任务形态)
「Prefer edit_file over bash」 单独评估:为 patch 提取服务则删;确有可靠性依据则按场景而非「是否在评测」表达
段插件名 prompt.benchinject vs 注释 prompt.benchmark.inject 一并清理(命名已不一致)

stall_manager.rs 三处(:409-412 / :651 / :813)改由 batch_mode 门控,删 benchmark_mode 判据;
4 条 bench 单测按 batch_mode 改写。

P2 删开关本体

  • 删 --benchmark / --scenario benchmark / AgentMode::from_name("benchmark") 三处入口;
  • 删 RuntimeConfig::benchmark_mode 字段与 build_runtime 的对应形参(该函数已 #[allow(too_many_arguments)],减一是净收益);
  • 保留 batch_mode 作为唯一「无人值守」档。

六 验收

  1. xwcode --benchmark → unknown argument;--mode benchmark → 明确报错(不再静默降级)。
  2. grep -r "SWEBENCH_CACHE" crates/ 仅剩 run_host.py/Dockerfile(缓存目录用途,与行为无关)。
  3. grep -rn "benchmark_mode" xwcore/src 为空;prompt_kernel.rs 无 use_bench 分支与提前 return。
  4. 同一 prompt 在 TTY 与 < /dev/null 下,system prompt 只差「无人值守」相关行,不再差 6 个段。
  5. 对「查一下内存占用」类请求:首轮 task_complete 收尾,finish_reason=TaskCompleted,无 patch。
  6. 拆除后跑 R5(同 5 题同模型)与 R4 对比。预期不是分数上升,而是:同题方差下降、
    失败形状收敛到「补丁对/不对」,不再出现「零动作」「散会」「跑了但编译不过」三类与模型能力无关的形态。

七 明确不做

  1. 不调小 max_iterations 替代拆除。 那会把「该停没停」换成「没做完被迫停」,直接带回 R3 那批零动作失败(同 #59 §「明确不做」)。
  2. 不保留「评测专用提示词」的私有副本。 只对评测成立的规则 = 在骗判分器,应删;对所有用户成立的,上收。没有中间地带。
  3. 不在本轮改适配器去打开 --benchmark。 开关即将删除,此刻翻它只污染基线可比性;R5 必须在拆除之后跑。
  4. 不把「bench 分支」当成「场景分支」保留。 若将来确有「一次性 / 无人值守」需求,用 batch_mode 表达,不得再引入评测语义。
likedislike
kemengCollaborators
8 days ago Comments:

【ar审核】纳入·lane=km主体(P2涉xwtui提示语一处由tx配)·理由:bench判分口径占用产品完成定义(check_exit has_patch门),P0,与#59同批设计。体量大,进版下版启动时定,本版不动bench面。

likedislike
kemengCollaborators
8 days ago Comments:

【ar追审】下版(v1.10.12)首件:诊断docs/BENCH_BRANCH_REMOVAL_DIAGNOSIS_20261101.md §七四步(P0-1删SWEBENCH_CACHE旁路/P0-2完成判据去评测化与#59同批/P1提示词合并+停止判据统一/P2删开关本体)。用户令:下版先不合入其他issue,专注拆除。km落点(跨5仓)已收,待v1.10.11关版后下版令。

likedislike
kemengCollaborators
3 days ago Comments:

[ar审核 2026-11-05] 结论:✅可认领开发。建议:km优先(建议仅负载均衡,任何人可抢,接单即开分支占位,comm同步防撞)。依赖:无。规范:一issue一分支,PR过L3;改门禁/契约/完成判据语义者ar复核diff。方向:拆除benchmark分支、判据回流完成定义,km认领;涉及门拆除ar复核。

likedislike
KkemengCollaborators
2 days ago Close issue
kemengCollaborators
2 days ago Comments:

分支已并 master(fix/61 面),判据面零变。关单;有回归请 reopen。

likedislike