# v0.9 规格说明：探索式评测第一期 —— 周期活动内嵌虚拟用户探索

**状态**: ready-for-agent
**日期**: 2026-08-03
**决策依据**: ADR-0003 v2 修订（2026-08-03）、CONTEXT.md「探索式评测」章节、grilling 共识清单（15 项）

## Problem Statement

平台的评测能力目前全部建立在"固定场景（考纲）"之上：预设题目、预设规则、统计通过率。这能回答"考纲过了多少"，回答不了"真实用户会踩到什么"——真实用户不按考纲出牌，他们会中途改主意、追问、被绕晕、放弃。被评智能体在面对这类复杂拟真行为时的表现（问题诊断与优化建议）目前没有任何评测手段。

## Solution

引入与固定场景并行的**探索式评测**模式：OpenClaw 作为**虚拟用户**，按活动配置的种子人设 × 种子目标自主与被评对象对话，产出**体验记录**（目标达成、卡点、被误导处），judge 岗位抽样复核，两条证据线汇入活动报告、v0.7 分析与 Markdown 导出。

第一期形态为**周期活动内嵌探索**：现有活动骨架不变（静态计划照常执行），全局一个常驻巡检代理（跑在已集成的 AI 助手上，heartbeat/cron 唤醒）按节拍巡检进行中的正式线活动，在预算内派发探索会话。OpenClaw 停摆只暂停探索，固定计划照常完成——耐久性归平台，自主性归代理。

## User Stories

1. As an 评测平台用户, I want 创建活动时配置该活动的种子集（种子人设 + 种子目标）, so that 虚拟用户的行动有据可依，且同种子集的活动跨期可比
2. As an 评测平台用户, I want 创建活动时调整探索预算（或使用平台默认值）, so that 探索行为的规模与负载在我的掌控之内
3. As an 平台运维者, I want 部署时 AI 助手注册一个全局常驻巡检作业, so that 所有进行中的正式线活动被自动巡检，无需逐活动配置
4. As an 常驻代理, I want 每次巡检唤醒时调平台巡检 API 拿到进行中活动、上次巡检以来的新结果与预算余量, so that 我能无状态地自主决定"继续观察 / 派探索会话"
5. As an 常驻代理, I want 通过 API 创建探索会话（指定活动、人设、目标、种子出处）, so that 我能以虚拟用户身份开始行动
6. As an 常驻代理, I want 通过会话 API 发消息并收到被评对象的回复, so that 我能按人设自主决定追问、等待、放弃
7. As an 常驻代理, I want 在会话结束时提交结构化体验记录, so that 我的第一手判定（达成/卡点/被误导）被平台留痕
8. As an 常驻代理, I want 超出预算时收到 API 明确的 409 拒绝与原因, so that 拒绝本身成为反馈信号，我及时收敛
9. As an 常驻代理, I want 在预算内从种子衍生变体（同目标换表达、同人设换追问策略）并被标记衍生出处, so that 行为多样性与留痕兼得
10. As an 评测平台用户, I want 在活动报告抽屉看到"探索发现"区块（会话数、目标达成率、问题清单）, so that 我知道真实用户遭遇了什么
11. As an 评测平台用户, I want 点开单个探索会话查看完整对话与体验记录, so that 每个"问题"都能下钻到原文证据
12. As an 分析岗位模型, I want 生成活动分析时收到探索摘要（问题清单 + 达成统计，非全量对话）, so that "固定场景成绩"与"真实用户遭遇"两条证据线合成一份结论
13. As an judge 岗位模型, I want 对抽样的探索对话做独立复核, so that 体验判定之外有客观质量维度（态度、专业性、幻觉）
14. As an 报告导出用户, I want Markdown 导出在存在探索数据时追加"探索发现"区块, so that 离线分享材料完整；无探索数据时导出与旧版一致
15. As an 加速调试线用户, I want 手动触发探索会话, so that 我能调试探索流程；同时加速线不被自动巡检打扰（时间压缩与拟真冲突）
16. As an 平台, I want OpenClaw 停摆时活动的固定计划照常走完, so that 探索是增强层而非单点故障
17. As an 平台, I want 活动窗口结束时仍未关闭的探索会话被妥善结算（标记状态、不再接受消息）, so that 不留悬挂会话
18. As an 评测平台用户, I want 探索会话与固定场景的子 Run 在报告里清楚区分, so that 通过率口径（ADR-0002）不被探索数据污染

## Implementation Decisions

### 数据模型

- 新增**探索会话**独立实体（不并入评测运行）：归属活动、指向评测对象、人设（JSON）、目标、种子出处（可空 = 衍生变体须回溯到种子）、状态机（running / completed / failed / expired）、触发来源（auto / manual）、体验记录 JSON、judge 复核 JSON、轮次计数、时间戳
- 新增会话轮次表（role、content、latency_ms、created_at），与评测运行的 turns 表平行，不复用
- 活动实体新增两个 JSON 配置字段（与 `plan` 同构地位）：**种子集**（种子人设数组 + 种子目标数组）、**探索预算**（最大会话数 / 单会话最大轮数 / 会话最小间隔，空则取平台默认）
- 活动实体新增 `last_patrolled_at`（巡检 API 每次读取后更新，支撑"上次巡检以来的新结果"语义）
- 三个变更各走一个 Alembic 迁移（batch mode）

### API 契约（全部 X-API-Key 鉴权，沿用 `require_api_key`）

