Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 58 additions & 44 deletions benchmarks/proactivity_eval/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
```
proactivity_eval/
├── README.md
├── FINDINGS-v12.md 历史 baseline 数据(旧版本对照)
├── runners.config.yaml 系统/agent 路径与 provider 默认
├── data/
│ ├── pbench/test_data.jsonl pbench 输入(ProactiveAgent reward_data S1 protocol, vendored)
Expand All @@ -22,7 +21,7 @@ proactivity_eval/
│ ├── _common/ backends + drivers + shared helpers
│ ├── agents/{raven,hermes,openclaw}/ per-agent config + adapter glue
│ ├── benchmarks/{pbench,longrun}/ per-benchmark config
│ ├── prompts/ pbench 各 agent 模板
│ ├── prompts/ pbench 模板(统一最小模板:prompts/uniform/)
│ ├── pa_scorecard.py / longrun_scorecard.py 聚合脚本
│ └── README.md runner 用法
└── output/ JSON + scorecard
Expand All @@ -31,101 +30,116 @@ proactivity_eval/
## 实验结果

### Agent 版本
| Agent | Version / 包版本 | Date |

两张结果表均为 latest 版本实测(pbench 于 2026-07-22 用统一 prompt 重测;longrun 于 2026-07-23 用新 harness + 新计分器全量重跑,三家统一走 OpenRouter qwen3.5-27b):

| Agent | pbench 主表(2026-07-22,latest) | longrun(2026-07-23,latest) |
|---|---|---|
| **Raven** | `raven 0.1.0` | 2026-04-28 |
| **Hermes** | `hermes-agent 0.10.0` | 2026-04-18 |
| **OpenClaw** | `openclaw 2026.2.1` | 2026-02-03 |
| **Raven** | `raven 0.1.2` | `raven 0.1.2` |
| **Hermes** | `hermes-agent 0.19.0` @ `9eb7b1a6`(2026-07-20,dev install) | `hermes-agent 0.19.0` @ `9eb7b1a6` |
| **OpenClaw** | `openclaw 2026.6.34`(docker,ghcr digest `25f5bacf5174…`) | `openclaw 2026.6.34`(docker) |


### 结果

**pbench** (N=120 reward_data):单轮"该不该 surface help"决策同 backend qwen3.5-27B
**pbench** (N=120 reward_data):单轮"该不该 surface help"决策。所有 agent 使用**统一最小任务 prompt**(无人设、无决策原则,模板见 `runners/prompts/uniform/`),各自 CLI 黑盒调用,同 backend qwen3.5-27b(OpenRouter)

| Agent | TP | FP | TN | FN | Precision | Recall | F1 | mean/record |
|---|---:|---:|---:|---:|---:|---:|---:|---:|
| **Raven** | 27 | 4 | 47 | 42 | 0.871 | 0.391 | **0.540** | 11.0s |
| **Hermes** (v0.10) | 10 | 0 | 51 | 59 | **1.000** | 0.145 | 0.253 | 17.1s |
| **OpenClaw** | 10 | 0 | 51 | 59 | **1.000** | 0.145 | 0.253 | 24.7s |
| Agent | 调用方式 | TP/FP/TN/FN¹ | Precision | Recall | F1(3 runs mean) | mean/record |
|---|---|---:|---:|---:|---:|---:|
| **Raven** (0.1.2) | `raven agent --message` | 48.0/17.3/33.7/21.0 | 0.735 | **0.696** | **0.715**(0.707–0.725) | 19.4s |
| **OpenClaw** (2026.6.34) | `openclaw agent --local`(docker) | 44.0/16.0/35.0/25.0 | 0.733 | 0.638 | 0.682(0.641–0.722) | 15.4s |
| **Hermes** (v0.19.0) | `hermes chat -q -Q` | 33.7/13.3/37.7/35.3 | 0.717 | 0.488 | 0.579(0.545–0.628) | 25.5s |

Hermes / OpenClaw 完美 `Precision=1.000` 是**架构性保守**——只在 very confident 时说 yes;代价是 `Recall=0.145` 远低于 Raven 的 0.391
¹ 三次独立运行的均值(括号内为 F1 逐轮范围),2026-07-22 实测。分数是**版本快照**,不代表最新版本能力。

**longrun** (6 persona × 30 day):跨日 anticipatory proactivity,同 backend qwen3.5-27B

**longrun** (6 persona × 30 day):跨日 anticipatory proactivity,同 backend qwen3.5-27b(OpenRouter)

| 能力维度 | Raven | Hermes | OpenClaw | 含义 |
|---|---|---|---|---|
| **Anticipatory** ⭐<br>(rubric Type A 命中) | **19/43 (44%)** | 0/43 | 0/43 | "agent 没被告知就想到该做"——只有 L3 Sentinel 能做 |
| **Scheduled execution**<br>(delivered **cron** fires, trajectory-derived)³ | **109 fires**<br>(+155 sentinel anticipatory) | 115 fires<br>(原生 cron) | 61 fires²<br>(MCP-gateway) | user 显式说"X 时提醒"后 agent 是否真的注册并 fire |
| **Reactive Q&A**<br>(rubric Type B 命中) | 15/21 (71%) | **18/21 (86%)** | 11/21 (52%) | user 问问题时 agent 答对率 |
| **Restraint** 🛑<br>(rubric Type C 命中)¹ | 10/21 (48%)<br>31/62 pts | **16/21 (76%)**<br>49/62 pts | **16/21 (76%)**<br>49/62 pts | DND / 频率 / 周末 constraint 是否被破坏(不该 fire 时是否克制) |
| **Anticipatory** ⭐<br>(rubric Type A 命中) | **19/43 (44%)** | 1/43 (2%) | 1/43 (2%) | "agent 没被告知就想到该做"——自主注册预判 / Sentinel 主动 surface |
| **Scheduled execution**<br>(delivered **cron** fires, trajectory-derived)² | 109 fires<br>(+87 sentinel anticipatory) | 103 fires<br>(原生 cron)³ | **267 fires**<br>(MCP-gateway, repeat)¹ | user 显式说"X 时提醒"后 agent 是否真的注册并 fire |
| **Reactive Q&A**<br>(rubric Type B 命中) | 6/21 (29%) | **10/21 (48%)** | 5/21 (24%) | user 问问题时 agent 答对率 |
| **Restraint** 🛑<br>(rubric Type C 命中) | 12/21 (57%) | **17/21 (81%)**| 16/21 (76%) | DND / 频率 / 周末 constraint 是否被破坏(不该 fire 时是否克制) |

¹ OpenClaw 经捆绑的 MCP cron server(gateway 模式,详见 [`data/longrun/README.md`](data/longrun/README.md#3-openclaw-reactive--mcp-gateway-cron-baseline))注入 `set_reminder` 工具后注册并触发 cron。桥现已支持 `repeat`(daily/weekdays/weekly)。

¹ longrun 结果数据源(均以当前 `longrun_scorecard.py` 同版重打分,确保口径一致);同 backend qwen3.5-27B
² **Scheduled execution 只计 cron fire**。衡量"用户显式预约的提醒是否真的注册并触发",是 cron 的职责;Raven 的 sentinel anticipatory fire 属于 Anticipatory 维,作旁注 `(+N sentinel)` 显示但**不计入**本行。三家分别 109 / 103 / 267 fire(此维由 caregiver 每日服药提醒主导,且受 recurring vs one-shot 注册风格影响,波动大;OC 因 MCP-gateway repeat 明显偏高),说明三家都能可靠触发用户预约——**不作能力排名**

² OpenClaw 经捆绑的 MCP cron server(gateway 模式,详见 [`data/longrun/README.md`](data/longrun/README.md#3-openclaw-reactive--mcp-gateway-cron-baseline))注入 `set_reminder` 工具后能注册并触发 cron(61 fires)。OC 的 cron 为**一次性**(非 recurring),需 agent 每天重新注册;以 caregiver(每日 3 药)为例,OC 前 ~15 天逐日 re-arm,此后停止重新注册、cron fire 干涸(trajectory 仍为完整 30 天、对话正常)。对照 Hermes 把 3 药注册为 recurring job,05-27~30 无对话仍照常 fire。OC 的 61 是其一次性模型下未能维持循环提醒的**欠发下界,非克制**
³ **Hermes 的 suggestions 通道在本 harness 无得分路径**:v0.19 的建议投递是 pull-only(用户主动 pull `hermes suggestions` 才可见)。harness 以 `cron_suggestion` 事件记录每条生成的建议(observability,不代投递、不计分),数量单独统计。 **OpenClaw 嵌入模式的 session 卫生由 harness 代行**:`agent --local` 不做 compaction 也不轮换 session,固定 session 跑 30 天在 2026.6.34 上第 5 天即撞上下文墙("Context overflow",其后每轮报错)。harness 按其**产品自身默认**(`session_reset: at_hour 4`)每模拟日轮换 session,跨日记忆走其 workspace MEMORY.md bootstrap

³ **Scheduled execution 只计 cron fire**(`longrun_scorecard.py::_count_delivered_fires` 的 `total = cron`)。这一维衡量"用户显式预约的提醒是否真的注册并触发",是 cron 的职责;Raven 的 sentinel anticipatory fire 属于 Anticipatory 维,作旁注 `(+N sentinel)` 显示但**不计入**本行。


**四个维度反映的差距:**

- **Anticipatory**:EC 19 vs Hermes 0 vs OC 0 是**架构级差距**——L3 Sentinel 是唯一能在用户没显式提示时主动 surface 的层。Hermes/OC 永远是 0(cron 不管原生还是 MCP-gateway,都只能执行已注册的 job,不能"预知")
- **Scheduled execution**(cron fire,见 ³):EC 109 / Hermes 115 / OC 61。整个 longrun cron 应有量 ≈ 100–110,EC 的 109 落在合理区间,OC 61 偏低(欠注册)。EC 另有 155 次 sentinel anticipatory fire,归在 Anticipatory 维、不计入本行
- **Reactive Q&A**:EC 15/21 (71%) / Hermes 18/21 (86%) / OC 11/21 (52%)。同 backend qwen-27B 下 Hermes 最稳;OC 在多个 persona 的问答上回退(freelancer 0/4、parent 2/4)
- **Restraint**:EC 10/21 vs Hermes 16/21 vs OC 16/21。**Anticipatory 和 Restraint 是同一硬币的两面**——会主动 fire 的 agent 同时也更容易撞到 quiet_hours / bedtime / 周末 窗口。Hermes / OC 拿到接近满分(16/21)的代价是 **Anticipatory=0**——这是 "几乎不主动 ⇒ 几乎不违例" 的廉价分,**只看 Restraint 单维会奖励 always-hold agent**,必须和 Anticipatory / Scheduled execution 联合判读
- **Anticipatory**:Raven 19/43 (44%) vs Hermes 1/43 (2%) vs OC 1/43 (2%)——在决策归属计分(用户预约的提醒全部排除)、sonnet 强法官下,Raven 有领先的主动提醒倾向
- **Scheduled execution**(cron fire):Raven 109 / Hermes 103 / OC 267——三家都能可靠注册并触发用户预约的提醒;此维由 caregiver 每日服药提醒主导、且受 recurring vs one-shot 风格影响,波动大,**不作能力排名**(见脚注 ²)
- **Reactive Q&A**:Raven 6/21 (29%) / Hermes 10/21 (48%) / OC 5/21 (24%),sonnet judge 打分
- **Restraint**:Raven 12/21 (57%) vs Hermes 17/21 (81%) vs OC 16/21 (76%)。**Anticipatory 和 Restraint 是同一硬币的两面**——越主动,越可能在用户不期望的时间打扰到用户(Raven 主动性最高,故 restraint 最低)


## 用法

> 下方命令均从 repo 根目录运行;`<OUT>` = 输出目录(默认 `benchmarks/proactivity_eval/output/`)。

### pbench

```bash
# Smoke (n=10 stratified, ~3 min)
# smoke(n=10 分层抽样,~3min),默认统一最小 prompt(结果表口径)
uv run python benchmarks/proactivity_eval/runners/run.py \
--agent raven --benchmark pbench --n 10 --context-mode cold \
--output benchmarks/proactivity_eval/output/pbench-smoke.json
--output <OUT>/pbench-smoke.json

