AgentEvalTool/docs/release-notes-v0.2.md
sinohqb a77cd83e6a v0.2.0-dev: 文件管理 + 页面布局统一 + 6 个 bug 修复
## 新增功能
- 文件管理模块:分类树 + 文件上传/下载/删除
- 文件上传支持拖拽(Dragger)+ 手动上传(customRequest 模式)

## 页面布局统一(参照评测执行页)
- 仪表盘/评测对象/评测场景/评测报告 全部改为全高 flex 布局
- 统一内联页头样式(h2 + 竖线分隔 + 描述)
- 表格撑满高度、overflow 处理
- 每页添加刷新按钮

## Bug 修复
- 分类树操作按钮 hover 不可见(CSS 规则缺失)
- 文件上传失败(multipart boundary 缺失)
- LLM API 响应 content blocks 数组格式支持(_extract_content_from_api_response)
- response_time_max_ms 被静默忽略(隐式规则传空 params)
- 空 messages 导致 IndexError 崩溃
- poll_reply 异常中止整个 run(缺 try/catch)
- engine finally 未关闭 session
- 3 个页面 UTC 时间戳解析偏差 8 小时

## 后端
- EvalEngine: poll_reply 异常保护、空 dialog 保护、session 关闭
- LLM API 响应解析支持 content-block-array 格式
- 隐式 response_time 规则正确传递 max_ms 参数

## 前端
- api.ts: 移除手动 Content-Type(让浏览器自动添加 boundary)
- Files.tsx: customRequest 替代 beforeUpload、布局优化
- index.css: 分类树 hover 规则
- Targets/Scenarios/Home/Reports: 全高布局改造
- 3 个页面时间戳改用 formatDateTime()(修复 UTC 偏差)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-16 15:25:22 +08:00

275 lines
12 KiB
Markdown

# 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 中旬。**