"""健康度评分计算引擎。 基于月报结构化数据,计算多维度评分: - 基础 4 维度:财务、经营、AI 商业化、AI 成本 - T2.9 扩展 5 维度:组织人才、产品技术、市场竞争、治理合规、融资资本 - T3.11 扩展 5 维度:协同赋能、AI 模型产品、数据合规、团队技术、客户成功 总分 = 加权平均,输出 0-100 分。 """ import logging from typing import Any logger = logging.getLogger(__name__) # 14 维度权重配置 WEIGHTS = { "financial": 0.15, "operational": 0.10, "ai_commercial": 0.10, "ai_cost": 0.05, "org_talent": 0.10, "product_tech": 0.10, "market_compete": 0.10, "governance": 0.05, "financing": 0.05, "synergy": 0.05, "ai_model_product": 0.05, "data_compliance": 0.05, "team_tech": 0.03, "customer_success": 0.07, } def _safe_float(value: Any, default: float = 0.0) -> float: """安全转换为 float。""" if value is None or value == "": return default try: return float(value) except (ValueError, TypeError): return default def _calc_financial_score(data: dict[str, Any]) -> float: """计算财务健康度。 指标: - 现金跑道(runway_months):>12 月=90+,6-12=60-90,<6=<60 - 营收同比增长(yoy_change):正=加分,负=减分 - 烧钱率趋势(burn_rate trend):down=加分,up=减分 """ score = 50.0 # 基础分 cash = data.get("cash_balance", {}) runway = _safe_float(cash.get("runway_months")) if runway > 0: if runway >= 12: score += 30 elif runway >= 6: score += 15 elif runway >= 3: score -= 10 else: score -= 30 revenue = data.get("revenue", {}) yoy = revenue.get("yoy_change", "") if yoy: yoy_val = _safe_float(str(yoy).replace("%", "").replace("+", "")) if yoy_val > 0: score += 15 elif yoy_val < 0: score -= 15 burn = data.get("burn_rate", {}) trend = burn.get("trend", "") if trend == "down": score += 10 elif trend == "up": score -= 10 return max(0, min(100, score)) def _calc_operational_score(data: dict[str, Any]) -> float: """计算经营健康度。 指标: - 团队规模变化(headcount):净增长=加分 - 关键指标达成情况 """ score = 60.0 headcount = data.get("headcount", {}) new_hires = _safe_float(headcount.get("new_hires")) departures = _safe_float(headcount.get("departures")) net_change = new_hires - departures if net_change > 0: score += 15 elif net_change < 0: score -= 10 if departures > 5: score -= 10 # 高流失率 key_metrics = data.get("key_metrics", []) if key_metrics: positive_count = sum( 1 for m in key_metrics if _safe_float(str(m.get("change", "")).replace("%", "").replace("+", "")) > 0 ) score += (positive_count / len(key_metrics)) * 20 return max(0, min(100, score)) def _calc_ai_commercial_score(data: dict[str, Any]) -> float: """计算 AI 商业化度。 基于 key_metrics 中 AI 相关指标的达成情况。 """ score = 50.0 key_metrics = data.get("key_metrics", []) ai_metrics = [ m for m in key_metrics if "ai" in str(m.get("name", "")).lower() or "模型" in str(m.get("name", "")) or "推理" in str(m.get("name", "")) ] if ai_metrics: for m in ai_metrics: change = str(m.get("change", "")) val = _safe_float(change.replace("%", "").replace("+", "")) if val > 0: score += 15 elif val < 0: score -= 10 else: # 无 AI 相关指标,给中等偏下分数 score = 40.0 return max(0, min(100, score)) def _calc_ai_cost_score(data: dict[str, Any]) -> float: """计算 AI 成本效率。 基于 burn_rate 和 AI 相关支出估算。 """ score = 55.0 burn = data.get("burn_rate", {}) trend = burn.get("trend", "") if trend == "down": score += 20 elif trend == "up": score -= 15 # 如果有 key_metrics 中的成本相关指标 key_metrics = data.get("key_metrics", []) cost_metrics = [ m for m in key_metrics if "成本" in str(m.get("name", "")) or "cost" in str(m.get("name", "")).lower() ] for m in cost_metrics: change = str(m.get("change", "")) val = _safe_float(change.replace("%", "").replace("+", "")) if val < 0: # 成本下降是好事 score += 10 elif val > 0: score -= 10 return max(0, min(100, score)) def _calc_org_talent_score(data: dict[str, Any]) -> float: """计算组织人才健康度。 指标:团队规模变化、流失率、关键岗位填补。 """ score = 60.0 headcount = data.get("headcount", {}) new_hires = _safe_float(headcount.get("new_hires")) departures = _safe_float(headcount.get("departures")) total = _safe_float(headcount.get("total"), 1) if total > 0: turnover_rate = departures / total if turnover_rate < 0.05: score += 20 elif turnover_rate < 0.10: score += 10 elif turnover_rate > 0.20: score -= 20 elif turnover_rate > 0.15: score -= 10 if new_hires > 0: score += 10 return max(0, min(100, score)) def _calc_product_tech_score(data: dict[str, Any]) -> float: """计算产品技术健康度。 指标:产品迭代频率、技术指标达成。 """ score = 55.0 key_metrics = data.get("key_metrics", []) tech_metrics = [ m for m in key_metrics if any(k in str(m.get("name", "")).lower() for k in ["产品", "product", "迭代", "release", "技术", "tech"]) ] if tech_metrics: for m in tech_metrics: change = str(m.get("change", "")) val = _safe_float(change.replace("%", "").replace("+", "")) if val > 0: score += 12 elif val < 0: score -= 8 else: score = 50.0 return max(0, min(100, score)) def _calc_market_compete_score(data: dict[str, Any]) -> float: """计算市场竞争健康度。 指标:市场份额变化、竞品动态、客户增长。 """ score = 55.0 key_metrics = data.get("key_metrics", []) market_metrics = [ m for m in key_metrics if any(k in str(m.get("name", "")) for k in ["市场", "份额", "客户", "竞品", "MAU", "DAU", "GMV"]) ] if market_metrics: for m in market_metrics: change = str(m.get("change", "")) val = _safe_float(change.replace("%", "").replace("+", "")) if val > 0: score += 12 elif val < 0: score -= 8 return max(0, min(100, score)) def _calc_governance_score(data: dict[str, Any]) -> float: """计算治理合规健康度。 指标:董事会召开频率、合规事件。 """ score = 70.0 governance = data.get("governance", {}) if governance.get("board_meeting_held"): score += 10 if governance.get("compliance_issues"): score -= 20 return max(0, min(100, score)) def _calc_financing_score(data: dict[str, Any]) -> float: """计算融资资本健康度。 指标:现金跑道、融资进度。 """ score = 55.0 cash = data.get("cash_balance", {}) runway = _safe_float(cash.get("runway_months")) if runway >= 18: score += 25 elif runway >= 12: score += 15 elif runway >= 6: score += 5 elif runway < 3: score -= 25 financing = data.get("financing", {}) if financing.get("in_progress"): score += 10 return max(0, min(100, score)) def _calc_synergy_score(data: dict[str, Any]) -> float: """计算协同赋能健康度(T3.11)。""" score = 55.0 synergy = data.get("synergy", {}) if synergy.get("active_count", 0) > 0: score += min(20, synergy.get("active_count", 0) * 5) if synergy.get("completed_count", 0) > 0: score += 10 return max(0, min(100, score)) def _calc_ai_model_product_score(data: dict[str, Any]) -> float: """计算 AI 模型产品健康度(T3.11)。""" score = 50.0 ai_data = data.get("ai_metrics", {}) if ai_data.get("model_accuracy"): score += 15 if ai_data.get("inference_cost_trend") == "down": score += 10 if ai_data.get("data_quality_score"): score += min(15, _safe_float(ai_data.get("data_quality_score")) * 0.15) return max(0, min(100, score)) def _calc_data_compliance_score(data: dict[str, Any]) -> float: """计算数据合规健康度(T3.11)。""" score = 70.0 compliance = data.get("data_compliance", {}) if compliance.get("issues_count", 0) > 0: score -= min(30, compliance.get("issues_count", 0) * 10) if compliance.get("audit_passed"): score += 15 return max(0, min(100, score)) def _calc_team_tech_score(data: dict[str, Any]) -> float: """计算团队技术健康度(T3.11)。""" score = 55.0 team = data.get("team_tech", {}) if team.get("tech_lead_count", 0) > 0: score += 15 if team.get("patent_count", 0) > 0: score += min(15, team.get("patent_count", 0) * 3) return max(0, min(100, score)) def _calc_customer_success_score(data: dict[str, Any]) -> float: """计算客户成功健康度(T3.11)。""" score = 55.0 cs = data.get("customer_success", {}) retention = _safe_float(cs.get("retention_rate"), -1) if retention >= 0: if retention >= 0.90: score += 25 elif retention >= 0.80: score += 15 elif retention < 0.70: score -= 15 nps = _safe_float(cs.get("nps")) if nps > 0: score += min(15, nps * 0.15) return max(0, min(100, score)) def calculate_health_score(structured_data: dict[str, Any]) -> dict[str, float]: """计算 14 维度健康度评分。 Args: structured_data: 月报 AI 解析后的结构化数据 Returns: 包含 total_score 和 14 个维度分数的字典 """ if not structured_data: return { "total_score": 0.0, "financial_score": 0.0, "operational_score": 0.0, "ai_commercial_score": 0.0, "ai_cost_score": 0.0, "org_talent_score": 0.0, "product_tech_score": 0.0, "market_compete_score": 0.0, "governance_score": 0.0, "financing_score": 0.0, "synergy_score": 0.0, "ai_model_product_score": 0.0, "data_compliance_score": 0.0, "team_tech_score": 0.0, "customer_success_score": 0.0, } scores = { "financial_score": _calc_financial_score(structured_data), "operational_score": _calc_operational_score(structured_data), "ai_commercial_score": _calc_ai_commercial_score(structured_data), "ai_cost_score": _calc_ai_cost_score(structured_data), "org_talent_score": _calc_org_talent_score(structured_data), "product_tech_score": _calc_product_tech_score(structured_data), "market_compete_score": _calc_market_compete_score(structured_data), "governance_score": _calc_governance_score(structured_data), "financing_score": _calc_financing_score(structured_data), "synergy_score": _calc_synergy_score(structured_data), "ai_model_product_score": _calc_ai_model_product_score(structured_data), "data_compliance_score": _calc_data_compliance_score(structured_data), "team_tech_score": _calc_team_tech_score(structured_data), "customer_success_score": _calc_customer_success_score(structured_data), } weight_keys = [ "financial", "operational", "ai_commercial", "ai_cost", "org_talent", "product_tech", "market_compete", "governance", "financing", "synergy", "ai_model_product", "data_compliance", "team_tech", "customer_success", ] score_keys = [ "financial_score", "operational_score", "ai_commercial_score", "ai_cost_score", "org_talent_score", "product_tech_score", "market_compete_score", "governance_score", "financing_score", "synergy_score", "ai_model_product_score", "data_compliance_score", "team_tech_score", "customer_success_score", ] total = sum(scores[sk] * WEIGHTS[wk] for sk, wk in zip(score_keys, weight_keys)) scores["total_score"] = round(total, 1) result = {k: round(v, 1) for k, v in scores.items()} logger.info("健康度评分计算完成(14 维度): %s", result) return result def determine_trend(current_score: float, previous_score: float | None) -> str: """判断评分趋势。 Args: current_score: 当前评分 previous_score: 上期评分(如有) Returns: "up" / "down" / "stable" """ if previous_score is None: return "stable" diff = current_score - previous_score if diff > 5: return "up" elif diff < -5: return "down" return "stable"