# 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)




[](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)