# AgentEvalTool v0.2 版本发布说明

**版本**: v0.2.0  
**日期**: 2026-07-14  
**状态**: 已发布(t480 开发线)  
**代号**: 「稳」(Stability milestone)  
**作者**: AgentEval Team

---

## 一、版本定位

v0.2 是 v0.1 MVP 之后的**第一个稳定性里程碑**,遵循「先稳后拓」的两步走战略中的第一步。核心目标:

> 让核心闭环(定义评测 → 执行评测 → 查看报告)具备**生产可用性**,为后续的平台化扩展(v0.3)打下坚实的工程基础。

**战略上下文**

```
v0.1 (2026-07-09)  MVP 闭环跑通
   │
   ├── v0.2 (2026-07-14)  ← 你在这里:稳定性 + 工程债 + 安全基线
   │
   └── v0.3 (规划中)      多通道 + 规则扩展 + OpenClaw 深度集成
```

**关键决策**(用户确认 2026-07-14)
- 定位:两步走,先稳后拓
- 规模:个人/小团队(<10 人),SQLite 足够
- 引擎:**async 全面重构**
- OpenClaw:**深度集成,插件双向调用**

---

## 二、主要变更

### 2.1 EvalEngine 全面异步化(核心改造)

| 项目 | v0.1 | v0.2 |
|---|---|---|
| Engine 模型 | 同步串行,阻塞 event loop | 全 async/await,协作式并发 |
| 取消机制 | 假取消(只改 DB 状态) | 真取消(asyncio.Event + CancelledError) |
| 超时配置 | 硬编码 30s/60s | `TimeoutConfig` 数据类,可配置 |
| 并发执行 | 不支持 | `max_concurrent_cases` + Semaphore |
| 通道抽象 | 同步 `send`/`poll_reply` | 全 async,支持 poll 与 push 两种实现 |
| HTTP 客户端 | `requests`(每次新建连接) | `httpx.AsyncClient`(连接池复用) |

**关键文件改动**
- `backend/agenteval/evaluation/engine.py` — 全量 async 重写,`run()`/`_run_case()`/`_generate_messages()` 全部 async
- `backend/agenteval/channels/base.py` — `EvalChannel` 三个方法全部 `async def`
- `backend/agenteval/channels/tutu.py` — `requests` → `httpx.AsyncClient`,实例级连接池
- `backend/agenteval/web/routers/runs.py` — `BackgroundTasks` → `asyncio.Task` 注册表 + 真取消
- `backend/agenteval/web/websocket.py` — 删除 `broadcast_sync` 桥接,新增 `emit()` 异步回调
- `backend/cli/run.py` + `cli/target.py` — `asyncio.run()` 包装,CLI 签名不变

### 2.2 安全基线(P0)

| 项 | v0.1 | v0.2 |
|---|---|---|
| 配置管理 | 硬编码在源码 | Pydantic Settings + `.env` 文件 |
| JWT token | 明文存 `config/config.json` 已 commit | `.gitignore` 保护,`.env.example` 模板 |
| CORS | `allow_origins=["*"]` 硬编码 | 从 `settings.allowed_origins` 读取 |
| API 鉴权 | 无 | `X-API-Key` middleware(未配置时 no-op) |
| OpenClaw proxy | 硬编码 origin/token | 全部从 settings 读取 |
| OpenClaw Origin | 硬编码 `http://192.168.8.145:8001` | **从 `allowed_origins` 自动推导** |

**关键文件改动**
- `backend/agenteval/config/settings.py` — Pydantic Settings 模块,`@model_validator` 自动推导 `openclaw_ws_origin`
- `backend/agenteval/web/deps.py` — 集中 `get_db` + `require_api_key`
- `backend/agenteval/web/routers/proxy.py` — 零硬编码,全部从 settings 读取
- `.gitignore` / `.env.example` / `config/config.example.json` — 新建

### 2.3 存储层去债

| 项 | v0.1 | v0.2 |
|---|---|---|
| Schema 迁移 | `create_all()` 一次性 | Alembic + 版本化 migration |
| `get_db` | 5 个 router 重复定义 | 集中到 `web/deps.py` |
| `utcnow()` | 已废弃的 `datetime.utcnow()` | `datetime.now(timezone.utc)` |
| 级联删除 | 无 | ORM 级联 `EvalRunDB → turns/results` |

**关键文件改动**
- `migrations/` — Alembic 初始化,baseline migration `15c107310eea_baseline_add_llm_config.py`
- `backend/agenteval/storage/db.py` — 添加 `Relationship` + `cascade="all, delete-orphan"`
- `backend/agenteval/storage/repository.py` — 新增 `RunRepository.delete()`
- `deploy/t480/Dockerfile` — CMD 改为 `alembic upgrade head && agenteval server start`

### 2.4 前端重构

