# harness-bench **Repository Path**: harvey_danny/harness-bench ## Basic Information - **Project Name**: harness-bench - **Description**: 这是一个"Agent Harness 对比评测"基准系统。 核心思想很巧妙:把同一个任务(冻结的 prompt + 冻结的 fixture 仓库快照 + 冻结的模型)分别交给不同的 agent 框架去执行, 然后比较框架本身的行为差异。比较的轴只有 harness 一个变量,其他全部冻结,所以差异可归因。 目前支持两个被测 harness: deepseek-harness 和 pi - **Primary Language**: TypeScript - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 6 - **Forks**: 6 - **Created**: 2026-08-16 - **Last Updated**: 2026-09-17 ## Categories & Tags **Categories**: ai **Tags**: None ## README
# harness-bench **Agent Harness 对比评测基准 —— 评"壳",不评模型** 同一个任务、同一个模型、同一份冻结的仓库快照,只更换 agent harness —— 让框架之间的差异,第一次变得**可归因、可复现、可统计**。 [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) ![Node](https://img.shields.io/badge/node-%E2%89%A524-green.svg) ![TypeScript](https://img.shields.io/badge/TypeScript-5.8-3178c6.svg) ![Tasks](https://img.shields.io/badge/tasks-143-8a2be2.svg) ![Harnesses](https://img.shields.io/badge/harnesses-6-orange.svg) [![Live site](https://img.shields.io/badge/live_site-uystat.com-2ea44f.svg)](https://uystat.com) [在线结果站](https://uystat.com) · [快速开始](#-快速开始) · [方法论](#-方法论与可复现性) · [Web 控制台](#-web-控制台) · [防泄漏设计](#-基准完整性防泄漏--污点审计) · [docs/](docs/)
--- ## 🌐 在线看评测结果: 不想先本地跑一遍?所有批次的评测结果已经发布成一个在线分析站:**[uystat.com](https://uystat.com)** - **看结论**:总览 / Harness 对比(Wilson 95% CI + 显著性检验)/ 能力矩阵 / 任务库 / 覆盖缺口与补测申请,支持按任务大类、难度、批次维度筛选 - **下原始数据**:`bench.db`、`runs.jsonl`、`task-catalog.json`、`session-ir-bundle.tar.zst`;下载有一个门禁 —— **Gitee 登录并 Star [本仓库](https://gitee.com/harvey_danny/harness-bench) 与 [pi-agent-go](https://gitee.com/harvey_danny/pi-agent-go)**(不收费、不设限,只要求一次点击) - **自建一份**:站点就是本仓库的 [`portal/`](portal/)(零依赖 Node 24,直接读 `.hb/bench.db`),步骤见 [portal/部署手册.md](portal/部署手册.md) --- ## 🎯 为什么需要它 做 coding agent 框架的人都会遇到同一个困境:改了框架里的一个策略,端到端成功率变了——但这到底是**框架能力变了**,还是任务难度波动、模型随机性、环境差异在捣乱? harness-bench 把这个问题变成机械事实: > **冻结模型、提示词与 fixture 快照,把 harness 作为唯一变量。** > 同任务多遍运行,用 Wilson 置信区间和显著性检验下结论,而不是用感觉。 历史批次里已经能挖出这类洞察:例如"小上下文 + 禁 shell"的压力任务曾让两个被测 harness 全部失败——说明上下文压缩策略与无 shell 环境下的工作能力是**共同短板**。这种跨 harness 的行为级结论,正是本基准要量产的东西。 ## ✨ 特性一览 | | | |---|---| | 🔬 **单变量可归因** | 批次冻结版本元组(hb 与各 harness 的 commit、模型、Node/平台、配置哈希),版本不一致的批次拒绝合并报告;脏 checkout 直接拒绝执行 | | 🌉 **SessionIR 归一化** | 各 harness 千差万别的原生日志 → 统一 JSONL 事件流;工具名归一为能力桶(`fs.read` `fs.edit` `proc.exec` `search` …),跨 harness 指标才可比 | | 📏 **三层评测** | 可执行验收(硬门槛 pass/fail)+ 过程指标(机械派生,不靠主观)+ LLM 盲评(rubric 100 分制、评审不可见 harness 身份、双评审算分歧、评审器自身经过校准) | | 📐 **严肃统计** | Wilson CI(通过率)、种子化 percentile bootstrap(中位数)、Fisher 精确检验与 Mann-Whitney U(小 n 精确置换)——全部对拍过 R/SciPy 参考值 | | 🔒 **防泄漏设计** | 污点扫描、canary 哨兵、参考答案收起、隐藏测试不落盘——杜绝"抄答案式通过"污染结果 | | 🖥 **Web 控制台** | 任务库 / 批次报告 / 能力矩阵 / 执行中心 / 失败实验室,与 CLI 共用同一套编排与统计内核,零逻辑分叉 | | 🧩 **开放适配** | 新增一个被测 harness,只需实现 `run` + `project` 两个函数 | ## 🏗 架构 ``` tasks//task.yml adapter-dsh · adapter-pi · adapter-pi-go (prompt + fixture + verify) adapter-soloncode · adapter-keen · generic │ │ └──────────► runner.runOnce() ◄┘ 隔离 homeDir · 交错执行 · 超时控制 │ ▼ SessionIR(harness 中立事件流) message / tool_call / turn_end / compaction … 工具名归一 → 能力桶:fs.read fs.write fs.edit proc.exec search web.fetch subagent │ ┌───────────────┼───────────────────┐ ▼ ▼ ▼ verify 可执行验收 过程指标 LLM judge(可选) 硬门槛 pass/fail tokens(cache分解) rubric 100 分 · 盲评 失败模式细分 turns · 探索比 双评审分歧 · temperature 0 timeout/crash/ 编辑→测试循环 评审器经 good/sloppy 校准 verify_fail/ 首次编辑耗时 … max_turns └───────────────┼───────────────────┘ ▼ SQLite (.hb/bench.db, WAL) │ ┌───────────────┼────────────────┐ ▼ ▼ ▼ HTML/MD 报告 能力矩阵热力图 CI 硬门 (hb gate) (CI + 显著性) category×harness pass→fail 回归即 exit 1 ``` 核心包 `packages/core`:zod schema(TaskDefinition / RunRecord)、SessionIR、runner、过程指标、统计层、报告/矩阵构建器、批次编排(`orchestrate.ts`)、job/suite 存储。CLI 与 Web 控制台都直接 import 这一层,**不 fork 任何统计逻辑**。 ## 🚀 快速开始 ### 环境要求 - **Node ≥ 24**(zstd 会话日志读取),pnpm - **DeepSeek API Key**:配置在 `hb.config.json` 的 `envFile` 指向的 `.env` 中;模型默认 `deepseek-v4-flash`(可在 `hb.config.json` 调整) - **dsh**:源码 checkout(默认 `../deepseek-harness/deepseek-harness`),必须是干净的 git checkout——批次会钉住版本 - **pi**:`npm i -g @earendil-works/pi-coding-agent`(跑 pi 时需要);其余 harness 按 `hb.config.json` 中各自路径配置 - **跑 `--sandbox enforce` 时,harness 必须装在机器级位置**(`C:\Users\` 之外,例如 `npm i -g --prefix D:\software\hb-tools ...`):沙箱账号穿不过别人的用户目录,装在自己 profile 下的 harness 起不来;路径写脚本入口(`.js`)而不是 `.cmd` shim。详见 [docs/sandbox.md](docs/sandbox.md) ### 安装与首次运行 ```sh pnpm install && pnpm rebuild better-sqlite3 pnpm test # 统计/存储/门/编排 单元测试 # 跑一个任务 × 两个 harness × 5 遍 pnpm hb run --task T1-fix-off-by-one --harness dsh,pi --repeats 5 --batch my-batch # 按大类 / 细粒度标签跑分 pnpm hb run --category bugfix --harness dsh,pi --repeats 3 pnpm hb run --tag forced-compaction --harness dsh,pi ``` ### 出报告、设门禁、开控制台 ```sh pnpm hb report --html .hb/report.html --md .hb/report.md # CI + 显著性 + 头对头结论 pnpm hb gate # CI 硬门(详见下文退出码) pnpm build:web && pnpm console # Web 控制台 → http://127.0.0.1:8787 pnpm dev:web # 前端开发模式(vite 5180 → 代理 8787) ``` ## ⌨️ CLI 速查 | 命令 | 作用 | |---|---| | `hb run` | 跑任务/大类/标签 × harness × repeats,批次落库(版本冻结 + 交错执行) | | `hb report` | 生成 HTML/MD 报告:每格 Wilson CI、显著性检验、头对头结论 | | `hb judge` / `hb judgments` | LLM 盲评与评分查询 | | `hb replay ` | 回放一次运行的 SessionIR 时间线 | | `hb recompute` | 从 IR 重算过程指标(指标可完全再生) | | `hb gate` | CI 硬门:对基线的 pass→fail 回归即 `exit 1` | | `hb audit` | 历史运行污点重扫,发现污染 run 即 `exit 1` | | `hb stash-solutions` | 将参考答案收起到主目录中性 vault(`--restore` 归还) | | `hb sandbox verify` | 自检本机沙箱是否真的生效(逐条探针,花不了模型预算);先报宿主就绪,未 provision 直接给修复命令 | | `hb sandbox provision` | Windows:一次性提权建 `srt-sandbox` 账号 + WFP 出网围栏;已就绪则空操作(幂等,`--force` 重装) | `hb gate` 退出码:`0` 通过 · `1` 存在 pass→fail 回归 · `2` 有失败但无回归 · `3` 环境/数据错误。默认基线为同版本元组的上一个批次;`--reverify` 可在保留的工作目录中重执行验收命令(`--keep-work` / `HB_KEEP=1` 保留工作目录)。 ## 📚 任务库 当前共 **187 个任务**:67 个原生任务 + 120 个导入任务。 | 来源 | 数量 | 验收方式 | 说明 | |---|---|---|---| | `Qihoo360/harness-bench` | 106 | `oracle-capability` | Python oracle 桥接验收(`--kind oracle-capability`,约 3.4h/dsh) | | 自研任务(`T*` / `H*` / `CF*` / `SP*` / `TR*`) | 67 | `snapshot-verify` | 精确修 bug、日志关联/六阶段计算/遗留迁移/对抗恢复、压缩保真、结果卸载、工具可靠性(`--kind snapshot-verify`,约 1.9h/dsh) | | SCBench(loop-arena) | 11 | `checkpoint-sequence` | 多 checkpoint 渐进验收,隔离工作目录(单题 54–110m,全组约 13.4h/dsh) | | `nyosegawa/harness-bench` | 3 | `external-repo-debug` | 隐藏的核心/回归测试,真实仓库需构建(约 6m/dsh) | 每个任务是一个目录:`tasks//task.yml` 定义 prompt、fixture 快照、超时与可执行验收;`category`(bugfix / feature / refactor / exploration-qa / long-horizon / adversarial / compaction-stress / compaction-fidelity / context-offload / tool-reliability)作为跑分聚合轴,`tags` 提供细粒度过滤。 `SP*` 与 `TR*` 是两组自包含实验族:SP 的假工具(`toolx.mjs`)随夹具分发,验收命令 `node check-answers.mjs` 在工作区内自检;TR 的业务逻辑、故障注入与判分器位于宿主机侧 `tools/trx-runtime/`(工作区只放不含逻辑的 `trx.mjs` 转发客户端),所以跑 TR 之前要把运行时封出仓库并常驻 mock 服务: ```sh pnpm tsx scripts/tr-runtime.mjs seal # tools/trx-runtime → 主目录 vault(agent 走不到答案键) node "${HB_TRX_VAULT:-$HOME/.hb-trx}/server.mjs" # 常驻,TR 验收依赖它;跑完 pnpm tsx scripts/tr-runtime.mjs unseal 归还 ``` 自检(需运行时在仓库内):`node scripts/selftest-sp.mjs` / `node scripts/selftest-trx.mjs`,每个场景都要求正解通过、故意写错的解失败。 分类清单与每类预计耗时见 `docs/task-catalog.md`(由 `node scripts/task-catalog.mjs` 从任务定义 + 历史运行重新生成),按类跑:`pnpm hb run --category <分类> --harness dsh`。 **导入外部基准:** ```sh node scripts/import-nyosegawa.mjs --cases benchmark/cases/axios__axios/low.yaml node scripts/import-qihoo.mjs pnpm hb run --kind oracle-capability --harness dsh,pi # 按 kind 选任务跑 ``` ## 🔌 被测 harness | harness | 接入方式 | 备注 | |---|---|---| | `dsh` | 自研 deepseek-harness,源码 checkout 启动 | cwd shim + `--patch` 层输出纯 JSONL 日志;批次内钉 commit | | `pi` | `pi -p --mode json` | prompt 经 stdin 传入(规避 cmd.exe 引号破坏) | | `pi-go` | pi 的 Go 实现 | `hb.config.json` 指向二进制与仓库 | | `soloncode` | `soloncode-cli.jar` | java 启动 | | `keen` | keen-code 原生二进制 | chat_completions 协议 | | `generic` | 通用 CLI 适配缝 | 配置 `genericBin` / `genericArgs` 即接入任意外部 harness | **新增一个被测 harness**:实现 `HarnessAdapter` 的 `run`(启动并采集原生日志)与 `project`(投影为 SessionIR)两个函数,注册进 CLI 的 adapter 表即可——统计、报告、矩阵、控制台全部自动可用。 ## 🖥 Web 控制台 `pnpm console`(默认 `http://127.0.0.1:8787`),后端为 Fastify(`apps/server`)+ 前端 React/Vite(`apps/web`),与 CLI 共用 `@hb/core`,不 fork 任何统计逻辑。 - **任务库** —— 全部任务按两级分类(粗大类 + 细粒度 tags)浏览,含每个 harness 的历史通过率 - **批次与报告** —— 批次列表 → 单批次报告:版本元组、每格 Wilson CI、头对头结论、judge 评分、方法论说明;α 与 drop-first 可调 - **能力矩阵** —— category × harness 通过率热力图 + Fisher/MWU 显著性;**只有统计显著的领先才标 ★**——这是"哪类任务该路由给哪个 harness"的数据层 - **执行中心** —— 从 UI 发起跑分,job 落库排队(`HB_JOB_CONCURRENCY` 可调),实时进度/取消/日志;server 重启时中断 job 标记 failed、queued 自动续跑 - **失败实验室** —— 按失败模式(timeout / crash / verify_fail / max_turns)浏览失败 run 与恢复行为指标(重复调用率、失败工具结果、编辑→测试循环);勾选任务组成"失败套件",一键 fan-out 到多个 harness 产出恢复行为对比 ## 📐 方法论与可复现性 - **版本元组冻结**:每次 `hb run` 创建批次行,钉住 hb/各 harness 的 commit、pi 版本、模型、Node/平台、配置哈希;报告拒绝合并版本元组不同的批次;脏 dsh checkout 被拒绝(除非 `--allow-dirty`) - **交错执行**:同一 repeat 内 harness 交错调度(`dsh,pi,dsh,pi,…`),使 provider 侧 prompt-cache 温度对两边保持均衡;每个 run 使用全新 homeDir(harness 侧冷缓存),指标带 cacheRead/cacheWrite 分解 - **统计层**:Wilson CI、种子化 percentile bootstrap(中位数)、Fisher 精确与 Mann-Whitney U(小 n 精确置换),全部在 `stats.test.ts` 中对拍 R/SciPy 参考值 - **评审器校准**:`scripts/calib.mjs` 用预先准备的 good/sloppy 两份都能通过测试的解,验证评审模型能把好坏拉开分差——先可信,再量东西 - **产物可追溯**:每次 run 存于 `.hb/runs//`(`session.ir.jsonl`、`verify.json`、原生日志);通过即清理工作目录(`HB_KEEP=1` 保留);指标可从 IR 全量重算(`hb recompute`) ## 🛡 基准完整性(防泄漏 / 污点审计) 默认(`sandbox.mode: "off"`)下 agent 运行无沙箱,能读到仓库里的一切。为防止"抄答案式通过"污染结果,做了六层防御;开启 `--sandbox enforce` 后隔离前移为事前控制,下列各层仍然保留: - **参考答案不落盘**:基线验证工作目录建在系统临时目录,每个 checkpoint 验收后立即删除(`--keep` 可保留调试) - **隐藏测试不驻留**:SCBench 验收测试与资产每次在临时目录物化、用后即删;历史答案/测试缓存已清除,且不再生成到仓库内 - **工作目录隔离**:`checkpoint-sequence`(及 `isolated: true`)任务的 workdir 建在 `.hb/runs/` 之外,agent 向上探索看不到兄弟运行产物 - **污点扫描**:runner 对每次运行的会话做泄漏扫描(访问 `.hb/`、baseline、隐藏测试、未来 checkpoint prompt、verify 产物等),命中则 `runs.tainted=1` 并落证据(`taint.json`);历史运行可用 `pnpm hb audit` 重扫 - **金丝雀陷阱**:参考答案带 canary 哨兵串,runner 逐文件扫描 workdir,命中即为答案被拷入的证据(零误报) - **参考答案收起**:`pnpm hb stash-solutions` 将 `solutions/` 移入主目录下中性命名的 vault(manifest 不含提示字样),测完 `--restore` 归还;runner 起跑时检测到 solutions 可见会告警 > `tainted=1` 不自动判负,但该 run 的 pass 在采信前必须人工复核证据。 ## 📁 项目结构 ``` packages/ ├── core/ schema(SessionIR/Task/Run) · runner · metrics · stats · report/matrix · orchestrate · store(SQLite WAL) ├── adapter-dsh/ dsh 源码启动 + 日志投影 ├── adapter-pi/ pi JSON 模式接入 + stdout 投影 ├── adapter-pi-go/ pi Go 版接入 ├── adapter-soloncode/ soloncode-cli.jar 接入 ├── adapter-keen-code/ keen-code 二进制接入 ├── sandbox/ 进程级隔离:execAgent 唯一 spawn 接缝 · 每 run 一个 srt broker · hb sandbox verify 探针 · hb sandbox provision 宿主就绪 └── adapter-generic-cli/ 通用 CLI 适配缝 apps/ ├── cli/ hb 命令行(commander) ├── server/ Fastify API + job 队列(托管 web/dist) └── web/ React 控制台(Vite) tasks//task.yml 任务定义:prompt + fixture + 超时 + 可执行验收 fixtures/seed/ 种子 TS 仓库;每任务的红测试即验收标准 scripts/ 基准导入 · 评审器校准 · 基线验证 reports/ 历史批次报告(MD + CSV) docs/ 需求 · 架构 · 平台策略 portal/ 数据门户:静态分析站 + Gitee 门禁下载(线上即 https://uystat.com) .hb/ 评测产物:bench.db(聚合库)+ runs//(SessionIR 与原始日志),随仓库交付;两份超 50MB 的转储切片说明见 .hb/SPLIT-FILES.md ``` ## 📖 文档 - [docs/requirements.md](docs/requirements.md) —— 需求定义 - [docs/mvp-plan.md](docs/mvp-plan.md) —— MVP 计划 - [docs/architecture-harness-provider.md](docs/architecture-harness-provider.md) —— HarnessProvider 执行协议 - [docs/platform-strategy.md](docs/platform-strategy.md) —— 平台化策略(SessionIR 定位为有损观测投影的论证) - [docs/sandbox.md](docs/sandbox.md) —— 沙箱隔离:架构、tier 语义、验收探针、Windows 上的硬限制 - [portal/README.md](portal/README.md) —— 数据门户:静态分析站 + Gitee 门禁下载(API / 登录 / 测试清单) - [portal/部署手册.md](portal/部署手册.md) —— 自包含的部署手册(含 bench.db 与三个下载数据包的口径) - [portal/docs/DESIGN.md](portal/docs/DESIGN.md) —— 门户的设计说明(页面、取数、门禁与限流) ## License [MIT](LICENSE)