74 lines
3.9 KiB
Python
74 lines
3.9 KiB
Python
class ReportAgent:
|
||
"""报告 Agent:整理评分结果为接口和 PDF 可复用的报告结构。"""
|
||
|
||
def build_report(self, scoring_result: dict) -> dict:
|
||
"""报告整理:校验评分结果字段并补齐展示默认值,不重新评分。"""
|
||
dimension_scores = self._normalize_dimension_scores(scoring_result.get("dimension_scores", []))
|
||
total_score = self._safe_float(scoring_result.get("total_score"), 0)
|
||
return {
|
||
"score_type": scoring_result.get("score_type", "percentage"),
|
||
"total_score": total_score,
|
||
"dimension_scores": dimension_scores,
|
||
"score_details": self._normalize_score_details(scoring_result.get("score_details", []), dimension_scores),
|
||
"errors": self._ensure_list(scoring_result.get("errors")),
|
||
"improvement_plan": self._ensure_list(scoring_result.get("improvement_plan")),
|
||
"evidence_summary": self._ensure_list(scoring_result.get("evidence_summary")),
|
||
"guideline_refs": self._ensure_list(scoring_result.get("guideline_refs")),
|
||
"overall_comment": scoring_result.get("overall_comment", ""),
|
||
"_llm_model": scoring_result.get("_llm_model"),
|
||
"_latency_metrics": scoring_result.get("_latency_metrics", {}),
|
||
}
|
||
|
||
def _normalize_dimension_scores(self, raw_scores: object) -> list[dict]:
|
||
"""维度校验:把模型输出归一为前端和数据库可保存的评分列表。"""
|
||
if not isinstance(raw_scores, list):
|
||
return []
|
||
normalized: list[dict] = []
|
||
for item in raw_scores:
|
||
if not isinstance(item, dict):
|
||
continue
|
||
normalized.append(
|
||
{
|
||
"dimension": str(item.get("dimension", "未命名维度")),
|
||
"score": self._safe_float(item.get("score"), 0),
|
||
"max_score": self._safe_float(item.get("max_score"), 0),
|
||
"comment": str(item.get("comment", "")),
|
||
"evidence": self._ensure_list(item.get("evidence")),
|
||
"deductions": self._ensure_list(item.get("deductions")),
|
||
"improvement": str(item.get("improvement", "")),
|
||
}
|
||
)
|
||
return normalized
|
||
|
||
def _normalize_score_details(self, raw_details: object, dimension_scores: list[dict]) -> list[dict]:
|
||
"""评分明细校验:保留可写入 training_score_detail 的细粒度字段。"""
|
||
source = raw_details if isinstance(raw_details, list) and raw_details else dimension_scores
|
||
normalized: list[dict] = []
|
||
for item in source:
|
||
if not isinstance(item, dict):
|
||
continue
|
||
deductions = self._ensure_list(item.get("deductions"))
|
||
normalized.append(
|
||
{
|
||
"rule_id": item.get("rule_id"),
|
||
"dimension": str(item.get("dimension", "综合表现")),
|
||
"score": self._safe_float(item.get("score"), 0),
|
||
"deducted_reason": str(item.get("deducted_reason") or ";".join(str(value) for value in deductions)),
|
||
"evidence_message_ids": self._ensure_list(item.get("evidence_message_ids") or item.get("evidence")),
|
||
"ai_confidence": self._safe_float(item.get("ai_confidence"), 0.85),
|
||
"comment": str(item.get("comment") or item.get("improvement") or ""),
|
||
}
|
||
)
|
||
return normalized
|
||
|
||
def _ensure_list(self, value: object) -> list:
|
||
"""列表校验:保证报告中的数组字段稳定返回 list。"""
|
||
return value if isinstance(value, list) else []
|
||
|
||
def _safe_float(self, value: object, default: float) -> float:
|
||
"""数值校验:把模型输出中的分数安全转换为 float。"""
|
||
try:
|
||
return float(value)
|
||
except (TypeError, ValueError):
|
||
return default
|