| 项 | v0.1 | v0.2 |
|---|---|---|
| `useRunSession` | 7 个 useState + 120 行 `applyEvent` | `useReducer` + 纯函数 reducer |
| 对话渲染 | CaseBlock/CaseDetail/Reports 三处重复 | 抽出 `TurnList` 公用组件 |
| AI 生成消息 | 两处重复 | 抽出 `GeneratedMessages` |
| 工具函数 | 分散在页面文件 | 集中到 `utils/date.ts` / `utils/colors.ts` |
| Reports 页 URL query | 不读取 `?run=xxx` | 支持,可分享链接 |

**关键文件改动**
- `frontend/web/src/hooks/sessionReducer.ts` — 纯函数 reducer(300+ 行),可单测
- `frontend/web/src/hooks/useRunSession.ts` — useReducer 化
- `frontend/web/src/components/TurnList.tsx` / `GeneratedMessages.tsx` — 新建
- `frontend/web/src/utils/date.ts` / `colors.ts` — 新建
- `frontend/web/src/pages/Reports.tsx` — 支持 `?run=xxx` URL query

### 2.5 测试基线(从 0 起步)

| 测试文件 | 数量 | 覆盖 |
|---|---|---|
| `tests/unit/test_engine.py` | 10 | async engine 并发/取消/超时/send 失败 |
| `tests/unit/test_cascade.py` | 3 | ORM 级联删除(target/scenario/run) |
| `tests/unit/test_settings.py` | 6 | `openclaw_ws_origin` 自动推导逻辑 |
| `tests/integration/test_runs_api.py` | 5 | API 集成(list/start/cancel/logs/404) |
| **合计** | **24** | **57% 整体覆盖率**(engine 61%, runs.py 86%, db.py 94%) |

**基础设施**
- `tests/conftest.py` — tmp SQLite fixture + 表结构 sanity check
- `tests/unit/mock_channel.py` — 可配置 MockChannel(延迟/失败/缺失回复)
- `pyproject.toml` — `asyncio_mode=auto`, `pythonpath=["backend", "."]`

### 2.6 部署规范化

| 项 | v0.1 | v0.2 |
|---|---|---|
| 版本号 | 前后端独立维护 | **pyproject.toml 单一数据源** |
| 部署流程 | 手动 rsync + docker compose up | `scripts/deploy-t480.sh` 一键部署 |
| 镜像 tag | 仅 `latest` | `<version>` + `latest` 双 tag |
| 构建元数据 | 无 | `/api/health` 返回 `version/commit/built_at` |
| 部署验证 | 人工 | 脚本自动 curl + 校验 version/commit |
| .env 挂载 | 无 | docker-compose 挂载 `.env` 进容器 |

**关键文件改动**
- `scripts/deploy-t480.sh` — 一键部署脚本(build/sync/rebuild/verify)
- `scripts/sync_version.py` — 版本号同步脚本
- `backend/agenteval/version.py` — 版本 + 构建元数据模块
- `deploy/t480/Dockerfile` — `ARG BUILD_COMMIT/BUILD_TIME` → `ENV AGENTEVAL_BUILD_*`
- `deploy/t480/docker-compose.yml` — 挂载 `.env` + `env_file`
- `AGENT.md` — 新部署流程 + 镜像 tag 约定 + 踩坑 #6/#7

---

## 三、关键 Bug 修复

| 编号 | 问题 | 根因 | 修复 |
|---|---|---|---|
| BUG-1 | 评测执行页点任务记录报 React #310 错误 | `useMemo` 在 early return 之后,违反 Hooks 规则 | 移动 `useMemo` 到 early return 之前 |
| BUG-2 | AI 助手页面显示登录页 | proxy.py 重构后 `openclaw_ws_origin` 默认 `None`,OpenClaw 拒收 WS | `@model_validator` 从 `allowed_origins` 自动推导 |
| BUG-3 | 评测执行页回到老版本 | rsync 排除了 `frontend/web/dist`,t480 跑旧 dist | `deploy-t480.sh` 强制 `npm run build` 后再 rsync |
| BUG-4 | 容器启动报 `duplicate column: llm_config` | t480 DB 已手动 ALTER,但 Alembic 不知道 | `docker run alembic stamp head` 标记 baseline |
| BUG-5 | `cancel` API 是假取消 | 只改 DB 状态,Engine 线程继续跑 | Engine 接受 `cancel_token`,每个 case 边界检查 |

---

## 四、架构演进图

