AgentEvalTool/backend/agenteval/exploration/summary.py
sinohqb 7eae6de52d refactor(evaluation/storage): 结算统一与 repository 拆分(Phase 2 + 3)
合并两个不可分割的深化:

Phase 2 — 智能作业结算统一(ADR-0012)
- intelligence_jobs.execute(job_kind, campaign_id, ...) 作为结算的
  唯一实现:建行 → 认领 → 校验 → generating → 落账,一处编排、
  一处截断(500 字符)。两个 executor 退化为 ensure_queued /
  validate / work_fn 三个小 adapter。
- analysis.validate_analysis_request() 共享校验入口(活动终态 →
  模型),路由捕获映射 400、executor 捕获落 failed 行,与
  validate_comparison_request 先例同构。
- campaign_runner._auto_start_analysis 的跳过守卫收敛至
  auto_intelligence_eligible 单一判断点。
- comparison.py 删除零调用的 build_comparison_payload;
  load_comparison_view 投影归位至 campaign_read_model。
- 新增 characterization 测试(认领竞争、重复触发、截断、恢复上限)。

Phase 3 — storage/repository.py 拆分
- AsyncJobRepository 及两个子类迁至
  storage/async_job_repository.py(Phase 2 的 intelligence_jobs
  与 comparison 必须 import 自该路径,故与 Phase 2 同 commit)。
- ExplorationSession / ExplorationMessage 迁至
  storage/exploration_repository.py;repository.py 由 1180 行降至
  约 814 行,grep 确认无残留符号。
- exploration 子模块与路由 import 全部更新;测试 import 跟随。

刻意不做:CAS 共享原语、app.py 五 registry 关停顺序归一
(ADR-0006 精神,等真实需求出现再议)。
2026-08-24 05:50:27 +08:00

85 lines
3.3 KiB
Python
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.

"""Exploration findings aggregation (探索发现聚合).
把探索会话的体验记录聚合成探索摘要:会话数、目标达成率、问题清单
blockers / misled 按出现次数降序、judge 复核结论(已就位才纳入;
findings 全量收各档发现poor 档排前)。这是体验记录这条第一手证据线
进入报告 / 分析 / 导出三个出口前的唯一聚合口径;只含统计与问题清单,
不含全量对话。
"""
from collections import Counter
from typing import Any, Optional
from sqlmodel import Session
from agenteval.exploration.models import ExplorationSession
_RATING_SEVERITY = {"poor": 0, "acceptable": 1, "good": 2}
def _issue_list(counter: Counter) -> list[dict[str, Any]]:
return [{"issue": issue, "count": count} for issue, count in counter.most_common()]
def summarize_exploration(sessions: list[ExplorationSession]) -> Optional[dict[str, Any]]:
"""聚合一组探索会话为探索摘要;无会话返回 None缺则无痕"""
if not sessions:
return None
with_experience = [s for s in sessions if s.experience is not None]
blockers: Counter = Counter()
misled: Counter = Counter()
achieved = 0
for session_obj in with_experience:
experience = session_obj.experience
if experience.get("goal_achieved"):
achieved += 1
blockers.update(experience.get("blockers") or [])
misled.update(experience.get("misled") or [])
judge = _summarize_judge_reviews(sessions)
return {
"session_count": len(sessions),
"sessions_with_experience": len(with_experience),
"goal_achieved_count": achieved,
"goal_achievement_rate": round(achieved / len(with_experience), 4) if with_experience else None,
"issues": _issue_list(blockers),
"misled": _issue_list(misled),
"judge_review": judge,
}
def summarize_campaign_exploration(db_session: Session, campaign_id: str) -> Optional[dict[str, Any]]:
"""取数 + 聚合一步完成:报告 / 分析 / 导出三个出口共用的探索摘要取法。"""
from agenteval.storage.exploration_repository import ExplorationSessionRepository
return summarize_exploration(ExplorationSessionRepository(db_session).list_by_campaign(campaign_id))
def _summarize_judge_reviews(sessions: list[ExplorationSession]) -> Optional[dict[str, Any]]:
"""只纳入复核完成的会话findings 全量收各档发现poor 档排前),
summaries 收复核总体结论。"""
findings: list[dict[str, Any]] = []
summaries: list[str] = []
reviewed = 0
for session_obj in sessions:
review = session_obj.judge_review
if not review or review.get("status") != "completed":
continue
reviewed += 1
if review.get("summary"):
summaries.append(str(review["summary"]))
for item in review.get("dimensions") or []:
findings.append(
{
"dimension": item.get("dimension"),
"rating": item.get("rating"),
"comment": item.get("comment") or "",
}
)
if reviewed == 0:
return None
findings.sort(key=lambda f: _RATING_SEVERITY.get(f["rating"], len(_RATING_SEVERITY)))
return {"reviewed_sessions": reviewed, "findings": findings, "summaries": summaries}