AgentEvalTool/CLAUDE.md
sinohqb 0096c22e27
All checks were successful
CI / test (push) Successful in 3m58s
docs: v1.1.1 release notes + ADR-0010 + context/CLAUDE updates
更新本次智能评估全链路修复与 UI/UX 优化的必要文档:
- ADR-0010 新增:方案③触发采用独立 OpenClaw session(main 持久 session 上下文
  缓存污染导致 worker 幻觉不执行)+ 时段分布约束
- CONTEXT.md:触发式执行词条补充时段约束与独立会话语义
- release-notes-v1.1.1.md 新增:智能评估全链路稳定化、任务队列监控、UI/UX 一致性
- docs/README.md:补 v1.1.0/v1.1.1 发布说明索引,版本升 v1.2
- CLAUDE.md:补智能评估执行机制(方案③)章节(scan loop 职责 + 独立 session/
  时段分布/状态一致性关键约束)
2026-08-18 19:01:14 +08:00

12 KiB
Raw Blame History

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

项目概述

AgentEvalTool 是智能体质量评估工具集平台v0.2.0),用于评估 AI 数字员工tutu-api 通道)和 AI 助手OpenClaw的服务质量。Python 3.11 后端 + TypeScript/React 前端SQLite 持久化。

常用命令

后端

# 安装(含 dev 依赖)
pip install -e ".[dev]"

# 启动 Web 后台
agenteval server start --host 0.0.0.0 --port 8000

# 运行全部测试
pytest

# 运行单个测试文件
pytest tests/unit/test_engine.py -v

# 运行带覆盖率的测试
pytest --cov=backend/agenteval --cov-report=term-missing

# Lint
ruff check backend/
ruff format backend/

前端

cd frontend/web
npm install
npm run dev        # 开发服务器
npm run build      # 构建生产产物(部署前必须执行)
npx tsc --noEmit   # 类型检查

数据库迁移

alembic upgrade head   # 升级到最新
alembic revision --autogenerate -m "描述"  # 生成新迁移

注意:init_db() 调用 SQLModel.metadata.create_all() 直接建表(用于全新 DBAlembic 用于已有 DB 的增量变更。migrations/env.py 设置了 render_as_batch=TrueSQLite 不支持 ALTER TABLEbatch mode 通过重建表来模拟)。

部署t480

scripts/deploy-t480.sh             # 一键部署(推荐)
scripts/deploy-t480.sh --skip-build  # 仅代码变更,跳过镜像重建
scripts/deploy-t480.sh --dry-run   # 预览命令

核心架构

三层结构

CLI (Typer) / Web API (FastAPI)
        ↓
EvalEngine异步评测执行引擎
        ↓ 通过抽象接口
EvalChannel → 消息通道TutuApiChannel
EvalRule    → 评估规则keyword_match / response_time / llm_score
        ↓
SQLite StorageRepository 模式)

关键抽象(均在 backend/agenteval/

  • channels/base.pyEvalChannel 抽象:send() / poll_reply() / health_check()V1 实现为 TutuApiChanneltutu-api HTTP + Bearer Token
  • evaluation/engine.pyEvalEngine:异步执行,遍历 Scenario.cases → messages → 调用 channel → 执行规则 → 写入 DB通过 asyncio.Event cancel_token 支持真取消;progress_callback 实时推送事件给 WebSocket
  • evaluation/rules/EvalRule 抽象,三种实现:keyword.py(关键词匹配)、response_time.py(延迟阈值)、llm_score.pyLLM-as-judge
  • models.py — 共享 Pydantic 模型:EvalTargetEvalRunScenarioEvalRunTurn + EvalResult
  • storage/db.pySQLite StaticPool + SQLModel 表定义)+ repository.pyTargetRepository / ScenarioRepository / RunRepository / ResultRepository+ file_repository.pyFileCategoryRepository / FileRecordRepository
  • config/settings.py — Pydantic Settings加载 AGENTEVAL_ 前缀的环境变量(.env 文件),@lru_cache 单例
  • web/deps.py — FastAPI 依赖注入:get_db()Session 生命周期管理)、require_api_key()X-API-Key 鉴权)

扩展性模式

  • 规则注册表evaluation/rules/__init__.py@register_rule 装饰器将规则类注册到 _RULE_REGISTRYget_rule(type, params) 按名称实例化。添加新规则只需创建类并加装饰器。
  • 通道工厂channels/factory.pyChannelFactory 维护 ChannelType → EvalChannel 映射,register() 类方法支持插件式注册新通道类型。

API 端点 / Run 生命周期