```
v0.1 (MVP)
├── 同步 EvalEngine → BackgroundTasks → SQLite (StaticPool)
├── 单通道 (tutu-api) / 3 规则 / HTML+JSON 报告
├── 零测试 / 硬编码敏感信息 / 无鉴权
└── 手动 rsync + docker compose up

v0.2 「稳」 ← 当前版本
├── async Engine + Semaphore + CancelToken → asyncio.Task 注册表
├── SQLite (aiosqlite 预留) + Alembic 迁移
├── APIKey 鉴权 / .env 配置 / 24 单测 + 集成测试 / CI 配置就位
├── 前端 useReducer 重构 useRunSession / 抽出 TurnList/GeneratedMessages
└── scripts/deploy-t480.sh 一键部署 + 镜像版本 tag + /api/health 验证

v0.3 「拓」(规划中)
├── 多通道 (tutu/http/openclaw) 插件化
├── 7 种规则 + 组合逻辑 (AND/OR/weighted)
├── 报告对比 + 模板外置
├── OpenClaw webhook 双向集成
└── 前端路由 + TanStack Query
```

---

## 五、文件改动统计

```
新增文件 (20):
  backend/agenteval/config/__init__.py
  backend/agenteval/config/settings.py
  backend/agenteval/version.py
  backend/agenteval/web/deps.py
  migrations/{alembic.ini, env.py, script.py.mako, README}
  migrations/versions/15c107310eea_baseline_add_llm_config.py
  scripts/deploy-t480.sh
  scripts/sync_version.py
  tests/{conftest.py, __init__.py}
  tests/unit/{mock_channel.py, test_engine.py, test_cascade.py, test_settings.py}
  tests/integration/test_runs_api.py
  frontend/web/src/hooks/sessionReducer.ts
  frontend/web/src/hooks/useTicker.ts
  frontend/web/src/components/{TurnList, GeneratedMessages}.tsx
  frontend/web/src/utils/{date, colors}.ts
  .gitignore, .env.example, config/config.example.json

重大改动 (10):
  backend/agenteval/evaluation/engine.py     (async 重写)
  backend/agenteval/channels/{base, tutu}.py (async + httpx)
  backend/agenteval/web/app.py               (lifespan + /api/health)
  backend/agenteval/web/routers/{runs, targets, scenarios, reports, stats, proxy}.py
  backend/agenteval/storage/db.py            (Relationship + cascade)
  frontend/web/src/hooks/useRunSession.ts    (useReducer)
  frontend/web/src/pages/Reports.tsx         (?run=xxx URL query)
  deploy/t480/{Dockerfile, docker-compose.yml}
  pyproject.toml, AGENT.md
```

---

## 六、已知问题

| 编号 | 问题 | 影响 | 计划修复 |
|---|---|---|---|
| KNOWN-1 | Repository 未抽象泛型基类 | 4 个 Repository 重复代码 | v0.3 评估收益后决定 |
| KNOWN-2 | `_generate_messages` 未测试 | LLM 动态用例生成路径无覆盖 | v0.2 后续补 |
| KNOWN-3 | `commit=no-git`(项目未 git init) | `/api/health` 无法显示真实 SHA | 用户决定后 `git init` |
| KNOWN-4 | 前端无单元测试 | reducer 已抽出但未写测试 | v0.3 引入 vitest |
| KNOWN-5 | Rules 覆盖率低(15-30%) | 规则逻辑无测试 | v0.3 规则扩展时同步补 |

---

## 七、部署验证

**t480 当前状态**(2026-07-14)
```bash
$ curl http://192.168.8.145:8001/api/health
{
  "status": "ok",
  "version": "0.2.0-dev",
  "commit": "no-git",
  "built_at": "2026-07-14T10:33:41Z"
}

$ docker ps
agenteval      Up (healthy)   t480-agenteval:0.2.0-dev
openclaw-eval  Up (healthy)   ghcr.io/openclaw/openclaw:latest
```

**一键部署命令**
```bash
scripts/deploy-t480.sh              # 完整部署
scripts/deploy-t480.sh --skip-build # 仅代码变更
scripts/deploy-t480.sh --dry-run    # 预览
```

---

## 八、下一步:v0.3 「拓」

v0.3 聚焦**平台化能力扩展**,预估工作量 4-5 周:

| 模块 | 目标 | 优先级 |
|---|---|---|
| 消息通道扩展 | HTTP + OpenClaw 通道实现 + entry_points 插件发现 | P0 |
| 评估规则扩展 | semantic_similarity / json_schema / safety / coherence + 组合逻辑 | P0 |
| OpenClaw 深度集成 | skill 触发评测 + webhook 完成通知(双向) | P1 |
| 报告能力升级 | 对比报告 / Markdown 导出 / 模板外置 | P1 |
| 场景能力增强 | 内置模板库 + 参数化场景 | P2 |
| 前端体验升级 | React Router data router + TanStack Query + 对比视图 | P2 |

---

## 九、致谢

v0.2 的完成得益于以下关键决策:
- 用户坚持「先稳后拓」的战略定力,避免了在 MVP 阶段过早平台化
- 选择 async 全面重构而非 Celery/RQ 任务队列,降低了运维复杂度
- 接受「小团队规模不需要多租户/PostgreSQL」的务实判断,避免了过度设计

**下一个里程碑:v0.3 「拓」,预计 2026-08 中旬。**