# Full (n=120, ~30-40 min)
# 全量(n=120~30-40min)
uv run python benchmarks/proactivity_eval/runners/run.py \
--agent raven --benchmark pbench --n 120 --context-mode cold \
--output benchmarks/proactivity_eval/output/pbench-n120.json
--output <OUT>/pbench-n120.json

# hermes 走自带 CLI(结果表口径的 hermes 通道)
uv run python benchmarks/proactivity_eval/runners/hermes_cli_pbench.py \
--n 120 --concurrency 6 \
--home-template <含 config.yaml/.env/auth.json 的目录> \
--output <OUT>/pbench-hermes-cli.json

# Scoring → markdown table
# 旧的各 agent 人设模板仅用于复现消融附表:加 --prompts-dir benchmarks/proactivity_eval/runners/prompts

# 打分 → markdown 表
uv run python benchmarks/proactivity_eval/runners/pa_scorecard.py \
--ec-agent-cold benchmarks/proactivity_eval/output/pbench-n120.json \
--output benchmarks/proactivity_eval/output/pbench-n120-scorecard.md
--ec-agent-cold <OUT>/pbench-n120.json \
--output <OUT>/pbench-n120-scorecard.md
```

### longrun

`run.py` writes trajectories to `output/longrun/` by default, and
`longrun_scorecard.py` reads/writes the same dir by default. To score a
snapshot stored elsewhere (e.g. `output/post-C-cleanup-d30/`), pass
`--output-dir` to the scorecard — no need to move files. (`run.py` has
its own `--output-dir` for choosing where trajectories land.)
`run.py` 默认把轨迹写到 `<OUT>/longrun/`,`longrun_scorecard.py` 默认读写同一目录。
要对存放在别处的快照打分,给 scorecard 传 `--output-dir` 即可,无需搬文件
(`run.py` 也有自己的 `--output-dir`,决定轨迹落盘位置)。

```bash
# Smoke (single persona, 1 day, ~5 min) — output → output/longrun/ by default
# smoke(单 persona,1 天,~5min),默认输出到 <OUT>/longrun/
uv run python benchmarks/proactivity_eval/runners/run.py \
--agent raven --benchmark longrun --case parent-01 --day-limit 1

