Exploration sessions aggregate into a single exploration summary (session counts, goal-achievement rate, issue lists from experience records, judge conclusions when reviewed) that feeds three exits: the campaign report gains an exploration dimension, the v0.7 analysis stage-two input gains the summary (stats only, never full dialogues), and the Markdown export appends a findings appendix after analysis and comparison. With no exploration data every output stays unchanged.
104 lines
3.8 KiB
Python
104 lines
3.8 KiB
Python
"""Exploration summary aggregation (v0.9 票据 05).
|
||
|
||
体验记录聚合成探索摘要:会话数、目标达成率、问题清单(blockers/misled
|
||
按出现次数降序)、judge 复核结论(已就位才纳入,只收 poor 档发现)。
|
||
缺则无痕:无会话返回 None。纯函数,不落库。
|
||
"""
|
||
|
||
from agenteval.exploration.models import ExplorationSession, ExplorationSessionStatus
|
||
from agenteval.exploration.summary import summarize_exploration
|
||
|
||
|
||
def _session(experience=None, judge_review=None, status=ExplorationSessionStatus.COMPLETED) -> ExplorationSession:
|
||
return ExplorationSession(
|
||
campaign_id="c-1",
|
||
target_id="t-1",
|
||
persona={"name": "x"},
|
||
goal="查询账单",
|
||
status=status,
|
||
experience=experience,
|
||
judge_review=judge_review,
|
||
)
|
||
|
||
|
||
def _experience(goal_achieved: bool, blockers=None, misled=None) -> dict:
|
||
return {
|
||
"goal_achieved": goal_achieved,
|
||
"blockers": blockers or [],
|
||
"misled": misled or [],
|
||
"emotion": "neutral",
|
||
"notes": "",
|
||
}
|
||
|
||
|
||
def test_no_sessions_returns_none():
|
||
assert summarize_exploration([]) is None
|
||
|
||
|
||
def test_aggregates_counts_rate_and_issue_lists():
|
||
sessions = [
|
||
_session(_experience(True, blockers=["缴费入口难找"])),
|
||
_session(_experience(False, blockers=["缴费入口难找", "验证码收不到"], misled=["被误导选了错误套餐"])),
|
||
_session(_experience(False, blockers=["验证码收不到"])),
|
||
]
|
||
summary = summarize_exploration(sessions)
|
||
assert summary["session_count"] == 3
|
||
assert summary["sessions_with_experience"] == 3
|
||
assert summary["goal_achieved_count"] == 1
|
||
assert summary["goal_achievement_rate"] == round(1 / 3, 4)
|
||
# 问题清单按出现次数降序(同频按首次出现顺序)
|
||
assert summary["issues"] == [
|
||
{"issue": "缴费入口难找", "count": 2},
|
||
{"issue": "验证码收不到", "count": 2},
|
||
]
|
||
assert summary["misled"] == [{"issue": "被误导选了错误套餐", "count": 1}]
|
||
|
||
|
||
def test_sessions_without_experience_excluded_from_rate_denominator():
|
||
sessions = [
|
||
_session(_experience(True)),
|
||
_session(), # 未关闭/无体验记录
|
||
]
|
||
summary = summarize_exploration(sessions)
|
||
assert summary["session_count"] == 2
|
||
assert summary["sessions_with_experience"] == 1
|
||
assert summary["goal_achievement_rate"] == 1.0
|
||
assert summary["issues"] == []
|
||
|
||
|
||
def test_no_experience_at_all_rate_is_none():
|
||
summary = summarize_exploration([_session(), _session()])
|
||
assert summary["goal_achievement_rate"] is None
|
||
assert summary["issues"] == [] and summary["misled"] == []
|
||
|
||
|
||
def test_judge_review_included_only_when_completed():
|
||
good_review = {
|
||
"status": "completed",
|
||
"dimensions": [
|
||
{"dimension": "attitude", "rating": "good", "comment": "友好"},
|
||
{"dimension": "hallucination", "rating": "poor", "comment": "编造了政策"},
|
||
],
|
||
"summary": "存在幻觉",
|
||
}
|
||
failed_review = {"status": "failed", "error": "解析失败"}
|
||
sessions = [
|
||
_session(_experience(True), judge_review=good_review),
|
||
_session(_experience(False), judge_review=failed_review),
|
||
_session(_experience(True)), # 未复核
|
||
]
|
||
summary = summarize_exploration(sessions)
|
||
judge = summary["judge_review"]
|
||
assert judge["reviewed_sessions"] == 1
|
||
# 只收 poor 档发现(问题清单口径)
|
||
assert judge["findings"] == [
|
||
{"dimension": "hallucination", "rating": "poor", "comment": "编造了政策"}
|
||
]
|
||
# 复核总体结论一并纳入
|
||
assert judge["summaries"] == ["存在幻觉"]
|
||
|
||
|
||
def test_judge_review_absent_when_none_reviewed():
|
||
summary = summarize_exploration([_session(_experience(True))])
|
||
assert summary["judge_review"] is None
|