AgentEvalTool/research/go-no-go-report.md
sinohqb 5827c3d3f5 docs(research): go/no-go 验收报告技术方案调研
调研现有报告生成能力(Run/Campaign/IntelligentEval 三套管线),
分析 go/no-go 结论的实现路径:纯函数判定核心 + 三级阈值配置 +
渐进式交付。估算总工作量 8 人天,推荐分阶段实施。

Refs: #20
2026-08-25 14:22:54 +08:00

370 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Go/No-Go 验收报告技术方案
> Ticket: [#20](https://git.solahqb22.cn/solahqb/AgentEvalTool/issues/20)
> Wayfinder: [#13](https://git.solahqb22.cn/solahqb/AgentEvalTool/issues/13)
> 日期: 2026-07-15
---
## 1. 现有报告能力分析
### 1.1 报告体系概览
系统当前有三套独立的报告生成管线:
| 报告类型 | 生成入口 | 渲染输出 | API 端点 |
|---------|---------|---------|---------|
| **单次运行报告** | `evaluation/report.py::generate_report()` | HTML / JSON / Markdown | `GET /api/reports/{run_id}` |
| **活动周期报告** | `evaluation/report.py::generate_campaign_report()` | JSON dict + Markdown | `GET /api/campaigns/{id}/report` |
| **智能评估报告** | `intelligent_eval/report.py::render_report_markdown()` | JSON + Markdown | `GET /api/intelligent-evals/{id}/report` |
### 1.2 单次运行报告Run Report
**数据源**`RunSummary` 模型(`models.py`),由 `build_run_summary()` 在引擎执行完毕后一次性写入。
**已有指标**
- `total_cases` / `passed_cases` / `failed_cases` -- 用例级计数
- `pass_rate` -- 含连通用例的全量通过率
- `judged_pass_rate` -- 剔除连通用例后的判定型通过率
- `total_rules` / `passed_rules` -- 规则级计数
- `avg_latency_ms` -- 平均延迟
- `case_outcomes` -- 每个用例的 passed/connectivity 权威判定
**结论性判断现状****无**。报告只呈现原始数字不做任何阈值比对。HTML 模板只有四个统计卡片(用例总数、通过用例、规则总数、规则通过率),没有"达标/不达标"标记。Markdown 输出同理,只列数据表格。
### 1.3 活动周期报告Campaign Report
**已有指标**
- `overall_pass_rate` / `overall_availability` / `avg_latency_ms` -- 整窗聚合
- `time_trend` -- 12 时段分桶的通过率/可用性/时延趋势
- `capability_summary` -- 按场景分组的指标汇总
- 智能分析LLM 诊断):总体结论 + 问题清单 + 改善建议
- 周期对比:基线 vs 本期的指标 delta + 趋势叙述
**结论性判断现状****部分**。智能分析的 `overall` 字段包含 LLM 生成的叙述性结论(如"整体表现稳定,建议关注场景 X 的退化"),但这是自然语言判断,不是机械的 go/no-go 判定。没有可配置的阈值比对逻辑。
### 1.4 智能评估报告Intelligent Eval Report
**已有指标**
- `scores.overall` + `scores.dimensions` -- 维度评分
- `findings` -- 问题发现(含 severity/dimension/evidence
- `priority_recommendations` -- 改进建议
**结论性判断现状****无**。有评分但无阈值判定。
### 1.5 已有的阈值机制(可复用)
| 层级 | 阈值 | 位置 | 用途 |
|------|------|------|------|
| 用例级 | `rule_pass_threshold` (默认 0.6) | `Case` 模型 | WEIGHTED 规则逻辑的加权分通过线 |
| 规则级 | `max_ms` | `ResponseTimeRule` | 单轮延迟上限 |
| 规则级 | `keywords_include/exclude` | `KeywordMatchRule` | 关键词匹配 |
| 用例级 | `coherence_min_score` | `Expectation` | 连贯性最低分(隐式规则) |
**关键发现**:系统已有完善的**用例级**判定链路(`judgement.combine_case_outcome` -> `build_run_summary` -> `case_outcomes`),但**完全缺少运行级/活动级的阈值判定**。go/no-go 需要填补的正是这个空白。
---
## 2. Go/No-Go 结论的实现方案
### 2.1 核心设计
新增一个纯函数模块 `evaluation/go_no_go.py`,职责单一:接收报告 dict + 阈值配置 -> 输出结构化结论。
```python
# 提议的数据模型
class AcceptanceCriteria(BaseModel):
"""上线验收标准"""
judged_pass_rate_min: float = 0.95 # 判定型通过率下限
pass_rate_min: float = 0.90 # 全量通过率下限
avg_latency_max_ms: Optional[float] = None # 平均延迟上限
availability_min: Optional[float] = None # 可用性下限(活动级)
no_high_severity_finding: bool = False # 不允许有高严重度发现(智能评估)
class GoNoGoVerdict(BaseModel):
"""Go/No-Go 结论"""
decision: str # "go" | "no_go" | "conditional"
summary: str # 人类可读结论,如"通过率 95%,达标,建议上线"
criteria_results: list[CriterionResult]
generated_at: datetime
class CriterionResult(BaseModel):
"""单条标准的比对结果"""
criterion: str # 标准名称
threshold: float # 阈值
actual: float # 实际值
passed: bool # 是否达标
detail: str # 说明
```
### 2.2 判定逻辑
```
function evaluate_go_no_go(report_dict, criteria):
results = []
// 1. 判定型通过率
if criteria.judged_pass_rate_min is set:
actual = report.summary.judged_pass_rate ?? report.summary.pass_rate
results.append(CriterionResult(
criterion="judged_pass_rate",
threshold=criteria.judged_pass_rate_min,
actual=actual,
passed=actual >= criteria.judged_pass_rate_min
))
// 2. 全量通过率
if criteria.pass_rate_min is set:
actual = report.summary.pass_rate
results.append(...)
// 3. 平均延迟
if criteria.avg_latency_max_ms is set:
actual = report.summary.avg_latency_ms
results.append(CriterionResult(
criterion="avg_latency",
threshold=criteria.avg_latency_max_ms,
actual=actual,
passed=actual <= criteria.avg_latency_max_ms
))
// 4. 可用性(活动级)
if criteria.availability_min is set:
actual = report.summary.overall_availability
results.append(...)
// 综合判定
all_passed = all(r.passed for r in results)
if all_passed:
decision = "go"
summary = f"通过率 {actual*100:.0f}%,达标,建议上线"
elif any critical failures:
decision = "no_go"
summary = f"通过率 {actual*100:.0f}%,未达标(阈值 {threshold*100:.0f}%),不建议上线"
else:
decision = "conditional"
summary = "部分指标达标,存在风险项,建议修复后复测"
return GoNoGoVerdict(decision, summary, results)
```
### 2.3 三级结论语义
| 结论 | 条件 | 含义 |
|------|------|------|
| **go** | 全部指标达标 | 建议上线 |
| **no_go** | 核心指标(通过率/可用性)未达标 | 不建议上线 |
| **conditional** | 核心达标但非核心指标(延迟等)有风险 | 建议修复后复测 |
### 2.4 报告渲染集成
**HTML 报告**:在 summary 卡片区域上方新增一个醒目的结论横幅:
- go: 绿色背景 "GO - 建议上线"
- no_go: 红色背景 "NO-GO - 不建议上线"
- conditional: 黄色背景 "CONDITIONAL - 存在风险"
下方增加一个"验收标准比对表",逐条列出阈值、实际值、是否达标。
**Markdown 报告**:在汇总表格后增加:
```markdown
## 上线验收结论
**结论**: GO / NO-GO / CONDITIONAL
| 指标 | 阈值 | 实际值 | 结果 |
|------|------|--------|------|
| 判定型通过率 | >= 95% | 96.2% | PASS |
| 平均延迟 | <= 5000ms | 3200ms | PASS |
```
**JSON 报告**:在顶层新增 `go_no_go` 字段,包含完整的 `GoNoGoVerdict` 结构。
### 2.5 API 设计
**方案 A推荐**:在现有报告端点中自动附带
```
GET /api/reports/{run_id}
-> { ...existing report..., go_no_go: { decision, summary, criteria_results } }
```
优点:前端无需改动调用逻辑,结论随报告自动返回。
缺点:需要知道使用哪套阈值 -> 从 Scenario 或全局配置读取。
**方案 B**:独立端点
```
GET /api/reports/{run_id}/verdict?pass_rate_min=0.95&latency_max=5000
```
优点:阈值灵活,可按需传入。
缺点:增加前端调用复杂度。
**推荐方案 A**,因为阈值应该在创建评测时就确定(绑定到 Scenario 或全局配置),而非每次查看报告时指定。
---
## 3. 达标阈值的配置方式
### 3.1 配置层级设计
```
全局默认Settings
└── 场景级覆盖Scenario.acceptance_criteria
└── 运行级覆盖EvalRun.acceptance_criteria可选
```
**优先级**:运行级 > 场景级 > 全局默认
### 3.2 具体实现位置
| 层级 | 存储位置 | 配置方式 |
|------|---------|---------|
| **全局默认** | `config/settings.py` 新增字段 | 环境变量 `AGENTEVAL_DEFAULT_PASS_RATE_MIN=0.95` |
| **场景级** | `Scenario` 模型新增 `acceptance_criteria: Optional[AcceptanceCriteria]` | API/前端创建场景时配置 |
| **运行级** | `EvalRun` 模型新增 `acceptance_criteria: Optional[AcceptanceCriteria]`(或从 Scenario 继承) | 创建 run 时可选覆盖 |
### 3.3 全局默认配置示例
```python
# settings.py 新增
default_acceptance_criteria: dict[str, Any] = Field(
default_factory=lambda: {
"judged_pass_rate_min": 0.95,
"pass_rate_min": 0.90,
},
description="Default acceptance criteria for go/no-go verdicts.",
)
```
### 3.4 场景级配置示例
在 Scenario 模型中新增可选字段:
```python
class Scenario(BaseModel):
# ... existing fields ...
acceptance_criteria: Optional[dict[str, Any]] = None
# 例如: {"judged_pass_rate_min": 0.98, "avg_latency_max_ms": 3000}
```
前端在场景编辑页增加"验收标准"配置区域(折叠面板),默认展示全局默认值,用户可覆盖。
### 3.5 数据库迁移
需要 Alembic 迁移脚本为 `scenarios` 表和 `eval_runs` 表添加 `acceptance_criteria` JSON 列。SQLite 的 `render_as_batch=True` 已配置,迁移无特殊障碍。
---
## 4. 工作量估算
### 4.1 后端
| 任务 | 人天 | 说明 |
|------|------|------|
| `evaluation/go_no_go.py` 核心判定逻辑 | 0.5 | 纯函数,单测覆盖 |
| `AcceptanceCriteria` / `GoNoGoVerdict` 数据模型 | 0.5 | Pydantic 模型 |
| `RunSummary` / `Scenario` 模型扩展 | 0.5 | 新增字段 + 兼容处理 |
| `generate_report()` 集成 go_no_go 结论 | 0.5 | 在报告 dict 中附加 verdict |
| `report_render.py` 三种格式渲染 | 1.0 | HTML 横幅 + Markdown 表格 + JSON 字段 |
| `settings.py` 全局默认配置 | 0.25 | 新增 Settings 字段 |
| Alembic 迁移 | 0.25 | scenarios + eval_runs 加列 |
| API 端点调整 | 0.5 | reports router 附带 verdict |
| 单元测试 + 集成测试 | 1.0 | go_no_go 逻辑 + API 覆盖 |
| **后端小计** | **5.0** | |
### 4.2 前端
| 任务 | 人天 | 说明 |
|------|------|------|
| 场景编辑页增加"验收标准"配置 | 1.0 | FormDrawer 内新增折叠面板 |
| Run 报告详情页展示 go/no-go 结论 | 1.0 | 结论横幅 + 比对表格 |
| 活动报告页展示活动级结论 | 0.5 | 复用组件 |
| **前端小计** | **2.5** | |
### 4.3 总计
| 模块 | 人天 |
|------|------|
| 后端 | 5.0 |
| 前端 | 2.5 |
| 联调 + 部署 | 0.5 |
| **总计** | **8.0 人天** |
如果只做后端API 返回 verdict前端后续迭代可压缩到 **5.0 人天**
---
## 5. 推荐方案
### 5.1 推荐:方案 A + 三级配置 + 渐进式交付
**理由**
1. **纯函数核心**`go_no_go.py`):与现有架构一致(`metrics.py` / `run_summary.py` 都是纯函数),易测试、易扩展。
2. **三级阈值配置**(全局默认 -> 场景级 -> 运行级):
- 全局默认保证开箱即用,不需要每个场景都配置
- 场景级覆盖满足差异化需求(如关键场景要求 98% 通过率)
- 运行级覆盖保留灵活性(如临时加严测试)
3. **自动附带而非独立端点**:前端零改动即可获得 verdict 数据,降低集成成本。
4. **三级结论go/no_go/conditional**:比二元判定更实用。"conditional" 覆盖了"通过率达标但延迟偏高"这类常见场景,避免误判。
5. **复用现有指标**:不需要新增数据采集,`judged_pass_rate` / `pass_rate` / `avg_latency_ms` / `availability` 均已由引擎计算并持久化。go/no-go 只是在读路径上增加一层阈值比对。
### 5.2 实施路径
```
Phase 1MVP5 人天):
- go_no_go.py 核心逻辑
- 全局默认阈值Settings
- generate_report() 集成
- JSON/Markdown 渲染
- 单元测试
Phase 2完善3 人天):
- 场景级 acceptance_criteria 配置
- HTML 渲染(结论横幅)
- 前端场景编辑页配置面板
- 前端报告展示页结论展示
Phase 3可选增强:
- 活动级 go/no-go跨 run 聚合判定)
- 智能评估报告的评分阈值集成
- Webhook 推送 verdictCI/CD 集成)
```
### 5.3 关键决策点
| 决策 | 推荐 | 备选 | 理由 |
|------|------|------|------|
| 核心指标选择 | `judged_pass_rate` 为主 | `pass_rate` | 连通用例无判定意义,`judged_pass_rate` 更准确反映质量 |
| 阈值存储 | JSON 列(灵活) | 独立表(规范化) | 阈值结构简单且固定JSON 足够,避免过度设计 |
| 结论渲染位置 | 报告顶部横幅 | 报告底部 | 结论应第一时间可见,类似体检报告的"总结" |
| 活动级 go/no-go | Phase 3 再做 | 同期实现 | 活动级需要跨 run 聚合,复杂度较高,且 ticket #20 聚焦单次验收 |
### 5.4 与现有架构的契合度
- **ADR-0002通过率口径**go/no-go 直接消费 `judged_pass_rate`,口径一致
- **ADR-0004聚合口径**:活动级聚合复用 `aggregate_runs`,不重算
- **规则注册表模式**go_no_go 判定器可设计为可扩展的(未来可能增加新指标)
- **纯函数渲染**:遵循 `report_render.py` 的 dict-in/string-out 模式
---
## 附录:关键代码路径
| 文件 | 职责 |
|------|------|
| `backend/agenteval/evaluation/report.py` | 报告生成(`generate_report` / `generate_campaign_report` |
| `backend/agenteval/evaluation/report_render.py` | 报告渲染HTML/Markdown/JSON |
| `backend/agenteval/evaluation/run_summary.py` | 运行汇总(`build_run_summary` |
| `backend/agenteval/evaluation/metrics.py` | 跨运行聚合(`aggregate_runs` |
| `backend/agenteval/evaluation/judgement.py` | 用例判定(`combine_case_outcome` |
| `backend/agenteval/evaluation/case_verdict.py` | 用例判定读路径(`resolve_case_verdicts` |
| `backend/agenteval/models.py` | 数据模型(`RunSummary` / `Scenario` / `Case` |
| `backend/agenteval/config/settings.py` | 全局配置 |
| `backend/agenteval/web/routers/reports.py` | 报告 API 端点 |