finalize medical consultation agent backend
This commit is contained in:
@@ -9,6 +9,7 @@ class ReportAgent:
|
||||
"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")),
|
||||
@@ -32,6 +33,30 @@ class ReportAgent:
|
||||
"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
|
||||
|
||||
@@ -114,8 +114,9 @@ class ScoringAgent:
|
||||
"你是医学教学问诊评分专家,只输出合法 JSON。"
|
||||
"请结合病例、问诊过程、检查申请、诊断和治疗提交进行教学评价。"
|
||||
"输出字段固定为 score_type,total_score,dimension_scores,errors,improvement_plan,"
|
||||
"evidence_summary,guideline_refs,overall_comment。"
|
||||
"evidence_summary,guideline_refs,overall_comment,score_details。"
|
||||
"dimension_scores 为 5-6 项,每项包含 dimension,score,max_score,comment,evidence,deductions,improvement。"
|
||||
"score_details 对应 scoring_rules,每项包含 rule_id,dimension,score,deducted_reason,evidence_message_ids,ai_confidence,comment。"
|
||||
"evidence、deductions、improvement_plan、evidence_summary 必须是数组,每个元素一句话。"
|
||||
"errors 每项包含 title,description,severity,related_dimension。"
|
||||
"评价必须具体指出用户问了什么、申请了什么检查、诊断治疗哪里充分或不足。"
|
||||
@@ -129,6 +130,7 @@ class ScoringAgent:
|
||||
for item in scoring_rules[:12]:
|
||||
compact.append(
|
||||
{
|
||||
"rule_id": getattr(item, "id", None),
|
||||
"dimension": getattr(item, "dimension", ""),
|
||||
"competency_dimension": getattr(item, "competency_dimension", ""),
|
||||
"score_weight": float(getattr(item, "score_weight", 0) or 0),
|
||||
@@ -161,6 +163,7 @@ class ScoringAgent:
|
||||
data.setdefault("score_type", "percentage")
|
||||
data.setdefault("total_score", 0)
|
||||
data.setdefault("dimension_scores", [])
|
||||
data.setdefault("score_details", [])
|
||||
data.setdefault("errors", [])
|
||||
data.setdefault("improvement_plan", [])
|
||||
data.setdefault("evidence_summary", [])
|
||||
@@ -183,6 +186,7 @@ class ScoringAgent:
|
||||
}
|
||||
)
|
||||
data["dimension_scores"] = normalized_dimensions or self._fallback_score("percentage", guideline_refs)["dimension_scores"]
|
||||
data["score_details"] = self._normalize_score_details(data.get("score_details"), data["dimension_scores"])
|
||||
data["errors"] = self._normalize_errors(data.get("errors"))
|
||||
data["improvement_plan"] = self._ensure_list(data.get("improvement_plan"))
|
||||
data["evidence_summary"] = self._ensure_list(data.get("evidence_summary"))
|
||||
@@ -195,6 +199,29 @@ class ScoringAgent:
|
||||
data["score_type"] = "percentage"
|
||||
return data
|
||||
|
||||
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
|
||||
details = []
|
||||
for item in source:
|
||||
if not isinstance(item, dict):
|
||||
continue
|
||||
deducted_reason = item.get("deducted_reason")
|
||||
if not deducted_reason:
|
||||
deducted_reason = ";".join(str(value) for value in item.get("deductions", []) if value)
|
||||
details.append(
|
||||
{
|
||||
"rule_id": item.get("rule_id"),
|
||||
"dimension": str(item.get("dimension") or "综合表现"),
|
||||
"score": float(item.get("score") or 0),
|
||||
"deducted_reason": self._truncate(deducted_reason or "", 260),
|
||||
"evidence_message_ids": self._ensure_list(item.get("evidence_message_ids") or item.get("evidence")),
|
||||
"ai_confidence": float(item.get("ai_confidence") or 0.85),
|
||||
"comment": self._truncate(item.get("comment") or item.get("improvement") or "", 220),
|
||||
}
|
||||
)
|
||||
return details
|
||||
|
||||
def _normalize_errors(self, errors: object) -> list[dict]:
|
||||
"""错误项归一化:转为报告可渲染的扣分项。"""
|
||||
normalized = []
|
||||
@@ -320,6 +347,35 @@ class ScoringAgent:
|
||||
"improvement": "用 SOAP 结构归纳病情,把证据、判断和计划串联起来。",
|
||||
},
|
||||
],
|
||||
"score_details": [
|
||||
{
|
||||
"rule_id": None,
|
||||
"dimension": "信息获取",
|
||||
"score": 20,
|
||||
"deducted_reason": "既往喘息史、过敏史、疫苗接种史、家属照护能力等信息不够完整。",
|
||||
"evidence_message_ids": ["围绕发热、咳嗽、喘息等核心症状展开问诊。"],
|
||||
"ai_confidence": 0.85,
|
||||
"comment": "完成主要症状追问,但儿科专科病史仍需补充。",
|
||||
},
|
||||
{
|
||||
"rule_id": None,
|
||||
"dimension": "分析推理",
|
||||
"score": 16,
|
||||
"deducted_reason": "鉴别诊断和严重程度判断未充分引用血氧、胸片和炎症指标。",
|
||||
"evidence_message_ids": ["主要诊断指向支气管肺炎。"],
|
||||
"ai_confidence": 0.84,
|
||||
"comment": "诊断方向基本正确,但严重程度分层需要更清晰。",
|
||||
},
|
||||
{
|
||||
"rule_id": None,
|
||||
"dimension": "检查利用",
|
||||
"score": 12,
|
||||
"deducted_reason": "对 SpO2、胸片异常和炎症指标的临床意义解释不够具体。",
|
||||
"evidence_message_ids": ["胸片、血氧或炎症指标可支持肺炎诊断和严重程度判断。"],
|
||||
"ai_confidence": 0.84,
|
||||
"comment": "关键检查申请较完整,但检查结果解释仍可细化。",
|
||||
},
|
||||
],
|
||||
"errors": [
|
||||
{
|
||||
"title": "信息采集不够系统",
|
||||
@@ -359,6 +415,13 @@ class ScoringAgent:
|
||||
}
|
||||
for item in data.get("dimension_scores", [])
|
||||
]
|
||||
converted["score_details"] = [
|
||||
{
|
||||
**item,
|
||||
"score": round(float(item.get("score", 0)) / 20, 1),
|
||||
}
|
||||
for item in data.get("score_details", [])
|
||||
]
|
||||
return converted
|
||||
|
||||
def _truncate(self, value: Any, limit: int) -> str:
|
||||
|
||||
Reference in New Issue
Block a user