aeval-framework 0.2.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/.gitignore +13 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/PKG-INFO +2 -2
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/pyproject.toml +5 -2
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/__init__.py +1 -1
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/api/app.py +28 -1
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/api/routes/runs.py +11 -36
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/api/routes/tasks.py +2 -1
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/cli.py +569 -107
- aeval_framework-0.3.0/src/agent_eval/core/comparison.py +340 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/core/contract.py +281 -0
- aeval_framework-0.3.0/src/agent_eval/core/discovery.py +149 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/core/metrics.py +389 -0
- aeval_framework-0.3.0/src/agent_eval/core/packaging.py +442 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/core/runner.py +695 -43
- aeval_framework-0.3.0/src/agent_eval/core/simulator.py +144 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/core/types.py +679 -4
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/graders/_evidence.py +5 -1
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/graders/metric.py +28 -19
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/graders/model_based.py +100 -12
- aeval_framework-0.3.0/src/agent_eval/graders/presentation_probes.py +392 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/graders/state_check.py +19 -2
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/metrics/__init__.py +8 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/metrics/answer_relevancy.py +3 -9
- aeval_framework-0.3.0/src/agent_eval/metrics/base.py +352 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/metrics/batch_evaluation.py +12 -6
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/metrics/context_precision.py +4 -10
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/metrics/context_recall.py +4 -9
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/metrics/faithfulness.py +4 -10
- aeval_framework-0.3.0/src/agent_eval/metrics/llm_judge.py +179 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/metrics/prompt_metric.py +6 -3
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/metrics/pytest_plugin.py +106 -28
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/metrics/report.py +89 -5
- aeval_framework-0.3.0/src/agent_eval/packs/__init__.py +8 -0
- aeval_framework-0.3.0/src/agent_eval/packs/starter/README.md +30 -0
- aeval_framework-0.3.0/src/agent_eval/packs/starter/manifest.json +8 -0
- aeval_framework-0.3.0/src/agent_eval/packs/starter/suite.yaml +29 -0
- aeval_framework-0.3.0/tests/smoke_achat_runner.py +94 -0
- aeval_framework-0.3.0/tests/test_agent_metric_catalog.py +474 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_api.py +44 -0
- aeval_framework-0.3.0/tests/test_baseline_comparison.py +250 -0
- aeval_framework-0.3.0/tests/test_cli.py +706 -0
- aeval_framework-0.3.0/tests/test_conversation.py +772 -0
- aeval_framework-0.3.0/tests/test_discovery.py +267 -0
- aeval_framework-0.3.0/tests/test_environment_identity.py +339 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_eval_dataset_api.py +3 -3
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_eval_metric_pipeline.py +6 -7
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_eval_metrics_module.py +14 -14
- aeval_framework-0.3.0/tests/test_eval_pytest_plugin.py +540 -0
- aeval_framework-0.3.0/tests/test_holdout_and_canary.py +301 -0
- aeval_framework-0.3.0/tests/test_metric_roles_gates_agreement.py +734 -0
- aeval_framework-0.3.0/tests/test_packaging.py +436 -0
- aeval_framework-0.3.0/tests/test_power_analysis.py +133 -0
- aeval_framework-0.3.0/tests/test_presentation_probes.py +710 -0
- aeval_framework-0.3.0/tests/test_prompt_determinism.py +210 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_regrade_and_archive.py +249 -0
- aeval_framework-0.2.0/.coverage +0 -0
- aeval_framework-0.2.0/src/agent_eval/metrics/base.py +0 -212
- aeval_framework-0.2.0/src/agent_eval/metrics/llm_judge.py +0 -100
- aeval_framework-0.2.0/tests/test_cli.py +0 -361
- aeval_framework-0.2.0/tests/test_eval_pytest_plugin.py +0 -282
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/README.md +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/api/__init__.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/api/events.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/api/routes/__init__.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/api/routes/datasets.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/api/routes/graders.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/api/routes/metrics.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/api/routes/suites.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/api/standalone.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/core/__init__.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/core/pricing.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/core/redaction.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/core/suite.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/dataset/__init__.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/dataset/models.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/dataset/quality.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/dataset/sources/__init__.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/dataset/sources/llm_generator.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/dataset/sources/manual.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/dataset/sources/regression.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/dataset/sources/trace_mining.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/dataset/storage.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/dataset/version.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/examples/__init__.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/examples/basic_usage.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/examples/mock_runner.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/graders/__init__.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/graders/_verdicts.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/graders/artifact_check.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/graders/code_based.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/graders/human.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/graders/step_level.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/graders/tool_calls.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/graders/transcript.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/metrics/synthetic_data.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/storage/__init__.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/storage/memory.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/storage/sqlite.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/trace/__init__.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/trace/mapping.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/trace/normalize.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/trace/observations.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/src/agent_eval/trace/phoenix.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/conftest.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_builtin_graders.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_collection_phases.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_e2e.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_eval_batch_evaluation.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_eval_dataset_sources.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_eval_dataset_storage.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_eval_metrics_api.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_eval_prompt_metric.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_eval_report.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_eval_task_history.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_evidence_capture_and_storage.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_graders.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_import_isolation.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_metrics.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_run_storage_fields.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_runner.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_sse.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_standalone_api.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_suite.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_termination_and_budgets.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_trace_normalization.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_trial_evidence.py +0 -0
- {aeval_framework-0.2.0 → aeval_framework-0.3.0}/tests/test_vocabulary_isolation.py +0 -0
|
@@ -9,6 +9,7 @@ build/
|
|
|
9
9
|
.ruff_cache/
|
|
10
10
|
*.db
|
|
11
11
|
*.sqlite3
|
|
12
|
+
.coverage
|
|
12
13
|
|
|
13
14
|
# Node / Next.js (dashboard)
|
|
14
15
|
node_modules/
|
|
@@ -24,3 +25,15 @@ Thumbs.db
|
|
|
24
25
|
|
|
25
26
|
# Editor-local state (Qoder)
|
|
26
27
|
.qoder/
|
|
28
|
+
|
|
29
|
+
# AI tool state
|
|
30
|
+
.claude/
|
|
31
|
+
.codex/
|
|
32
|
+
.meituan-catpaw/
|
|
33
|
+
|
|
34
|
+
# Run artifacts & scratch notes
|
|
35
|
+
.live-run-output.txt
|
|
36
|
+
testlist.txt
|
|
37
|
+
|
|
38
|
+
# Personal (never commit)
|
|
39
|
+
docs/eval-harness-interview-prep.md
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: aeval-framework
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Aeval — open-source agent evaluation framework driven by OTel traces (suites, graders, metrics, storage, API, CLI)
|
|
5
5
|
Project-URL: Homepage, https://github.com/QiYuyyds/Aeval
|
|
6
6
|
Project-URL: Repository, https://github.com/QiYuyyds/Aeval
|
|
7
7
|
Project-URL: Documentation, https://github.com/QiYuyyds/Aeval/tree/main/docs
|
|
8
|
-
Project-URL: Changelog, https://github.com/QiYuyyds/Aeval/
|
|
8
|
+
Project-URL: Changelog, https://github.com/QiYuyyds/Aeval/blob/main/CHANGELOG.md
|
|
9
9
|
Author: Aeval contributors
|
|
10
10
|
License: MIT
|
|
11
11
|
Keywords: agents,evaluation,llm,otel,testing,tracing
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# Distribution name: aeval-framework (PyPI). Python module: agent_eval, CLI: eval-suite.
|
|
3
3
|
# (`agent-eval` on PyPI belongs to an unrelated project — UK AISI agenteval.)
|
|
4
4
|
name = "aeval-framework"
|
|
5
|
-
version = "0.
|
|
5
|
+
version = "0.3.0"
|
|
6
6
|
description = "Aeval — open-source agent evaluation framework driven by OTel traces (suites, graders, metrics, storage, API, CLI)"
|
|
7
7
|
readme = "README.md"
|
|
8
8
|
requires-python = ">=3.11"
|
|
@@ -52,7 +52,7 @@ eval-suite = "agent_eval.cli:main"
|
|
|
52
52
|
Homepage = "https://github.com/QiYuyyds/Aeval"
|
|
53
53
|
Repository = "https://github.com/QiYuyyds/Aeval"
|
|
54
54
|
Documentation = "https://github.com/QiYuyyds/Aeval/tree/main/docs"
|
|
55
|
-
Changelog = "https://github.com/QiYuyyds/Aeval/
|
|
55
|
+
Changelog = "https://github.com/QiYuyyds/Aeval/blob/main/CHANGELOG.md"
|
|
56
56
|
|
|
57
57
|
[build-system]
|
|
58
58
|
requires = ["hatchling"]
|
|
@@ -60,6 +60,9 @@ build-backend = "hatchling.build"
|
|
|
60
60
|
|
|
61
61
|
[tool.hatch.build.targets.wheel]
|
|
62
62
|
packages = ["src/agent_eval"]
|
|
63
|
+
# src/agent_eval/packs/** (含 starter pack 的 suite.yaml/manifest.json) 作为
|
|
64
|
+
# package data 随 wheel 分发 —— `eval-suite run demo` 的零 setup 首跑依赖它;
|
|
65
|
+
# 仓库 packs/starter/ 与之同源, tests/test_packaging.py 钉住两侧一致。
|
|
63
66
|
|
|
64
67
|
[tool.pytest.ini_options]
|
|
65
68
|
asyncio_mode = "auto"
|
|
@@ -22,6 +22,7 @@ from typing import Any
|
|
|
22
22
|
from fastapi import FastAPI
|
|
23
23
|
|
|
24
24
|
from agent_eval.api.routes import datasets, graders, metrics, runs, suites, tasks
|
|
25
|
+
from agent_eval.core.metrics import MIN_ALIGNED_RATINGS_FOR_AGREEMENT
|
|
25
26
|
from agent_eval.core.runner import EvalRunner
|
|
26
27
|
from agent_eval.core.types import (
|
|
27
28
|
DEFAULT_BOOTSTRAP_ROUNDS,
|
|
@@ -82,6 +83,7 @@ def statistics_defaults() -> dict[str, Any]:
|
|
|
82
83
|
"bootstrap_rounds": DEFAULT_BOOTSTRAP_ROUNDS,
|
|
83
84
|
"min_valid_trials_for_saturation": MIN_VALID_TRIALS_FOR_SATURATION,
|
|
84
85
|
"gate_invalid_ratio_limit": DEFAULT_INVALID_RATIO_LIMIT,
|
|
86
|
+
"min_aligned_ratings_for_agreement": MIN_ALIGNED_RATINGS_FOR_AGREEMENT,
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
|
|
@@ -95,6 +97,21 @@ def meta_payload(
|
|
|
95
97
|
同一大版本内响应结构向后兼容, 但统计口径的数值语义可能变化 —— 口径版本
|
|
96
98
|
必须显式公布, 调用方才能判断两个 run 是否可直接比较。
|
|
97
99
|
"""
|
|
100
|
+
# 扩展点发现与 CLI 同源 (core/discovery.discover_extensions):
|
|
101
|
+
# 两处给出的自定义判据/环境/模拟器名字集合必须一致, 不允许
|
|
102
|
+
# 「接口看得见、命令行用不上」的分歧 (spec: cli)。
|
|
103
|
+
from agent_eval.core.discovery import discover_extensions
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
discovered = discover_extensions().catalog()
|
|
107
|
+
except Exception: # noqa: BLE001 — 元数据异常不阻断 /meta
|
|
108
|
+
discovered = {}
|
|
109
|
+
discovered_graders = [e["name"] for e in discovered.get("graders", [])]
|
|
110
|
+
builtin_graders = [g["name"] for g in get_grader_catalog()]
|
|
111
|
+
# 发现的自定义判据追加在内置之后 (去重); 与 CLI extensions 清单同一份来源
|
|
112
|
+
graders = sorted(builtin_graders) + sorted(
|
|
113
|
+
n for n in discovered_graders if n not in builtin_graders
|
|
114
|
+
)
|
|
98
115
|
return {
|
|
99
116
|
"name": "Aeval",
|
|
100
117
|
"package": DISTRIBUTION_NAME,
|
|
@@ -118,7 +135,12 @@ def meta_payload(
|
|
|
118
135
|
"capture_is_one_declaration": True,
|
|
119
136
|
},
|
|
120
137
|
"capabilities": {
|
|
121
|
-
"graders":
|
|
138
|
+
"graders": graders,
|
|
139
|
+
"extensions": discovered,
|
|
140
|
+
"user_simulation": True,
|
|
141
|
+
"run_event_injection": True,
|
|
142
|
+
"judgment_moments": ["at_end", "not_at_end", "any_time", "after_last_event"],
|
|
143
|
+
"environment_identity_boundary": True,
|
|
122
144
|
"storage": ["memory", "sqlite"],
|
|
123
145
|
"trace_providers": ["phoenix (optional, lazily imported)"],
|
|
124
146
|
"sse": True,
|
|
@@ -131,6 +153,11 @@ def meta_payload(
|
|
|
131
153
|
"cost_axis": True,
|
|
132
154
|
"evidence_provenance_levels": True,
|
|
133
155
|
"deferred_grading": True,
|
|
156
|
+
# ④ agent 指标目录: 证据感知测量上下文 / 诊断-判分角色轴 / κ/α / 门
|
|
157
|
+
"evidence_aware_metrics": True,
|
|
158
|
+
"metric_roles": ["diagnostic", "judging"],
|
|
159
|
+
"inter_rater_agreement": ["cohen_kappa", "krippendorff_alpha"],
|
|
160
|
+
"reward_basis_gates": True,
|
|
134
161
|
# 重评分本期只有库层入口 (EvalRunner.regrade_run)。它牵涉同一大版本的
|
|
135
162
|
# 响应结构兼容承诺, 暴露面另立变更 —— 列出来免得调用方以为 /runs 上能调。
|
|
136
163
|
"regrade_over_http": False,
|
|
@@ -29,6 +29,7 @@ from pydantic import BaseModel, Field
|
|
|
29
29
|
from sse_starlette.sse import EventSourceResponse
|
|
30
30
|
|
|
31
31
|
from agent_eval.api.events import run_event_bus
|
|
32
|
+
from agent_eval.core.comparison import runs_comparable
|
|
32
33
|
from agent_eval.core.metrics import classify_trial, trial_invalid_reason
|
|
33
34
|
from agent_eval.core.types import STATISTICS_VERSION, TrialVerdict
|
|
34
35
|
|
|
@@ -185,6 +186,8 @@ async def get_run(run_id: str):
|
|
|
185
186
|
"trace_id": t.trace_id,
|
|
186
187
|
"success": t.success,
|
|
187
188
|
"score": t.avg_score(),
|
|
189
|
+
# trial 总分 (权重/策略/乘性门塌缩后的值; None = 该字段落盘前的历史 run)
|
|
190
|
+
"synthesized_score": t.synthesized_score,
|
|
188
191
|
"duration_ms": t.duration_ms,
|
|
189
192
|
"error": t.error,
|
|
190
193
|
"verdict": t.verdict.value,
|
|
@@ -217,6 +220,10 @@ async def get_run(run_id: str):
|
|
|
217
220
|
gr.judgment_moment.value if gr.judgment_moment else None
|
|
218
221
|
),
|
|
219
222
|
"subject_only": gr.subject_only,
|
|
223
|
+
# 门结果: 因子 / 是否乘入总分 / 未生效原因 (spec: graders)
|
|
224
|
+
"gate_factor": gr.gate_factor,
|
|
225
|
+
"gate_applied": gr.gate_applied,
|
|
226
|
+
"gate_reason": gr.gate_reason,
|
|
220
227
|
}
|
|
221
228
|
for gr in t.grader_results
|
|
222
229
|
],
|
|
@@ -477,6 +484,7 @@ async def submit_human_score(run_id: str, request: HumanScoreRequest):
|
|
|
477
484
|
# 重算 trial 成功状态与 run 汇总 (含该 task 汇总)
|
|
478
485
|
if task is not None:
|
|
479
486
|
trial.success = runner._compute_trial_success(task, trial.grader_results)
|
|
487
|
+
trial.synthesized_score = runner._trial_weighted_score(task, trial)
|
|
480
488
|
trial.verdict = classify_trial(trial)
|
|
481
489
|
trial.invalid_reason = trial_invalid_reason(trial)
|
|
482
490
|
if run.statistics_version is None:
|
|
@@ -554,13 +562,12 @@ def _build_comparison(run_a, run_b) -> dict[str, Any]:
|
|
|
554
562
|
summary_a = run_a.summary
|
|
555
563
|
summary_b = run_b.summary
|
|
556
564
|
|
|
565
|
+
# 可比性前置与 CLI / 基线门同源 (core.comparison.runs_comparable)
|
|
566
|
+
comparable, not_comparable_reason = runs_comparable(run_a, run_b)
|
|
557
567
|
version_a = getattr(run_a, "statistics_version", None)
|
|
558
568
|
version_b = getattr(run_b, "statistics_version", None)
|
|
559
569
|
evidence_a = getattr(run_a, "evidence", None)
|
|
560
570
|
evidence_b = getattr(run_b, "evidence", None)
|
|
561
|
-
same_caliber = version_a is not None and version_a == version_b
|
|
562
|
-
same_boundary, boundary_reason = _compare_evidence_boundaries(evidence_a, evidence_b)
|
|
563
|
-
comparable = same_caliber and same_boundary
|
|
564
571
|
|
|
565
572
|
all_k_values: set[int] = set()
|
|
566
573
|
for summary in (summary_a, summary_b):
|
|
@@ -684,42 +691,10 @@ def _build_comparison(run_a, run_b) -> dict[str, Any]:
|
|
|
684
691
|
"b": evidence_b.model_dump() if evidence_b else None,
|
|
685
692
|
},
|
|
686
693
|
"comparable": comparable,
|
|
687
|
-
"not_comparable_reason":
|
|
688
|
-
comparable, same_caliber, version_a, version_b, boundary_reason
|
|
689
|
-
),
|
|
694
|
+
"not_comparable_reason": not_comparable_reason,
|
|
690
695
|
}
|
|
691
696
|
|
|
692
697
|
|
|
693
|
-
def _compare_evidence_boundaries(
|
|
694
|
-
evidence_a: Any, evidence_b: Any
|
|
695
|
-
) -> tuple[bool, str | None]:
|
|
696
|
-
"""两个 run 的证据边界是否一致 (缺记录即无法判定可比)。"""
|
|
697
|
-
if evidence_a is None and evidence_b is None:
|
|
698
|
-
return False, "两个 run 均未记录证据采集边界 (历史 run), 无法判定可比性"
|
|
699
|
-
if evidence_a is None or evidence_b is None:
|
|
700
|
-
missing = "a" if evidence_a is None else "b"
|
|
701
|
-
return False, f"run_{missing} 未记录证据采集边界 (历史 run), 无法判定可比性"
|
|
702
|
-
return evidence_a.compare_with(evidence_b)
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
def _not_comparable_reason(
|
|
706
|
-
comparable: bool,
|
|
707
|
-
same_caliber: bool,
|
|
708
|
-
version_a: str | None,
|
|
709
|
-
version_b: str | None,
|
|
710
|
-
boundary_reason: str | None,
|
|
711
|
-
) -> str | None:
|
|
712
|
-
if comparable:
|
|
713
|
-
return None
|
|
714
|
-
if not same_caliber:
|
|
715
|
-
return (
|
|
716
|
-
"两个 run 的统计口径版本不同"
|
|
717
|
-
if version_a is not None and version_b is not None
|
|
718
|
-
else "至少一个 run 未记录统计口径版本 (历史 run), 无法判定可比性"
|
|
719
|
-
)
|
|
720
|
-
return boundary_reason or "两个 run 的证据采集边界不同"
|
|
721
|
-
|
|
722
|
-
|
|
723
698
|
def _delta(a: float | None, b: float | None) -> float | None:
|
|
724
699
|
if a is None or b is None:
|
|
725
700
|
return None
|
|
@@ -109,8 +109,9 @@ async def get_task_history(task_id: str):
|
|
|
109
109
|
"valid_trials": len(valid),
|
|
110
110
|
"invalid_trials": len(buckets[TrialVerdict.INVALID]),
|
|
111
111
|
"pending_trials": len(buckets[TrialVerdict.PENDING]),
|
|
112
|
+
# 与 run summary 的 avg_score 同一口径: trial 总分 (含门塌缩), 非 grader 简均
|
|
112
113
|
"avg_score": (
|
|
113
|
-
round(sum(t.
|
|
114
|
+
round(sum(t.total_score() for t in valid) / len(valid), 4)
|
|
114
115
|
if valid else None
|
|
115
116
|
),
|
|
116
117
|
"graders": {
|