POST /api/runs → API 先创建 pending 状态的 run返回 run_id → 后台 asyncio.Task 调用 EvalEngine.run(existing_run=...) 复用该记录 → ws://…/ws/runs/{run_id} 推送实时进度。

WebSocket 事件类型/ws/runs/{run_id},由 ConnectionManager.emit() 广播):

事件 触发时机 payload
case_start 开始评测一个 case {case_id, case_index, total_cases}
messages_generated 动态 case 的 AI 生成消息完成 {case_id, messages}
turn_start 开始发送一轮对话 {case_id, turn_index}
turn_end 收到回复 {case_id, turn_index, reply, latency_ms}
turn_error 发送或接收失败 {case_id, turn_index, error}
rule_result 单条规则评估完成 {case_id, turn_index, rule_type, passed, score, reason}
case_end case 评测完成 {case_id, passed, score, error?}
run_completed 整个 run 完成 {run_id, status}
error case 级或 run 级错误 {case_id?, message}

前端 sessionReducer.tsWS_EVENT action 处理以上所有事件类型。

OpenClaw 代理

后端通过 routers/proxy.py 提供 HTTP + WebSocket 反向代理(路径前缀 /openclaw),将请求转发到 OpenClaw 服务docker-compose 中 openclaw-eval 容器。WS 桥接会自动注入认证 token 到 connect.authenticate 消息并重写 Origin 头。前端 /openclaw 路由以全屏 iframe 嵌入代理地址。

智能评估执行机制(方案③触发式执行)

