All checks were successful
CI / test (pull_request) Successful in 4m7s
新增纯函数模块 evaluation/go_no_go.py,基于 RunSummary 指标自动生成 go/no-go/conditional 三级结论。 - AcceptanceCriteria 模型:judged_pass_rate_min、pass_rate_min、avg_latency_max_ms - GoNoGoVerdict 模型:decision、summary、criteria_results - evaluate_go_no_go() 纯函数:接收 summary dict + criteria -> 返回 verdict - 集成到 generate_report(),报告 dict 自动附带 go_no_go 字段 - 三级结论:go(全部达标)、no_go(核心未达标)、conditional(有风险) - 新增 9 项单元测试(642 tests passed) Closes #20
139 lines
4.2 KiB
Python
139 lines
4.2 KiB
Python
"""Tests for go/no-go acceptance verdict."""
|
|
|
|
import pytest
|
|
|
|
from agenteval.evaluation.go_no_go import (
|
|
AcceptanceCriteria,
|
|
CriterionResult,
|
|
GoNoGoVerdict,
|
|
evaluate_go_no_go,
|
|
)
|
|
|
|
|
|
def test_go_verdict_all_pass():
|
|
"""All criteria met -> go."""
|
|
summary = {
|
|
"judged_pass_rate": 0.96,
|
|
"pass_rate": 0.95,
|
|
"avg_latency_ms": 2000,
|
|
}
|
|
criteria = AcceptanceCriteria(
|
|
judged_pass_rate_min=0.95,
|
|
pass_rate_min=0.90,
|
|
avg_latency_max_ms=5000,
|
|
)
|
|
verdict = evaluate_go_no_go(summary, criteria)
|
|
assert verdict.decision == "go"
|
|
assert "达标" in verdict.summary
|
|
assert all(r.passed for r in verdict.criteria_results)
|
|
|
|
|
|
def test_no_go_verdict_core_failed():
|
|
"""Core metric (pass rate) failed -> no_go."""
|
|
summary = {
|
|
"judged_pass_rate": 0.80,
|
|
"pass_rate": 0.75,
|
|
}
|
|
criteria = AcceptanceCriteria(
|
|
judged_pass_rate_min=0.95,
|
|
pass_rate_min=0.90,
|
|
)
|
|
verdict = evaluate_go_no_go(summary, criteria)
|
|
assert verdict.decision == "no_go"
|
|
assert "不建议上线" in verdict.summary
|
|
assert any(not r.passed for r in verdict.criteria_results)
|
|
|
|
|
|
def test_conditional_verdict_non_core_risk():
|
|
"""Core passed but non-core (latency) failed -> conditional."""
|
|
summary = {
|
|
"judged_pass_rate": 0.96,
|
|
"pass_rate": 0.95,
|
|
"avg_latency_ms": 8000,
|
|
}
|
|
criteria = AcceptanceCriteria(
|
|
judged_pass_rate_min=0.95,
|
|
pass_rate_min=0.90,
|
|
avg_latency_max_ms=5000,
|
|
)
|
|
verdict = evaluate_go_no_go(summary, criteria)
|
|
assert verdict.decision == "conditional"
|
|
assert "风险" in verdict.summary
|
|
|
|
|
|
def test_default_criteria():
|
|
"""Default criteria should be applied when None."""
|
|
summary = {
|
|
"judged_pass_rate": 0.96,
|
|
"pass_rate": 0.95,
|
|
}
|
|
verdict = evaluate_go_no_go(summary, None)
|
|
assert verdict.decision == "go"
|
|
assert len(verdict.criteria_results) >= 1
|
|
|
|
|
|
def test_empty_summary():
|
|
"""Empty summary -> conditional with no results."""
|
|
verdict = evaluate_go_no_go({}, None)
|
|
assert verdict.decision == "conditional"
|
|
assert "无可用指标" in verdict.summary
|
|
assert len(verdict.criteria_results) == 0
|
|
|
|
|
|
def test_criterion_result_model():
|
|
"""CriterionResult model should work correctly."""
|
|
result = CriterionResult(
|
|
criterion="pass_rate",
|
|
threshold=0.95,
|
|
actual=0.96,
|
|
passed=True,
|
|
detail="通过率 96% >= 95%",
|
|
)
|
|
assert result.criterion == "pass_rate"
|
|
assert result.passed is True
|
|
|
|
|
|
def test_verdict_model():
|
|
"""GoNoGoVerdict model should work correctly."""
|
|
verdict = GoNoGoVerdict(
|
|
decision="go",
|
|
summary="测试通过",
|
|
criteria_results=[],
|
|
)
|
|
assert verdict.decision == "go"
|
|
assert verdict.generated_at is not None
|
|
|
|
|
|
def test_latency_only_when_configured():
|
|
"""Latency should only be checked when avg_latency_max_ms is set."""
|
|
summary = {
|
|
"judged_pass_rate": 0.96,
|
|
"avg_latency_ms": 10000, # High latency
|
|
}
|
|
# Without latency threshold
|
|
criteria_no_latency = AcceptanceCriteria(judged_pass_rate_min=0.95)
|
|
verdict1 = evaluate_go_no_go(summary, criteria_no_latency)
|
|
assert verdict1.decision == "go"
|
|
assert all(r.criterion != "avg_latency_ms" for r in verdict1.criteria_results)
|
|
|
|
# With latency threshold
|
|
criteria_with_latency = AcceptanceCriteria(
|
|
judged_pass_rate_min=0.95,
|
|
avg_latency_max_ms=5000,
|
|
)
|
|
verdict2 = evaluate_go_no_go(summary, criteria_with_latency)
|
|
assert verdict2.decision == "conditional"
|
|
assert any(r.criterion == "avg_latency_ms" for r in verdict2.criteria_results)
|
|
|
|
|
|
def test_judged_pass_rate_fallback_to_pass_rate():
|
|
"""If judged_pass_rate is missing, fall back to pass_rate."""
|
|
summary = {"pass_rate": 0.96}
|
|
criteria = AcceptanceCriteria(judged_pass_rate_min=0.95)
|
|
verdict = evaluate_go_no_go(summary, criteria)
|
|
assert verdict.decision == "go"
|
|
# Should have one result using pass_rate as judged_pass_rate
|
|
assert len(verdict.criteria_results) == 1
|
|
assert verdict.criteria_results[0].criterion == "judged_pass_rate"
|
|
assert verdict.criteria_results[0].actual == 0.96
|