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