智能评估的 Worker 自动化(取代旧 Cron 池,见 ADR-0009/0010app.py::_intelligent_eval_scan_loop 驱动lifespan 后台任务,每 60s

  1. requeue_stale_assigned_tasksassigned 超时(>10min且评估 executing → 回 pending卡死恢复
  2. scan_and_enqueue_tasks:扫描 executing 评估,时段到期/欠账 → 入队(任务队列)
  3. settle_tasks_for_finished_evals:评估离开 executing 后,其 pending/assigned 任务回收为 completed
  4. _supplement_decision_logsagent 未上报决策日志时按状态兜底补录
  5. 触发:有 planning 评估 → 触发 planner skill有 pending 任务 → 触发 worker skill

关键约束:

  • 独立 session:触发命令必须带 --session-idagenteval-worker-<ts> / agenteval-planner-<ts>禁止复用 --agent main 的持久 session——main session 多次触发累积上下文缓存后 worker 会幻觉不执行(见 ADR-0010
  • 时段分布:触发指令明确"仅执行当前到期时段内欠账的会话",平台每 60s 持续触发推进后续时段,保证 1h 窗口按时段分批
  • 状态一致性submit_report 要求会话全部 close 才允许 completedworker 触发 timeout 600s

文件管理模块

/api/files 端点提供分类树 + 文件上传/下载功能。FileCategoryDB 自引用(parent_id)实现树形结构,FileRecordDB 关联分类。文件物理存储在 data/uploads/,按分类子目录组织。删除分类会级联删除子分类 + 文件记录 + 物理文件。

前端

SPA 由 FastAPI 托管(GET /{full_path:path}index.html)。frontend/web/src/api.ts 是所有接口定义的单一出口axios 拦截器统一处理错误。useRunSession.ts hook 管理 WebSocket 实时状态。

路由采用 keep-alive 标签页模式(非标准 <Routes>):所有页面同时挂载在 DOM 中,通过 display: block/none 切换可见性,保证页面状态在切 tab 时不丢失。路由配置集中在 App.tsxrouteConfigs 数组中Zustand tabStore 管理标签页的打开/关闭/激活状态,react-router 仅用于 URL 同步。

三种状态管理策略

  • Zustandstores/tabStore.ts):全局标签页状态,唯一一个 store
  • useReducerhooks/sessionReducer.ts评测会话状态cases/turns/results/progress纯 reducer 无副作用hook 负责 WS/REST 副作用
  • useState:各页面本地数据,无全局缓存(不使用 SWR/React Query

Vite 开发代理dev server 端口 3000/api/ws/openclaw 全部代理到 localhost:8000;生产构建时 dist/ 由 FastAPI 直接托管。

Ant Design CSS-in-JS 冲突Ant Design v5 的 emotion 运行时注入会覆盖静态 CSS 的 flex/height 规则。Runs 页采用"导航与内容分离"方案——Tabs 组件仅用于渲染导航头(.nav-only-tabs CSS 隐藏 .ant-tabs-content-holder),实际内容 div 由 flex 直接控制高度,绕过 Ant Design 内部 DOM。

构建注意@monaco-editor/react 独立拆分为 vendor-monaco chunkvite.config.tsmanualChunks)。设计 Token 在 tokens.ts 集中管理(组件直接 import非 CSS 变量方案)。

开发约定

  • 版本号单一数据源pyproject.toml → 由 scripts/sync_version.py 同步到 package.json,部署脚本自动执行
  • Python lintruffline-length 120target py310
  • 前端类型检查tsc --noEmit
  • 文档文件名带版本号,如 architecture-v1.0.md
  • SQLite 必须用 StaticPool + check_same_thread=False,否则多线程下连接耗尽
  • 所有 Router 用 Depends(get_db) 管理 Session,后台任务也需 try/finally 关闭
  • frontend/web/dist/ 是构建产物,部署前必须 npm run build,否则 t480 跑旧版

配置

  • .env(参考 .env.exampleAGENTEVAL_API_KEYX-API-Key 鉴权)、AGENTEVAL_ALLOWED_ORIGINSCORS首个非 localhost URL 用作 OpenClaw WS OriginAGENTEVAL_OPENCLAW_* 系列(代理上游地址 + 认证 token
  • config/config.jsontutu-api 通道配置(敏感信息,只读挂载到容器)
  • 无 CI/CD部署依赖手动执行 scripts/deploy-t480.sh

测试结构

tests/
├── conftest.py          # 共享 fixtures内存 SQLite DB、TestClient
├── unit/
│   ├── mock_channel.py  # 测试用 MockChannel
│   ├── test_engine.py   # EvalEngine 单元测试asyncio_mode=auto
│   ├── test_cascade.py  # 级联删除测试
│   └── test_settings.py # Pydantic Settings 测试
└── integration/
    └── test_runs_api.py # Runs API 集成测试

pytest.ini_optionspythonpath = ["backend", "."],测试直接 import agentevalcli

Agent skills

Issue tracker

工作项跟踪使用 git.solahqb22.cn/solahqb/AgentEvalTool 的 Gitea Issues。详见 docs/agents/issue-tracker.md

Triage labels

Triage 使用五个默认角色标签。详见 docs/agents/triage-labels.md

Domain docs

仓库采用单一上下文:根目录 CONTEXT.md 配合 docs/adr/。详见 docs/agents/domain.md

部署关键信息

  • t480sola-t480192.168.8.145:8001Docker Compose 双容器agenteval + openclaw-eval
  • 端口映射:主机 8001 → 容器 8000主机 8000 已被占用)
  • 健康检查curl http://192.168.8.145:8001/api/health 返回 version/commit脚本验证与本地 pyproject.toml 一致
  • 回滚docker tag t480-agenteval:<old-version> t480-agenteval:latest && docker compose up -d
  • backend/ 通过 volume 热加载,只有 Python 依赖变更才需要 --build
  • 前端 dist/ 也通过 volume 挂载,因此每次前端变更也需要重新构建(./scripts/deploy-t480.sh 自动处理)
  • openclaw-eval 容器使用 ghcr.io/openclaw/openclaw:latest 镜像,通过 AGENTEVAL_API_URL 环境变量连接 agenteval

已知陷阱

  1. index.css 必须显式 importVite 不会自动包含未被引用的 CSS。main.tsx 必须有 import './index.css'否则全局样式动画、布局覆盖、nav-only-tabs全部无效且无报错。这是历史遗留 bug项目创建以来就缺失已修复但容易在重构时再次丢失。

  2. UTC 时间戳解析:后端返回的 datetime 字符串不含时区标记(如 "2026-07-14T16:40:00"JS 的 new Date() 会按本地时间解析导致偏差 8 小时。前端必须使用 utils/date.tstoDate() 函数(检测并追加 Z 后缀),禁止直接 new Date(str)。根本修复需后端序列化时附带时区。

  3. Ant Design CSS-in-JS 覆盖Ant Design v5 的 emotion 运行时注入优先级高于静态 CSS 文件中的 flex/height/overflow 规则。需要弹性布局的容器避免依赖 .ant-tabs-content 等 Ant 内部 DOM改用导航与内容分离方案。见上方前端架构说明。

  4. SQLite 连接池:必须用 StaticPool + check_same_thread=False。使用默认连接池会导致多线程下连接耗尽async + FastAPI 线程池混合场景)。

  5. .env 在 t480 上需手动维护:部署脚本不会自动同步 .env 文件,新增环境变量需 SSH 到主机手动补全。容易导致 OpenClaw 代理等功能静默失效。