Skip to main content

tb4-five-arm

在 Terminal-Bench 4.0 上做 codex harness 五臂对照(裸 codex / 原生 /goal / LoopX 三模式)。复用 SWE-Marathon 那套驱动,靠 WEN_BENCH 切换。重点是 TB4 相对 SWE-Marathon 的四处结构性差异——每一处踩错都**退出码 0、有轨迹、有分数**,只是分数不对。

Jump to install

Source facts

Repository
loopx-project/loopx
Last source activity
September 2, 2026 at 17:05
Detected SKILL.md language
Chinese
Stars
5,913
Forks
561

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
tb4-five-arm
description
在 Terminal-Bench 4.0 上做 codex harness 五臂对照(裸 codex / 原生 /goal / LoopX 三模式)。复用 SWE-Marathon 那套驱动,靠 WEN_BENCH 切换。重点是 TB4 相对 SWE-Marathon 的四处结构性差异——每一处踩错都**退出码 0、有轨迹、有分数**,只是分数不对。
# Terminal-Bench 4.0 五臂对照 五臂定义、LoopX profile 装配、agent 类、监控工具全部与 [[swe-marathon-five-arm]] 相同,**先读那一份**。这里只写 TB4 特有的部分。 对照维度仍是 **harness 不是模型**:五臂的模型、effort、工具面、沙箱、容器一致。 ## 切换方式 ```bash export WEN_BENCH=tb4 # 必须 export,见下面「最毒的一个坑」 source env.sh ./scripts/prebuild_images.sh music-harmony # 应建 2 个镜像,不是 1 个 ./scripts/verify_envs.sh music-harmony # install-only,不烧 token ./scripts/canary_timeout.sh # 五臂 × 短死线 ./scripts/marathon_all.sh --dry # 63 任务 × 5 臂 = 315 trial ``` benchmark 相关的量全在 `scripts/bench/tb4.sh`,驱动脚本里没有任何 TB4 常量。 `WEN_BENCH` 不设时默认 `swe-marathon`,行为与引入 bench 层之前逐字一致 (已用 `bash -x` 逐参数 diff 验证过)。 ## 数据来源 `terminal-bench/` 是 `harbor-framework/terminal-bench` 的 **tag v4.0.0** (commit `452bf305c6`),66 个任务,见 `terminal-bench/VERSION`。 - **不能用 `harbor run -d terminal-bench@4.0`**:harbor 的注册表(Supabase `dataset` 表)里只有 `terminal-bench@2.0`,实测查 4.0 返回 `null`。 - **不要跟 main**:上游 README 明说 "will be continuously updated", 跟 main 跑出来的结果不可复现。 - `tasks/dataset.toml` 里每个任务有 sha256 digest,`task.toml` 与 `tests/` 一个字节都不能改。要注入环境变量走 harbor 的 `--ve` / `--ae`。 ## TB4 vs SWE-Marathon:四处结构性差异 | 项 | SWE-Marathon | TB4.0 | |---|---|---| | `agent.timeout_sec` | 3600–36000 各异 | **全部 28800(统一 8h)** | | `verifier.environment_mode` | 无(shared) | **全部 `separate`** | | `network_mode` | 三态,逐任务 | **一个都没声明** → harbor 默认 public | | 每任务镜像数 | 1(`environment/`) | **2(`environment/` + `tests/`)** | | 连续分 | `metrics.json` 有 | **没有**,只有二值 reward | 排除 3 个要 H100 的任务(`fp8-rmsnorm-gemm` / `jax-speedrun-gpu` / `math-eval-grader`),本机是 4090D。剩 63 个,其中 11 个是多容器 (`environment/docker-compose.yaml`),1 个(`medical-claims-processing`) 还要 MCP server(playwright,sse `http://playwright-mcp:3080/sse`)。 ## 坑(都会静默通过) ### 一、最毒的一个:`WEN_BENCH` 用前缀赋值 ```bash WEN_BENCH=tb4 source env.sh # ✗ 错 export WEN_BENCH=tb4; source env.sh # ✓ 对 ``` bash 在 `source` 返回后会把前缀赋值的变量**还原成未设置**,但 `WEN_TASKS_DIR` 是 export 的、留了下来。于是后续任何脚本自己 source env.sh 时:`WEN_BENCH` 空 → 回退 swe-marathon profile,却继承着 TB4 的任务目录 —— 拿 **TB4 的任务**、套 **marathon 的网络策略**(`from-task` 找不到 `network_mode` 就断网)、 开着判官注入、写进 `marathon-full/`。退出码 0,全程无警告。 `env.sh` 里有个一致性闸门专门拦这个(`WEN_TASKS_DIR_BENCH` 与当前 bench 不符 就丢弃继承值),但闸门只保证**状态自洽**,不保证是你想要的那个 bench。 开跑前看一眼各脚本打印的 `bench:` 那一行。 ### 二、网络策略反了 → 66 个任务全跑成断网 TB4 的 66 个 `task.toml` **一个都没有声明 `network_mode` / `allow_internet`**, 而 harbor 0.20.0 的 `NetworkPolicy.network_mode` 默认是 `PUBLIC` —— 上游的标定条件是联网。 而 `marathon_run.sh` 原本的做法是 grep `task.toml` 的 `network_mode`、 **找不到就回退 `no-network`**。直接套用会把 66 个任务全跑成断网: 退出码 0、有轨迹、有分数,只是分数偏低,看着像"模型不行"。 `bench/tb4.sh` 里 `BENCH_NET_POLICY=public` 显式钉死,不走那条 grep。 **另注:`--allow-agent-host` 在 public 下是空操作。** 实测 harbor 会打印 ``` UserWarning: Run-specific allowlist host(s) ['<model-gateway>', '<container-gateway>'] are ignored because the effective network policy is public. ``` 模型端点的可达性靠代理环境变量和宿主机路由,不靠这个参数,别以为加了就生效。 **再注:本机实测容器不穿代理也能出网**(`docker run` 里直连 pypi.org 得 200)。 代理注入是沿用 marathon 对 public 任务的既有做法、属冗余保险; `no_proxy` 已包含模型网关,不会劫持 codex 的调用。 ### 三、`environment_mode = "separate"`:两个镜像、两个环境 全部 66 个任务都是 separate。harbor 0.20.0 的实际时序 (`harbor/trial/single_step.py:38-55`、`trial/trial.py:610-680`): ``` 跑 agent → 上传 agent 日志 → 收 artifacts → **停掉 agent 环境** → 起一个从 tests/ 构建的独立 verifier 环境 → 验证 → 停 ``` 三个后果: 1. **每个任务两个镜像**(66 × 2 = 132)。`prebuild_images.sh` 原来只扫 `environment/`,漏掉 `tests/`。漏了的话 verifier 镜像会在**运行期**首次构建, 而运行期没有代理(那是刻意的,代理进运行时容器会破坏隔离),dockerd 自己钉的 `<dead-dockerd-proxy>` 又是死的 → `apt-get` 超时 → verifier 起不来记 errored。 **症状极像"任务没做出来"**:agent 阶段完全正常、有轨迹、有 token 消耗。 现在由 `BENCH_IMAGE_DIRS=(environment tests)` 覆盖,且跳过会计数。 2. **只有声明在 `artifacts` 里的文件能跨到 verifier**(66 个全声明了)。 agent 把活干在别处、没写到声明路径 → verifier 看到空目录 → reward 0, 而 agent 轨迹完全正常。这是 shared 模式下不存在的失败模式。 3. 串行,所以每 trial 的容器/网段**峰值**不翻倍,但多一次构建、 多一个 compose project。 ### 四、二值 reward 在紧预算下没有区分度,而 TB4 没有连续分 SWE-Marathon 靠任务自写的 `metrics.json`(`partial_score` / `pass_rate` / `pytest` / `gates_*`)补救;**TB4 不写这个文件**,只有 harbor 的二值 reward。 `bench/tb4.sh` 设 `BENCH_HAS_PARTIAL=0`,于是: - `_partial.py` 整体跳过并打印原因,不静默兜底 - `_compare.py` **整列不渲染** partial,而不是渲染成一列 0.0 (一列 0.0 会被读成"全都没得分",比不显示更坏) - `_compare.py` 的跨跑次对照自动改用 `reward` 做差,表头跟着变 marathon 那轮实测:撞死线的 23 条 trial 无一得分,自己收尾的 14 条中 11 条得分 ——决定分数的是"能不能在预算内做完"。TB4 统一 8h 预算而我们的死线远短于此, 这个问题只会更严重。**唯一还能分辨的信号是终止原因**(自己收工 vs 撞死线), `_receipts.py` 有这个数据,报表必须并排给出。 ### 五、超时倍率不要照抄 marathon marathon 用的是 build 6× / setup 3× / verifier 4×,那是为**未做资源标定**的 Dockerfile 定的。TB 4.0 的卖点恰恰是"重新标定了 time/CPU/memory" (`build_timeout_sec` 中位数 900、`verifier.timeout_sec` 中位数 600), 照抄 6× 等于把上游的标定压掉。`bench/tb4.sh` 用 4 / 3 / 2。 ### 六、canary 的预算比例要重算 `canary_timeout.sh` 的 `CANARY_TIMEOUT_MULT=0.05` 是按 8h 声明预算定的 (8h × 0.05 = 24 分钟 > `GOAL_TIMEOUT_SEC` 5 分钟,保证**我们先到**)。 TB4 恰好也统一 8h,所以同一个值仍成立。换到声明预算短的 benchmark 上, harbor 侧可能反而先到,冒烟就白做了 —— 而那是**静默**的: 五臂照样出 result.json,只是走的是另一条超时路径。 ### 七、全量的量级要先量再定 63 任务 × 5 臂 = **315 trial**,外加 126 个镜像构建。 `MARATHON_AGENT_TIMEOUT_MULT` 沿用 marathon 的 0.3 得 8640s(2.4h)/trial。 **先拿冒烟的真实单 trial 墙钟再算总时长**,别直接开全量。 网段池是硬约束:默认约 32 个 bridge 网络,机器共用。起跑前确认池子有余量 (`marathon_all.sh` 有 `MARATHON_NET_CAP` 闸门),清理容器时**连 compose 网络 一起清**(`docker rm -f` 不删网络)。 ### 八、11 个多容器 + 1 个 MCP 任务未验证 冒烟只覆盖单容器路径。`ctr-optimization` `cumulative-layout-shift` `freight-dispatch-shift` `heat-pump-warranty` `intrastat-meldung` `kv-live-surgery` `legacy-utility-triage` `live-database-cutover` `medical-claims-processing` `nextjs-performance` `payments-pipeline-fix` 容器数与内存压力显著更高;`medical-claims-processing` 还要 MCP server 起得来。全量前单独验这 11 个。 ## 产物 ``` tb4-full/<task>/<arm>/<stamp>/<arm>/result.json job 级,含 stats /<trial>/verifier/ reward.txt /agent/ trajectory.json / goal_receipt.json tb4-full/.claims/<task>__<arm>.claim tb4-jobs/ marathon_run.sh 单独跑的落脚点 verify-envs-tb4/ canary-timeout-tb4/ ``` 成功判据与 marathon 相同(`scripts/_is_done.py`,驱动与监控共用): ``` n_completed_trials >= 1 且 n_errored_trials == 0 ```
View on GitHub