- `GET /api/exploration/patrol`：返回进行中的正式线活动（time_scale == 1）清单，每项含活动 id/名称/对象、自 `last_patrolled_at` 以来的新结果摘要（复用 `build_campaign_report` 聚合口径）、探索预算余量；响应生成后更新各活动 `last_patrolled_at`
- `POST /api/exploration/sessions`：body = campaign_id、persona、goal、seed_ref（可空）；平台硬校验（活动存在且 running、正式线仅接受 auto 或 manual 触发；加速线仅接受 manual；预算余量）→ 创建 running 会话；超限 409 + 原因
- `POST /api/exploration/sessions/{id}/messages`：body = content；平台转发到目标的通道（复用 ChannelFactory）、持久化双方轮次、返回回复与延迟；单会话轮数超限 409；会话非 running 状态 409
- `POST /api/exploration/sessions/{id}/close`：body = 体验记录（goal_achieved: bool、blockers[]、misled[]、emotion、notes）；结构校验 + 非法值归一（沿 v0.7 白名单经验）；会话转 completed
- 探索发现读出口（实现裁决：不设独立 `/api/campaigns/{id}/exploration`，避免与报告链重复聚合）：
  - `GET /api/campaigns/{id}/report` 的 `exploration` 键携带探索发现聚合（会话数、达成率、问题清单、judge 复核），无探索数据时缺则无痕
  - `GET /api/exploration/campaigns/{id}/sessions`：会话列表（下钻用）
  - `GET /api/exploration/sessions/{id}/messages`：单会话对话记录（下钻用）
- 活动窗口 finalize 时：仍 running 的会话转 expired，不再接受消息（在 `resolve_finalize` 同处挂接）

### 护栏（平台硬执行，不信任客户端自律）

- 平台默认：≤8 会话/窗口、≤12 轮/会话、相邻会话 ≥30min（正式线真实时间）；活动级预算覆盖
- 预算计数是平台账本：创建/发消息/关闭均实时校验，超限一律 409

### 判定双证据线

- 体验判定：close 接口收结构化自报，为第一手证据
- judge 抽样复核：会话结束后平台对对话抽样（实现裁决：按「轮」抽样，默认 ≤3 轮即最多 6 条消息、每条截断 500 字符控 token），经 judge 岗位模型产出质量维度复核；ChatClient 可注入（沿 v0.7 分析 seam）；异步后台执行，失败落错误不阻塞

### 报告 / 分析 / 导出

- 活动报告聚合新增"探索发现"维度（会话数、目标达成率、问题清单来自体验记录聚合）；judge 复核结论一并纳入（实现裁决：findings 全量收各档发现、poor 档排前，而非只收 poor）；周期对比口径不变（探索数据不参与）
- v0.7 分析输入追加探索**摘要**（问题清单 + 达成统计，非全量对话）
- Markdown 导出：存在探索数据时追加「探索发现」附录（缺则无痕），附录顺序：智能分析 → 周期对比 → 探索发现

### 前端

- 活动创建表单：种子集与预算配置输入（种子可留空 = 该活动不参与探索）
- 报告抽屉新增「探索发现」区块（模式沿 v0.7 智能分析区块）：达成率、问题清单、会话列表；会话点开查看完整对话 + 体验记录
- 不建新顶级页面

### AI 助手侧（不在平台代码仓内的行为，契约即平台 API）

- 现有已集成 OpenClaw（AI 助手菜单、openclaw-eval 容器）上扩展巡检/探索 skill，走部署脚本既有 skill 同步管线
- 注册一个全局常驻 heartbeat/cron 巡检作业（节拍默认 1h）；巡检 API 本身与节拍无关

### 档位

- 正式线（time_scale == 1）：自动巡检 + 自动派发
- 加速调试线：仅手动触发会话，不参与自动巡检

## Testing Decisions

- 好测试只测外部行为：API 契约、状态机迁移、护栏拒绝、聚合口径、渲染产物；不测内部编排细节
- **集成测试（TestClient，主力接缝）**：会话生命周期（创建→对话→关闭）、护栏 409 各分支（超会话数/超轮数/间隔不足/加速线 auto 拒绝）、巡检 API 内容与 last_patrolled_at 推进、finalize 结算 expired、报告/导出纳入。先例：`test_campaigns_api.py`、`test_campaign_comparison_api.py`
- **纯函数单测**：探索发现聚合 + Markdown 渲染（dict 进 string 出）。先例：`test_report_render.py`
- **假客户端测试**：judge 抽样复核与分析输入扩展，注入假 ChatClient。先例：`test_campaign_analysis.py`
- 前端仅 `tsc --noEmit`（无 vitest，沿用现状）
- AI 助手 skill 行为不进自动化测试，靠部署后端到端验证（与 v0.4 以来 agenteval-run skill 验收方式一致）

## Out of Scope

- 双轨之二「探索活动」独立活动类型（OpenClaw 全权接管生命周期）——后续里程碑
- 周期对比扩展（探索数据跨期对照）——待种子集指纹与达成率口径稳定
- 计划条目重排（原 ADR-0003 v2 字面意义的"自适应重规划"）——本期代理只派发探索会话，不改写静态计划
- 全局种子库/人设库（活动级配置已够，复用需求出现再提取）
- 事件驱动唤醒（纯 heartbeat/cron 巡检）
- 前端测试基线（vitest）
- volcengine-102 同步

## Further Notes

- 词汇表与 ADR 已先行落地（commit c35159f）：CONTEXT.md「探索式评测」章节、ADR-0003 v2 修订
- 巡检 API 的"新结果摘要"复用 `build_campaign_report` 聚合口径，不重算新指标
- OpenClaw heartbeat/cron 事实依据：作业持久化 SQLite、重启不丢、瞬态错误重试、连续 10 次失败自动禁用——天然熔断，与"决策点不可用则跳过"的可靠性边界吻合
- 里程碑目录 `.scratch/v0.9/`，票据由 `/to-tickets` 生成于 `issues/`