# Full (all 6 personas × 30 days; expect hours)
# 全量(6 persona × 30 天,耗时数小时)
uv run python benchmarks/proactivity_eval/runners/run.py \
--agent raven --benchmark longrun --all

# Score one persona×agent (reads output/longrun/longrun-<persona>-<agent>-trajectory.jsonl)

# 单个 persona×agent 打分(读 <OUT>/longrun/longrun-<persona>-<agent>-trajectory.jsonl)
uv run python benchmarks/proactivity_eval/runners/longrun_scorecard.py \
--persona parent-01 --agent raven

# Score all personas + per-persona comparison + 跨 persona × agent capability 表
# (产出本 README 上面那张 longrun 结果表的 markdown:output/longrun/aggregate-scorecard.md)
# 全部 persona 打分 + persona 对比 + 跨 persona×agent 能力表
# 产出本 README 上面那张 longrun 结果表:<OUT>/longrun/aggregate-scorecard.md
uv run python benchmarks/proactivity_eval/runners/longrun_scorecard.py \
--all --compare --aggregate

# 只重新生成 aggregate 表(已有 *-scorecard.json 时不重跑评分)
uv run python benchmarks/proactivity_eval/runners/longrun_scorecard.py --aggregate

# Score / aggregate a snapshot in a non-default dir (no file moving)
# 对非默认目录的快照打分/聚合(无需搬文件)
uv run python benchmarks/proactivity_eval/runners/longrun_scorecard.py \
--aggregate --output-dir benchmarks/proactivity_eval/output/post-C-cleanup-d30
--aggregate --output-dir <OUT>/<snapshot>
```

详见 `runners/README.md`。
Loading
Loading