docs(uiux): UIUX 设计方案大改 + 5 份作业指导书对齐 + 开发任务文档
- UIUX 文档:填充 19 个缺口(多主体画像/健康度/AI+看板/增长域/洞察域/创始人端/OODA/助推/商密) - UIUX 文档:插入 6 个新章节(十四~十九),旧章节重编号为二十~三十一,更新目录和交叉引用 - 作业指导书 x5:导航改为 6 域分组,新增 Context Bar/工作模式/Insight Rail/决策线程/多工作区等 UI 概念 - 新建 docs/2-task-uiux.md:50 个代码落地开发任务,按 P0-P6 分优先级 + 8 Sprint 规划 - 后端/前端:大量新增模型、路由、组件(来自之前 Phase 开发)
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
"""AI AAR Agent — 五问复盘。"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def generate_aar(trigger_event: str, original_plan: str, actual_result: str) -> dict:
|
||||
"""AI 生成五问复盘。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请进行 AAR 五问复盘:
|
||||
|
||||
触发事件:{trigger_event}
|
||||
原计划:{original_plan}
|
||||
实际结果:{actual_result}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"what_happened": "发生了什么", "why_happened": "为什么发生", "what_worked": "什么做得好", "what_failed": "什么没做好", "what_to_change": "下次怎么改", "lessons": ["教训1", "教训2"], "improvements": [{{"action": "改进措施", "owner": "负责人", "deadline": "截止日期"}}]}}"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, dict) else {}
|
||||
|
||||
|
||||
async def check_aar_triggers(company_id: str, recent_events: list[dict]) -> list[dict]:
|
||||
"""检测 AAR 触发条件。"""
|
||||
triggers: list[dict] = []
|
||||
for event in recent_events:
|
||||
if event.get("type") in ["risk_resolved", "funding_completed", "funding_failed", "talent_joined", "talent_left"]:
|
||||
triggers.append({
|
||||
"trigger_event": event.get("title", ""),
|
||||
"trigger_type": event.get("type", ""),
|
||||
})
|
||||
return triggers
|
||||
@@ -0,0 +1,3 @@
|
||||
"""AAR 触发条件检测。"""
|
||||
|
||||
from app.services.aar_agent import check_aar_triggers
|
||||
@@ -0,0 +1,25 @@
|
||||
"""Agent 执行引擎。"""
|
||||
|
||||
import logging
|
||||
from datetime import datetime, timezone
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def execute_agent(agent_name: str, autonomy_level: str, input_data: dict) -> dict:
|
||||
"""执行 Agent 任务并记录结果。"""
|
||||
start_time = datetime.now(timezone.utc)
|
||||
|
||||
# 实际实现中会调用具体的 Agent
|
||||
output = {"result": "Agent 执行完成", "agent": agent_name}
|
||||
|
||||
duration_ms = int((datetime.now(timezone.utc) - start_time).total_seconds() * 1000)
|
||||
|
||||
return {
|
||||
"agent_name": agent_name,
|
||||
"autonomy_level": autonomy_level,
|
||||
"output_summary": str(output)[:200],
|
||||
"output_detail": output,
|
||||
"duration_ms": duration_ms,
|
||||
"executed_at": start_time.isoformat(),
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
"""Agent 编排引擎 — L1-L4 分级自治。"""
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
AUTONOMY_LEVELS = {
|
||||
"L1": {"description": "人工审核后执行", "requires_pre_approval": True, "requires_post_review": False},
|
||||
"L2": {"description": "人工确认后执行", "requires_pre_approval": True, "requires_post_review": False},
|
||||
"L3": {"description": "事后审核", "requires_pre_approval": False, "requires_post_review": True},
|
||||
"L4": {"description": "人工决策", "requires_pre_approval": True, "requires_post_review": False},
|
||||
}
|
||||
|
||||
|
||||
async def orchestrate_agent(agent_name: str, autonomy_level: str, input_data: dict) -> dict:
|
||||
"""编排 Agent 执行。
|
||||
|
||||
根据自治级别决定是否需要人工审核。
|
||||
"""
|
||||
level_config = AUTONOMY_LEVELS.get(autonomy_level, AUTONOMY_LEVELS["L1"])
|
||||
|
||||
return {
|
||||
"agent_name": agent_name,
|
||||
"autonomy_level": autonomy_level,
|
||||
"requires_approval": level_config["requires_pre_approval"],
|
||||
"requires_post_review": level_config["requires_post_review"],
|
||||
"status": "pending_approval" if level_config["requires_pre_approval"] else "executed",
|
||||
"input_summary": str(input_data)[:200],
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
"""条款监控引擎。
|
||||
|
||||
持续监控触发条件,生成预警。
|
||||
"""
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.models.agreement import InvestmentAgreement
|
||||
|
||||
|
||||
async def check_clause_triggers(db: AsyncSession, company_id: str) -> list[dict]:
|
||||
"""检查协议条款触发条件。
|
||||
|
||||
返回触发的预警列表。
|
||||
"""
|
||||
result = await db.execute(
|
||||
select(InvestmentAgreement).where(
|
||||
InvestmentAgreement.company_id == company_id,
|
||||
InvestmentAgreement.status == "active",
|
||||
)
|
||||
)
|
||||
agreements = result.scalars().all()
|
||||
|
||||
alerts: list[dict] = []
|
||||
for agreement in agreements:
|
||||
if not agreement.monitoring_rules:
|
||||
continue
|
||||
for rule in agreement.monitoring_rules:
|
||||
alerts.append({
|
||||
"agreement_id": str(agreement.id),
|
||||
"agreement_title": agreement.title,
|
||||
"rule": rule.get("rule", ""),
|
||||
"metric": rule.get("metric", ""),
|
||||
"threshold": rule.get("threshold", ""),
|
||||
"triggered_at": datetime.now(timezone.utc).isoformat(),
|
||||
})
|
||||
|
||||
return alerts
|
||||
@@ -0,0 +1,30 @@
|
||||
"""投资协议解析 Agent。
|
||||
|
||||
解析 PDF → 提取关键条款 → 生成监控规则。
|
||||
"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def parse_agreement(text_content: str) -> dict:
|
||||
"""AI 解析投资协议文本,提取关键条款。
|
||||
|
||||
返回关键条款和监控规则。
|
||||
"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请分析以下投资协议文本,提取关键条款并生成监控规则。
|
||||
|
||||
协议文本:
|
||||
{text_content[:8000]}
|
||||
|
||||
请以 JSON 格式返回:
|
||||
{{
|
||||
"key_clauses": [
|
||||
{{"name": "条款名称", "content": "条款内容", "trigger_condition": "触发条件"}}
|
||||
],
|
||||
"monitoring_rules": [
|
||||
{{"rule": "监控规则描述", "metric": "关联指标", "threshold": "阈值"}}
|
||||
]
|
||||
}}"""
|
||||
result = await llm.chat(prompt, temperature=0.1)
|
||||
return result if isinstance(result, dict) else {"key_clauses": [], "monitoring_rules": []}
|
||||
@@ -0,0 +1,20 @@
|
||||
"""AI Alpha 归因 Agent。
|
||||
|
||||
干预事件 → 指标变化 → 估值影响 → 回报贡献。
|
||||
"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def attribute_alpha(intervention: dict, metric_changes: dict) -> dict:
|
||||
"""AI 归因分析 — 将干预事件与指标变化和回报贡献关联。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请进行投后管理 Alpha 归因分析:
|
||||
|
||||
干预事件:{intervention}
|
||||
指标变化:{metric_changes}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"causality_confidence": 0.75, "valuation_impact": 15.0, "return_contribution": 0.12, "alpha_score": 0.68, "evidence": ["证据1", "证据2"], "concerns": ["关注点"]}}"""
|
||||
result = await llm.chat(prompt, temperature=0.3)
|
||||
return result if isinstance(result, dict) else {}
|
||||
@@ -0,0 +1,3 @@
|
||||
"""异常检测服务。"""
|
||||
|
||||
from app.services.predictor import detect_anomalies
|
||||
@@ -0,0 +1,30 @@
|
||||
"""AI 董事会 Agent。
|
||||
|
||||
会前材料摘要、决议追踪、提问清单生成。
|
||||
"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def generate_meeting_summary(materials_text: str) -> str:
|
||||
"""AI 生成会前材料摘要。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请为董事会会议生成材料摘要,突出关键决策点和风险事项:
|
||||
|
||||
{materials_text[:6000]}"""
|
||||
result = await llm.chat(prompt, temperature=0.3)
|
||||
return result if isinstance(result, str) else str(result)
|
||||
|
||||
|
||||
async def generate_questions(materials_text: str) -> list[str]:
|
||||
"""AI 生成董事会提问清单。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""基于以下会议材料,生成董事会成员应关注的关键问题(5-8 个):
|
||||
|
||||
{materials_text[:6000]}
|
||||
|
||||
以 JSON 数组格式返回:["问题1", "问题2", ...]"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
if isinstance(result, list):
|
||||
return result
|
||||
return ["请补充会议材料以生成提问清单"]
|
||||
@@ -0,0 +1,16 @@
|
||||
"""采用生命周期鸿沟诊断。"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def diagnose_chasm(company_data: str) -> dict:
|
||||
"""AI 诊断早期采用者→早期大众鸿沟。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请对以下企业进行采用生命周期鸿沟诊断:
|
||||
|
||||
{company_data[:5000]}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"current_stage": "早期采用者", "chasm_detected": true, "gap_analysis": "鸿沟分析", "crossing_strategy": "跨越策略", "risk_level": "high/medium/low"}}"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, dict) else {"chasm_detected": False}
|
||||
@@ -0,0 +1,37 @@
|
||||
"""流失风险预警。"""
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from sqlalchemy import select, func
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.models.company import Company
|
||||
from app.models.report import MonthlyReport
|
||||
|
||||
|
||||
async def detect_churn_risk(db: AsyncSession, tenant_id: str) -> list[dict]:
|
||||
"""识别企业活跃度下降/数据共享减少/互动减少的早期信号。"""
|
||||
result = await db.execute(
|
||||
select(Company).where(Company.tenant_id == tenant_id)
|
||||
)
|
||||
companies = result.scalars().all()
|
||||
|
||||
risks: list[dict] = []
|
||||
for company in companies:
|
||||
# 检查最近月报提交情况
|
||||
report_result = await db.execute(
|
||||
select(func.count(MonthlyReport.id))
|
||||
.where(MonthlyReport.company_id == company.id)
|
||||
)
|
||||
report_count = report_result.scalar_one()
|
||||
|
||||
if report_count == 0:
|
||||
risks.append({
|
||||
"company_id": str(company.id),
|
||||
"company_name": company.name,
|
||||
"risk_level": "high",
|
||||
"signals": ["从未提交月报"],
|
||||
"detected_at": datetime.now(timezone.utc).isoformat(),
|
||||
})
|
||||
|
||||
return risks
|
||||
@@ -0,0 +1,16 @@
|
||||
"""TOC 约束点识别。"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def identify_constraints(company_data: str) -> dict:
|
||||
"""AI 识别约束点 — 敏感度分析 → 约束点 = 敏感度 × 改善空间。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请对以下企业数据进行 TOC 约束点识别:
|
||||
|
||||
{company_data[:5000]}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"constraints": [{{"name": "约束点", "sensitivity": 0.8, "improvement_space": 0.7, "priority_score": 0.56, "action": "改善建议"}}]}}"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, dict) else {"constraints": []}
|
||||
@@ -0,0 +1,3 @@
|
||||
"""跨基金资源调度优化。"""
|
||||
|
||||
from app.services.fund_strategy_analyzer import analyze_fund_strategy
|
||||
@@ -0,0 +1,20 @@
|
||||
"""AI 客户增长 Agent。"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def generate_customer_plan(
|
||||
company_context: str,
|
||||
lp_resources: str,
|
||||
) -> dict:
|
||||
"""AI 分析 LP 资源 + Portfolio 客户网络,生成客户获取方案。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请基于以下信息生成客户获取方案:
|
||||
|
||||
企业上下文:{company_context[:3000]}
|
||||
LP 资源:{lp_resources[:3000]}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"target_customer": "目标客户画像", "entry_angle": "切入角度", "decision_chain": [{{"role": "角色", "name": "姓名", "influence": "高/中/低"}}], "pricing_strategy": "定价策略", "competitive_analysis": {{""strengths": ["优势"], "weaknesses": ["劣势"]}}, "lp_resources": ["可利用资源"]}}"""
|
||||
result = await llm.chat(prompt, temperature=0.5)
|
||||
return result if isinstance(result, dict) else {}
|
||||
@@ -0,0 +1,35 @@
|
||||
"""AI 决策前哨 Agent。
|
||||
|
||||
识别关键决策点 → 场景分析。
|
||||
"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def identify_decision_points(company_context: str) -> list[dict]:
|
||||
"""AI 识别企业即将面临的关键决策岔路口。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""基于以下企业上下文,识别该企业即将面临的关键决策岔路口(1-3 个):
|
||||
|
||||
{company_context[:6000]}
|
||||
|
||||
以 JSON 数组格式返回:
|
||||
[{{"decision_type": "pivot/hiring/funding/product/org", "title": "决策标题", "description": "描述", "signals": ["触发信号"]}}]"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, list) else []
|
||||
|
||||
|
||||
async def analyze_scenarios(decision: dict) -> dict:
|
||||
"""AI 生成场景分析 — A 路线 vs B 路线。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请为以下决策生成场景分析,对比 A 路线和 B 路线:
|
||||
|
||||
决策:{decision.get('title', '')}
|
||||
描述:{decision.get('description', '')}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"route_a": {{"description": "A 路线描述", "pros": ["优势"], "cons": ["风险"], "success_probability": 0.7}},
|
||||
"route_b": {{"description": "B 路线描述", "pros": ["优势"], "cons": ["风险"], "success_probability": 0.5}},
|
||||
"recommendation": "建议"}}"""
|
||||
result = await llm.chat(prompt, temperature=0.5)
|
||||
return result if isinstance(result, dict) else {}
|
||||
@@ -0,0 +1,33 @@
|
||||
"""数字孪生引擎。
|
||||
|
||||
企业模型 + 场景模拟 + 精度追踪。
|
||||
"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def build_twin_model(company_data: str) -> dict:
|
||||
"""构建企业数字孪生模型。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请基于以下企业数据构建数字孪生模型参数:
|
||||
|
||||
{company_data[:5000]}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"model_params": {{"revenue_growth_rate": 0.15, "burn_rate": 500000, "runway_months": 18}}, "scenarios": ["融资", "产品转型", "组织调整", "市场变化"], "accuracy_score": 0.75}}"""
|
||||
result = await llm.chat(prompt, temperature=0.3)
|
||||
return result if isinstance(result, dict) else {}
|
||||
|
||||
|
||||
async def simulate_scenario(model_params: dict, scenario: str) -> dict:
|
||||
"""模拟决策场景。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请基于以下模型参数模拟场景:
|
||||
|
||||
模型参数:{model_params}
|
||||
场景:{scenario}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"projected_outcome": "预测结果", "key_metrics": [{{"metric": "指标", "value": "值"}}], "risk_assessment": "风险评估", "confidence": 0.7}}"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, dict) else {}
|
||||
@@ -0,0 +1,17 @@
|
||||
"""邮件发送服务。"""
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def send_report_email(to: str, subject: str, report_content: str) -> bool:
|
||||
"""发送报告邮件。"""
|
||||
logger.info(f"发送报告邮件 → {to}: {subject}")
|
||||
return True
|
||||
|
||||
|
||||
async def send_risk_alert_email(to: str, risk_title: str, risk_description: str) -> bool:
|
||||
"""发送风险预警邮件。"""
|
||||
logger.info(f"发送风险预警邮件 → {to}: {risk_title}")
|
||||
return True
|
||||
@@ -0,0 +1,22 @@
|
||||
"""文本向量化服务 — 调用千问 embedding API。"""
|
||||
|
||||
import logging
|
||||
|
||||
from app.core.config import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def get_embedding(text: str) -> list[float]:
|
||||
"""获取文本的向量嵌入。"""
|
||||
try:
|
||||
from openai import AsyncOpenAI
|
||||
client = AsyncOpenAI(api_key=settings.llm_api_key, base_url=settings.llm_base_url)
|
||||
response = await client.embeddings.create(
|
||||
model="text-embedding-v2",
|
||||
input=text[:2000],
|
||||
)
|
||||
return response.data[0].embedding
|
||||
except Exception as e:
|
||||
logger.warning(f"Embedding 获取失败: {e}")
|
||||
return []
|
||||
@@ -0,0 +1,19 @@
|
||||
"""AI 重大事项识别。
|
||||
|
||||
从月报/弱信号中提取重大事项。
|
||||
"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def detect_major_events(report_content: str) -> list[dict]:
|
||||
"""AI 从月报内容中识别重大事项。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请从以下月报内容中识别重大事项(融资/人事/产品/法律/市场/组织):
|
||||
|
||||
{report_content[:6000]}
|
||||
|
||||
以 JSON 数组格式返回:
|
||||
[{{"event_type": "funding/personnel/product/legal/market/org", "title": "事项标题", "description": "描述", "severity": "low/medium/high/critical"}}]"""
|
||||
result = await llm.chat(prompt, temperature=0.3)
|
||||
return result if isinstance(result, list) else []
|
||||
@@ -0,0 +1,16 @@
|
||||
"""AI 退出预测 Agent。"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def predict_exit(company_data: str) -> dict:
|
||||
"""AI 计算退出路径 + 时机窗口 + 期望收益对比。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请基于以下企业数据进行退出时机预测:
|
||||
|
||||
{company_data[:5000]}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"exit_path": "ipo/acquisition/secondary/merger", "timing_window": {{"start": "2025-06", "end": "2026-12"}}, "expected_return": 3.5, "hold_return": 2.8, "confidence": 0.7, "signals": ["退出信号1", "信号2"], "recommendation": "退出建议"}}"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, dict) else {}
|
||||
@@ -0,0 +1,16 @@
|
||||
"""扩展机会识别。"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def identify_expansion_opportunities(company_data: str) -> list[dict]:
|
||||
"""识别新市场/新产品/新客户群推荐。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请分析以下企业数据,识别扩展机会:
|
||||
|
||||
{company_data[:5000]}
|
||||
|
||||
以 JSON 数组格式返回:
|
||||
[{{"type": "new_market/new_product/new_customer", "title": "机会标题", "description": "描述", "estimated_value": "预估价值", "feasibility": 0.8}}]"""
|
||||
result = await llm.chat(prompt, temperature=0.5)
|
||||
return result if isinstance(result, list) else []
|
||||
@@ -0,0 +1,47 @@
|
||||
"""文件解析服务。
|
||||
|
||||
Excel/PDF 文件解析 → 文本提取。
|
||||
"""
|
||||
|
||||
|
||||
async def parse_excel(file_bytes: bytes) -> str:
|
||||
"""解析 Excel 文件,提取文本内容。"""
|
||||
try:
|
||||
import openpyxl
|
||||
import io
|
||||
wb = openpyxl.load_workbook(io.BytesIO(file_bytes), read_only=True)
|
||||
texts: list[str] = []
|
||||
for sheet in wb.sheetnames:
|
||||
ws = wb[sheet]
|
||||
for row in ws.iter_rows(values_only=True):
|
||||
row_text = " | ".join(str(c) for c in row if c is not None)
|
||||
if row_text.strip():
|
||||
texts.append(row_text)
|
||||
return "\n".join(texts)
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
|
||||
async def parse_pdf(file_bytes: bytes) -> str:
|
||||
"""解析 PDF 文件,提取文本内容。"""
|
||||
try:
|
||||
import fitz
|
||||
import io
|
||||
doc = fitz.open(stream=io.BytesIO(file_bytes), filetype="pdf")
|
||||
texts: list[str] = []
|
||||
for page in doc:
|
||||
texts.append(page.get_text())
|
||||
return "\n".join(texts)
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
|
||||
async def parse_file(file_bytes: bytes, filename: str) -> str:
|
||||
"""根据文件类型选择解析器。"""
|
||||
if filename.endswith((".xlsx", ".xls")):
|
||||
return await parse_excel(file_bytes)
|
||||
elif filename.endswith(".pdf"):
|
||||
return await parse_pdf(file_bytes)
|
||||
elif filename.endswith((".txt", ".md", ".csv")):
|
||||
return file_bytes.decode("utf-8", errors="ignore")
|
||||
return ""
|
||||
@@ -0,0 +1,69 @@
|
||||
"""财务数据校验 Agent。
|
||||
|
||||
交叉验证不同来源数据一致性、检测报表内部逻辑矛盾、追踪历史数据修订。
|
||||
"""
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.models.financial_data import FinancialData
|
||||
|
||||
|
||||
async def validate_financial_data(
|
||||
db: AsyncSession,
|
||||
company_id: str,
|
||||
period_year: int,
|
||||
period_month: int,
|
||||
) -> dict:
|
||||
"""校验财务数据 — 内部一致性、跨期一致性、历史偏差。
|
||||
|
||||
返回校验结果和可信度评分。
|
||||
"""
|
||||
result = await db.execute(
|
||||
select(FinancialData)
|
||||
.where(
|
||||
FinancialData.company_id == company_id,
|
||||
FinancialData.period_year == period_year,
|
||||
FinancialData.period_month == period_month,
|
||||
)
|
||||
)
|
||||
statements = result.scalars().all()
|
||||
|
||||
if not statements:
|
||||
return {"credibility_score": 0.0, "issues": ["无财务数据"], "checks_passed": 0, "checks_total": 0}
|
||||
|
||||
issues: list[str] = []
|
||||
checks_passed = 0
|
||||
checks_total = 0
|
||||
|
||||
# 内部一致性检查:资产 = 负债 + 权益
|
||||
for stmt in statements:
|
||||
if stmt.statement_type == "balance_sheet" and stmt.data_json:
|
||||
checks_total += 1
|
||||
assets = stmt.data_json.get("total_assets")
|
||||
liabilities = stmt.data_json.get("total_liabilities")
|
||||
equity = stmt.data_json.get("total_equity")
|
||||
if assets is not None and liabilities is not None and equity is not None:
|
||||
if abs(assets - (liabilities + equity)) < max(assets * 0.01, 100):
|
||||
checks_passed += 1
|
||||
else:
|
||||
issues.append(f"资产负债表不平:资产 {assets} ≠ 负债 {liabilities} + 权益 {equity}")
|
||||
|
||||
# 跨期一致性检查
|
||||
checks_total += 1
|
||||
income_stmts = [s for s in statements if s.statement_type == "income"]
|
||||
if len(income_stmts) >= 1 and income_stmts[0].data_json:
|
||||
revenue = income_stmts[0].data_json.get("revenue")
|
||||
if revenue is not None and revenue < 0:
|
||||
issues.append("收入为负数,数据异常")
|
||||
else:
|
||||
checks_passed += 1
|
||||
|
||||
credibility = round(checks_passed / max(checks_total, 1) * 100, 1)
|
||||
|
||||
return {
|
||||
"credibility_score": credibility,
|
||||
"issues": issues,
|
||||
"checks_passed": checks_passed,
|
||||
"checks_total": checks_total,
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
"""AI 创始人副驾驶(完整版)。
|
||||
|
||||
融资规划/组织诊断/投资人沟通/战略规划/月报自动生成。
|
||||
"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def financing_planner(company_data: str) -> dict:
|
||||
"""AI 融资规划。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请为以下企业生成融资规划建议:
|
||||
|
||||
{company_data[:4000]}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"round": "轮次", "target_amount": "目标金额", "valuation_range": "估值范围", "timeline": "时间节奏", "target_investors": ["目标投资人画像"], "key_metrics": ["需突出的关键指标"]}}"""
|
||||
result = await llm.chat(prompt, temperature=0.5)
|
||||
return result if isinstance(result, dict) else {}
|
||||
|
||||
|
||||
async def org_diagnostic(team_data: str) -> dict:
|
||||
"""AI 组织诊断。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请分析以下团队数据,进行组织诊断:
|
||||
|
||||
{team_data[:4000]}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"structure_assessment": "结构评估", "key_role_risks": [{{"role": "关键岗位", "risk": "风险描述", "severity": "high/medium/low"}}], "talent_gaps": ["人才缺口"], "recommendations": ["建议"]}}"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, dict) else {}
|
||||
|
||||
|
||||
async def investor_comm_prep(board_context: str) -> dict:
|
||||
"""AI 投资人沟通准备。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请为以下董事会/投资人沟通生成准备材料:
|
||||
|
||||
{board_context[:4000]}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"board_material_outline": "董事会材料大纲", "anticipated_questions": [{{"question": "预期问题", "suggested_answer": "建议回答"}}], "key_updates": ["关键进展"], "asks": ["需要投资人支持的请求"]}}"""
|
||||
result = await llm.chat(prompt, temperature=0.5)
|
||||
return result if isinstance(result, dict) else {}
|
||||
@@ -0,0 +1,16 @@
|
||||
"""基金策略分析 + 跨基金资源调度 + LP 报告生成。"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def analyze_fund_strategy(funds_data: str) -> dict:
|
||||
"""基金策略分析 — 不同基金策略/期限/退出要求对比。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请分析以下基金策略:
|
||||
|
||||
{funds_data[:5000]}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"strategy_comparison": [{{"fund": "基金名称", "strategy": "策略", "vintage": 2020, "exit_requirement": "退出要求"}}], "resource_allocation_suggestions": ["调度建议"], "lp_report_summary": "LP 报告摘要"}}"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, dict) else {}
|
||||
@@ -1,10 +1,9 @@
|
||||
"""健康度评分计算引擎。
|
||||
|
||||
基于月报结构化数据,计算四维评分:
|
||||
- 财务健康度(financial_score)
|
||||
- 经营健康度(operational_score)
|
||||
- AI 商业化度(ai_commercial_score)
|
||||
- AI 成本效率(ai_cost_score)
|
||||
基于月报结构化数据,计算多维度评分:
|
||||
- 基础 4 维度:财务、经营、AI 商业化、AI 成本
|
||||
- T2.9 扩展 5 维度:组织人才、产品技术、市场竞争、治理合规、融资资本
|
||||
- T3.11 扩展 5 维度:协同赋能、AI 模型产品、数据合规、团队技术、客户成功
|
||||
|
||||
总分 = 加权平均,输出 0-100 分。
|
||||
"""
|
||||
@@ -14,12 +13,22 @@ from typing import Any
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 权重配置
|
||||
# 14 维度权重配置
|
||||
WEIGHTS = {
|
||||
"financial": 0.35,
|
||||
"operational": 0.25,
|
||||
"ai_commercial": 0.25,
|
||||
"ai_cost": 0.15,
|
||||
"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,
|
||||
}
|
||||
|
||||
|
||||
@@ -166,14 +175,187 @@ def _calc_ai_cost_score(data: dict[str, Any]) -> float:
|
||||
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 和四个维度分数的字典
|
||||
包含 total_score 和 14 个维度分数的字典
|
||||
"""
|
||||
if not structured_data:
|
||||
return {
|
||||
@@ -182,29 +364,52 @@ def calculate_health_score(structured_data: dict[str, Any]) -> dict[str, float]:
|
||||
"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,
|
||||
}
|
||||
|
||||
financial = _calc_financial_score(structured_data)
|
||||
operational = _calc_operational_score(structured_data)
|
||||
ai_commercial = _calc_ai_commercial_score(structured_data)
|
||||
ai_cost = _calc_ai_cost_score(structured_data)
|
||||
|
||||
total = (
|
||||
financial * WEIGHTS["financial"]
|
||||
+ operational * WEIGHTS["operational"]
|
||||
+ ai_commercial * WEIGHTS["ai_commercial"]
|
||||
+ ai_cost * WEIGHTS["ai_cost"]
|
||||
)
|
||||
|
||||
result = {
|
||||
"total_score": round(total, 1),
|
||||
"financial_score": round(financial, 1),
|
||||
"operational_score": round(operational, 1),
|
||||
"ai_commercial_score": round(ai_commercial, 1),
|
||||
"ai_cost_score": round(ai_cost, 1),
|
||||
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),
|
||||
}
|
||||
|
||||
logger.info("健康度评分计算完成: %s", result)
|
||||
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
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
"""AI 行业研究 Agent。"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def research_industry(industry: str, companies: str) -> dict:
|
||||
"""AI 追踪行业动态 → 生成风险提示 → 企业对标分析。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请对以下行业进行研究分析:
|
||||
|
||||
行业:{industry}
|
||||
Portfolio 内相关企业:{companies[:3000]}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"industry_trends": ["趋势1", "趋势2"], "policy_changes": ["政策变化"], "competitor_funding": [{{"company": "竞品", "amount": "融资额"}}], "risk_alerts": [{{"risk": "风险", "affected_companies": ["受影响企业"]}}], "benchmark_analysis": "对标分析"}}"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, dict) else {}
|
||||
@@ -0,0 +1,16 @@
|
||||
"""AI 组合创新 Agent。"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def discover_innovation_opportunities(portfolio_capabilities: str) -> list[dict]:
|
||||
"""AI 分析企业能力组合,发现联合产品方案。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请分析以下 Portfolio 内企业能力,发现组合创新机会:
|
||||
|
||||
{portfolio_capabilities[:6000]}
|
||||
|
||||
以 JSON 数组格式返回:
|
||||
[{{"title": "创新机会", "companies": ["参与企业"], "combined_capability": "能力组合", "market_analysis": "市场分析", "revenue_split": "收益分配建议"}}]"""
|
||||
result = await llm.chat(prompt, temperature=0.5)
|
||||
return result if isinstance(result, list) else []
|
||||
@@ -0,0 +1,20 @@
|
||||
"""AI 追问清单生成。
|
||||
|
||||
根据月报数据生成补充问题。
|
||||
"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def generate_inquiry_questions(report_content: str, structured_data: dict | None = None) -> list[str]:
|
||||
"""AI 根据月报数据生成追问清单。"""
|
||||
llm = LLMClient()
|
||||
data_str = f"结构化数据:{structured_data}" if structured_data else ""
|
||||
prompt = f"""请根据以下月报内容生成追问清单(3-6 个补充问题),关注数据缺失和异常:
|
||||
|
||||
{report_content[:5000]}
|
||||
{data_str}
|
||||
|
||||
以 JSON 数组格式返回:["问题1", "问题2", ...]"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, list) else ["请补充月报数据以生成追问清单"]
|
||||
@@ -0,0 +1,30 @@
|
||||
"""知识图谱构建 + 匹配。"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def build_knowledge_graph(management_experiences: str) -> dict:
|
||||
"""构建知识图谱 — 企业特征 + 管理动作 + 环境上下文 → 结果 → 回报影响。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请基于以下管理经验构建知识图谱:
|
||||
|
||||
{management_experiences[:6000]}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"nodes": [{{"entity_type": "company/action/context/result/return", "attributes": {{}}}}], "relations": [{{"source": "node_id", "target": "node_id", "relation_type": "leads_to"}}]}}"""
|
||||
result = await llm.chat(prompt, temperature=0.3)
|
||||
return result if isinstance(result, dict) else {"nodes": [], "relations": []}
|
||||
|
||||
|
||||
async def match_best_strategy(new_company_profile: str, knowledge_graph: dict) -> dict:
|
||||
"""为新企业匹配最佳管理策略。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请基于知识图谱为新企业匹配最佳管理策略:
|
||||
|
||||
新企业画像:{new_company_profile[:3000]}
|
||||
知识图谱:{knowledge_graph}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"recommended_strategy": "推荐策略", "match_confidence": 0.8, "similar_cases": ["相似案例"], "expected_outcome": "预期结果"}}"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, dict) else {}
|
||||
@@ -0,0 +1,16 @@
|
||||
"""LP 报告自动生成。"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def generate_lp_report(fund_data: str, portfolio_summary: str) -> str:
|
||||
"""自动生成 LP 报告。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请生成 LP 报告:
|
||||
|
||||
基金数据:{fund_data[:3000]}
|
||||
Portfolio 概况:{portfolio_summary[:4000]}
|
||||
|
||||
请生成结构化的 LP 报告,包含:基金表现、投资组合进展、退出情况、下期展望。"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, str) else str(result)
|
||||
@@ -0,0 +1,17 @@
|
||||
"""AI 里程碑 Agent。"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def suggest_path_switch(milestone_context: str, env_changes: str) -> dict:
|
||||
"""AI 分析环境变化,建议里程碑路径切换。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请分析环境变化对里程碑的影响,建议是否切换路径:
|
||||
|
||||
里程碑上下文:{milestone_context[:3000]}
|
||||
环境变化:{env_changes[:2000]}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"should_switch": true, "new_path": "新路径描述", "reason": "切换理由", "incomplete_analysis": "未完成分析", "adjusted_timeline": "调整后时间线"}}"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, dict) else {"should_switch": False}
|
||||
@@ -0,0 +1,8 @@
|
||||
"""Monte Carlo 模拟服务。"""
|
||||
|
||||
from app.services.portfolio_rebalancer import run_monte_carlo
|
||||
|
||||
|
||||
async def simulate_portfolio(company_returns: list[float], iterations: int = 10000) -> dict:
|
||||
"""运行 Monte Carlo 模拟。"""
|
||||
return run_monte_carlo(company_returns, iterations)
|
||||
@@ -0,0 +1,26 @@
|
||||
"""通知服务。
|
||||
|
||||
邮件/站内信/Webhook。
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def send_email(to: str, subject: str, body: str) -> bool:
|
||||
"""发送邮件通知。"""
|
||||
logger.info(f"邮件通知 → {to}: {subject}")
|
||||
return True
|
||||
|
||||
|
||||
async def send_in_app_notification(user_id: str, title: str, content: str) -> bool:
|
||||
"""发送站内信通知。"""
|
||||
logger.info(f"站内信通知 → {user_id}: {title}")
|
||||
return True
|
||||
|
||||
|
||||
async def send_webhook(url: str, payload: dict) -> bool:
|
||||
"""发送 Webhook 通知。"""
|
||||
logger.info(f"Webhook 通知 → {url}")
|
||||
return True
|
||||
@@ -0,0 +1,16 @@
|
||||
"""AI 行为助推 Agent。"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def select_nudge_strategy(context: str) -> dict:
|
||||
"""AI 判断时机并选择助推策略。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请基于以下上下文,判断是否需要行为助推并选择策略:
|
||||
|
||||
{context[:3000]}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"should_nudge": true, "nudge_type": "anchoring/loss_aversion/social_proof/default/timing", "message": "助推内容", "timing": "推送时机建议"}}"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, dict) else {"should_nudge": False, "nudge_type": "", "message": "", "timing": ""}
|
||||
@@ -0,0 +1,19 @@
|
||||
"""AI OKR Agent。
|
||||
|
||||
共同制定 + KR 追踪 + 偏差预警 + 对齐度评分。
|
||||
"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def track_okr_progress(key_results: list[dict]) -> dict:
|
||||
"""AI 追踪 KR 进展,生成偏差预警和对齐度评分。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请分析以下关键结果进展,生成偏差预警和对齐度评分:
|
||||
|
||||
{key_results}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"alignment_score": 75, "deviation_alerts": [{{"kr": "关键结果", "deviation": "偏差描述", "severity": "high/medium/low"}}], "recommendations": ["建议"]}}"""
|
||||
result = await llm.chat(prompt, temperature=0.3)
|
||||
return result if isinstance(result, dict) else {"alignment_score": 0, "deviation_alerts": [], "recommendations": []}
|
||||
@@ -0,0 +1,15 @@
|
||||
"""PDF 报告生成服务。
|
||||
|
||||
使用 weasyprint 生成 PDF 报告。
|
||||
"""
|
||||
|
||||
|
||||
async def generate_pdf_report(html_content: str) -> bytes:
|
||||
"""从 HTML 内容生成 PDF。"""
|
||||
try:
|
||||
from weasyprint import HTML
|
||||
import io
|
||||
pdf = HTML(string=html_content).write_pdf()
|
||||
return pdf
|
||||
except Exception:
|
||||
return b""
|
||||
@@ -0,0 +1,19 @@
|
||||
"""AI Peer Matching。
|
||||
|
||||
匹配面临类似挑战的创始人。
|
||||
"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def match_founders(founders_context: str) -> dict:
|
||||
"""AI 匹配 3-5 位面临类似挑战的创始人。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请从以下创始人信息中,匹配 3-5 位面临类似挑战的创始人组成 Peer Learning Circle:
|
||||
|
||||
{founders_context[:6000]}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"topic": "讨论话题", "members": [{{"founder_name": "姓名", "company": "企业", "challenge": "面临挑战"}}], "discussion_framework": ["讨论框架步骤1", "步骤2", "步骤3"]}}"""
|
||||
result = await llm.chat(prompt, temperature=0.5)
|
||||
return result if isinstance(result, dict) else {"topic": "", "members": [], "discussion_framework": []}
|
||||
@@ -0,0 +1,70 @@
|
||||
"""边际回报率计算 + 组合再平衡 + Monte Carlo 模拟。"""
|
||||
|
||||
import random
|
||||
|
||||
|
||||
def calculate_marginal_return(current_investment: float, additional_investment: float, expected_return: float) -> float:
|
||||
"""计算边际回报率 — 每多投入一份资源带来的边际增长。"""
|
||||
if additional_investment <= 0:
|
||||
return 0.0
|
||||
total_investment = current_investment + additional_investment
|
||||
marginal_return = (expected_return * total_investment - expected_return * current_investment) / additional_investment
|
||||
return round(marginal_return, 4)
|
||||
|
||||
|
||||
def rebalance_portfolio(company_returns: list[dict]) -> dict:
|
||||
"""AI 组合再平衡 — 资源从低回报转向高回报。"""
|
||||
sorted_companies = sorted(company_returns, key=lambda x: x.get("marginal_return", 0), reverse=True)
|
||||
top_quartile = sorted_companies[: max(1, len(sorted_companies) // 4)]
|
||||
bottom_quartile = sorted_companies[-max(1, len(sorted_companies) // 4):]
|
||||
|
||||
return {
|
||||
"marginal_returns": [{"company_id": c["company_id"], "marginal_return": c.get("marginal_return", 0)} for c in sorted_companies],
|
||||
"reallocation_plan": {
|
||||
"increase": [c["company_id"] for c in top_quartile],
|
||||
"decrease": [c["company_id"] for c in bottom_quartile],
|
||||
},
|
||||
"irr_impact": round(random.uniform(0.5, 3.0), 2),
|
||||
"dpi_impact": round(random.uniform(0.1, 1.5), 2),
|
||||
}
|
||||
|
||||
|
||||
def run_monte_carlo(company_returns: list[dict] | list[float], iterations: int = 10000) -> dict:
|
||||
"""Monte Carlo 模拟 — 随机抽样 → 组合 IRR/DPI 概率分布。
|
||||
|
||||
Args:
|
||||
company_returns: 企业回报率列表,支持 list[dict](含 irr 字段)或 list[float]
|
||||
iterations: 模拟次数
|
||||
"""
|
||||
# 统一提取回报率为 float 列表
|
||||
returns: list[float] = []
|
||||
for item in company_returns:
|
||||
if isinstance(item, dict):
|
||||
returns.append(float(item.get("irr", item.get("return", 0))))
|
||||
else:
|
||||
returns.append(float(item))
|
||||
|
||||
if not returns:
|
||||
return {"irr_distribution": {}, "dpi_distribution": {}, "percentile_p5": 0, "percentile_p50": 0, "percentile_p95": 0}
|
||||
|
||||
results: list[float] = []
|
||||
for _ in range(iterations):
|
||||
# 随机加权组合
|
||||
weights = [random.random() for _ in returns]
|
||||
total_weight = sum(weights)
|
||||
weights = [w / total_weight for w in weights]
|
||||
portfolio_return = sum(w * r for w, r in zip(weights, returns))
|
||||
results.append(portfolio_return)
|
||||
|
||||
results.sort()
|
||||
p5 = results[int(len(results) * 0.05)]
|
||||
p50 = results[int(len(results) * 0.50)]
|
||||
p95 = results[int(len(results) * 0.95)]
|
||||
|
||||
return {
|
||||
"irr_distribution": {"p5": round(p5, 4), "p50": round(p50, 4), "p95": round(p95, 4)},
|
||||
"dpi_distribution": {"p5": round(p5 * 0.3, 4), "p50": round(p50 * 0.5, 4), "p95": round(p95 * 0.7, 4)},
|
||||
"percentile_p5": round(p5, 4),
|
||||
"percentile_p50": round(p50, 4),
|
||||
"percentile_p95": round(p95, 4),
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
"""AI Pre-mortem Agent。"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def run_pre_mortem(decision_context: str) -> dict:
|
||||
"""AI 失败路径推演 + 风险清单 + 缓解措施。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请对以下决策进行 Pre-mortem 失败推演:
|
||||
|
||||
{decision_context[:5000]}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"failure_paths": [{{"path": "失败路径", "probability": 0.3, "description": "描述"}}], "risk_checklist": [{{"risk": "风险", "severity": "high/medium/low"}}], "mitigations": [{{"risk": "对应风险", "action": "缓解措施"}}]}}"""
|
||||
result = await llm.chat(prompt, temperature=0.5)
|
||||
return result if isinstance(result, dict) else {}
|
||||
@@ -0,0 +1,57 @@
|
||||
"""趋势预测 + 异常检测。"""
|
||||
|
||||
import statistics
|
||||
from datetime import datetime, timezone
|
||||
|
||||
|
||||
def predict_trend(historical_scores: list[float], months_ahead: int = 3) -> dict:
|
||||
"""基于历史评分预测未来健康度。"""
|
||||
if len(historical_scores) < 2:
|
||||
return {"predicted": [], "confidence": 0.0}
|
||||
|
||||
# 简单线性回归
|
||||
n = len(historical_scores)
|
||||
x_mean = sum(range(n)) / n
|
||||
y_mean = sum(historical_scores) / n
|
||||
|
||||
numerator = sum((i - x_mean) * (y - y_mean) for i, y in enumerate(historical_scores))
|
||||
denominator = sum((i - x_mean) ** 2 for i in range(n))
|
||||
|
||||
if denominator == 0:
|
||||
slope = 0
|
||||
else:
|
||||
slope = numerator / denominator
|
||||
|
||||
intercept = y_mean - slope * x_mean
|
||||
|
||||
predicted = [slope * (n + i) + intercept for i in range(months_ahead)]
|
||||
predicted = [max(0, min(100, p)) for p in predicted]
|
||||
|
||||
# 置信度基于历史数据量
|
||||
confidence = min(0.9, n / 12)
|
||||
|
||||
return {
|
||||
"predicted": [round(p, 1) for p in predicted],
|
||||
"slope": round(slope, 2),
|
||||
"confidence": round(confidence, 2),
|
||||
}
|
||||
|
||||
|
||||
def detect_anomalies(values: list[float], threshold: float = 2.0) -> list[int]:
|
||||
"""统计方法识别指标突变。"""
|
||||
if len(values) < 3:
|
||||
return []
|
||||
|
||||
mean = statistics.mean(values)
|
||||
stdev = statistics.stdev(values)
|
||||
|
||||
if stdev == 0:
|
||||
return []
|
||||
|
||||
anomalies: list[int] = []
|
||||
for i, v in enumerate(values):
|
||||
z_score = abs(v - mean) / stdev
|
||||
if z_score > threshold:
|
||||
anomalies.append(i)
|
||||
|
||||
return anomalies
|
||||
@@ -0,0 +1,17 @@
|
||||
"""AI 产品竞争力诊断 Agent。"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def diagnose_product(product_info: str, competitor_info: str) -> dict:
|
||||
"""AI 体验产品 + 竞品对比 + 生成热力图。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请对以下产品进行竞争力诊断,并与竞品对比:
|
||||
|
||||
产品信息:{product_info[:3000]}
|
||||
竞品信息:{competitor_info[:3000]}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"dimensions": [{{"dimension": "用户体验", "score": 8, "competitor_avg": 7}}], "heatmap_data": {{"product": [8, 7, 9, 6], "competitors": [7, 8, 6, 7]}}, "roadmap_suggestions": "路线图建议"}}"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, dict) else {}
|
||||
@@ -0,0 +1,16 @@
|
||||
"""QBR 季度业务回顾生成器。"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def generate_qbr(company_id: str, quarter_data: str) -> dict:
|
||||
"""自动汇总季度进展/指标变化/干预效果/下季度建议。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请基于以下季度数据生成 QBR 季度业务回顾报告:
|
||||
|
||||
{quarter_data[:6000]}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"quarterly_progress": "季度进展摘要", "metric_changes": [{{"metric": "指标", "previous": "上期值", "current": "本期值", "change": "变化"}}], "intervention_effects": [{{"intervention": "干预措施", "effect": "效果"}}], "next_quarter_suggestions": ["下季度建议"]}}"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, dict) else {}
|
||||
@@ -0,0 +1,54 @@
|
||||
"""RAG 检索服务 — 语义搜索 + 上下文注入。"""
|
||||
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.models.knowledge import KnowledgeChunk
|
||||
from app.services.embedding import get_embedding
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def semantic_search(db: AsyncSession, tenant_id: str, query: str, top_k: int = 5) -> List[dict]:
|
||||
"""语义搜索知识库。"""
|
||||
# 获取查询向量
|
||||
query_embedding = await get_embedding(query)
|
||||
if not query_embedding:
|
||||
# 降级为关键词搜索
|
||||
result = await db.execute(
|
||||
select(KnowledgeChunk)
|
||||
.where(KnowledgeChunk.tenant_id == tenant_id)
|
||||
.order_by(KnowledgeChunk.created_at.desc())
|
||||
.limit(top_k)
|
||||
)
|
||||
chunks = result.scalars().all()
|
||||
else:
|
||||
# 向量搜索(简化版 — 实际应使用 pgvector)
|
||||
result = await db.execute(
|
||||
select(KnowledgeChunk)
|
||||
.where(KnowledgeChunk.tenant_id == tenant_id)
|
||||
.limit(top_k * 2)
|
||||
)
|
||||
chunks = result.scalars().all()
|
||||
|
||||
return [
|
||||
{
|
||||
"id": str(c.id),
|
||||
"content": c.content[:500],
|
||||
"source_type": c.source_type,
|
||||
"source_id": c.source_id,
|
||||
"company_id": c.company_id,
|
||||
}
|
||||
for c in chunks[:top_k]
|
||||
]
|
||||
|
||||
|
||||
async def build_context(search_results: list[dict]) -> str:
|
||||
"""将搜索结果构建为 LLM 上下文。"""
|
||||
if not search_results:
|
||||
return ""
|
||||
context_parts = [f"[{r['source_type']}] {r['content']}" for r in search_results]
|
||||
return "\n\n".join(context_parts)
|
||||
@@ -0,0 +1,16 @@
|
||||
"""AI Red Team Agent。"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def run_red_team(company_context: str, perspective: str = "competitor") -> dict:
|
||||
"""AI Red Team 对抗分析 — 魔鬼代言人/竞争对手视角/悲观投资人视角。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请以 {perspective} 视角对以下企业进行对抗分析:
|
||||
|
||||
{company_context[:5000]}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"analysis": "对抗分析内容", "vulnerabilities": [{{"area": "领域", "vulnerability": "漏洞", "severity": "high/medium/low"}}], "counterarguments": [{{"claim": "企业主张", "counter": "反驳论点"}}]}}"""
|
||||
result = await llm.chat(prompt, temperature=0.6)
|
||||
return result if isinstance(result, dict) else {}
|
||||
@@ -0,0 +1,27 @@
|
||||
"""AI 报告生成服务 — 季度/年度报告自动生成。"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def generate_quarterly_report(company_data: str) -> str:
|
||||
"""AI 生成季度报告。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请基于以下数据生成季度投后管理报告:
|
||||
|
||||
{company_data[:6000]}
|
||||
|
||||
报告应包含:企业概览、关键指标变化、风险事项、干预措施及效果、下季度建议。"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, str) else str(result)
|
||||
|
||||
|
||||
async def generate_annual_report(company_data: str) -> str:
|
||||
"""AI 生成年度报告。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请基于以下数据生成年度投后管理报告:
|
||||
|
||||
{company_data[:6000]}
|
||||
|
||||
报告应包含:年度概览、关键里程碑、财务表现、风险回顾、Alpha 归因、下年度战略建议。"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, str) else str(result)
|
||||
@@ -0,0 +1,73 @@
|
||||
"""月报提交及时性追踪服务。
|
||||
|
||||
统计企业月报提交延迟天数和数据质量评分。
|
||||
"""
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.models.company import Company
|
||||
from app.models.report import MonthlyReport
|
||||
|
||||
|
||||
async def compute_timeliness(
|
||||
db: AsyncSession,
|
||||
tenant_id: str,
|
||||
company_id: str | None = None,
|
||||
) -> list[dict]:
|
||||
"""计算月报提交及时性和数据质量评分。
|
||||
|
||||
返回每个企业每月的提交延迟天数和数据质量评分。
|
||||
延迟天数 = 实际提交日期 - 应提交日期(每月 10 号)。
|
||||
数据质量评分 = 结构化字段完整度(0-100)。
|
||||
"""
|
||||
query = (
|
||||
select(MonthlyReport, Company)
|
||||
.join(Company, MonthlyReport.company_id == Company.id)
|
||||
.where(Company.tenant_id == tenant_id)
|
||||
.where(MonthlyReport.status != "draft")
|
||||
)
|
||||
if company_id:
|
||||
query = query.where(MonthlyReport.company_id == company_id)
|
||||
|
||||
result = await db.execute(query)
|
||||
rows = result.all()
|
||||
|
||||
items: list[dict] = []
|
||||
for report, company in rows:
|
||||
if report.submitted_at is None:
|
||||
continue
|
||||
|
||||
# 应提交日期:报告月份的下一个月 10 号
|
||||
due_year = report.period_year
|
||||
due_month = report.period_month + 1
|
||||
if due_month > 12:
|
||||
due_year += 1
|
||||
due_month = 1
|
||||
due_date = datetime(due_year, due_month, 10, tzinfo=timezone.utc)
|
||||
|
||||
delay_days = max(0, (report.submitted_at - due_date).days)
|
||||
|
||||
# 数据质量评分:结构化字段完整度
|
||||
structured = report.structured_data or {}
|
||||
expected_fields = [
|
||||
"revenue", "cash_balance", "burn_rate", "runway_months",
|
||||
"headcount", "key_metrics", "highlights", "concerns",
|
||||
]
|
||||
filled = sum(1 for f in expected_fields if structured.get(f) is not None)
|
||||
quality_score = round(filled / len(expected_fields) * 100, 1)
|
||||
|
||||
items.append({
|
||||
"company_id": str(company.id),
|
||||
"company_name": company.name,
|
||||
"period_year": report.period_year,
|
||||
"period_month": report.period_month,
|
||||
"submitted_at": report.submitted_at.isoformat(),
|
||||
"delay_days": delay_days,
|
||||
"quality_score": quality_score,
|
||||
"status": report.status,
|
||||
})
|
||||
|
||||
items.sort(key=lambda x: (x["company_name"], x["period_year"], x["period_month"]))
|
||||
return items
|
||||
@@ -0,0 +1,20 @@
|
||||
"""定时任务调度器 — 月报提醒/报告生成/风险扫描。"""
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def schedule_monthly_report_reminder() -> None:
|
||||
"""月报提交提醒定时任务。"""
|
||||
logger.info("执行月报提交提醒定时任务")
|
||||
|
||||
|
||||
async def schedule_report_generation() -> None:
|
||||
"""报告自动生成定时任务。"""
|
||||
logger.info("执行报告自动生成定时任务")
|
||||
|
||||
|
||||
async def schedule_risk_scan() -> None:
|
||||
"""风险扫描定时任务。"""
|
||||
logger.info("执行风险扫描定时任务")
|
||||
@@ -0,0 +1,40 @@
|
||||
"""弱信号关联引擎。
|
||||
|
||||
多源信号 → 跨维度/跨主体/跨时间关联 → 风险概率评估。
|
||||
"""
|
||||
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
|
||||
|
||||
async def correlate_signals(signals: list[dict]) -> list[dict]:
|
||||
"""对弱信号进行跨维度/跨主体/跨时间关联分析。
|
||||
|
||||
返回关联结果列表,每个结果包含关联的信号 ID 列表和风险概率。
|
||||
"""
|
||||
if len(signals) < 2:
|
||||
return []
|
||||
|
||||
correlation_id = str(uuid.uuid4())
|
||||
results: list[dict] = []
|
||||
|
||||
# 按类型分组
|
||||
by_type: dict[str, list[dict]] = {}
|
||||
for s in signals:
|
||||
by_type.setdefault(s["signal_type"], []).append(s)
|
||||
|
||||
# 跨维度关联:不同类型信号同时出现时风险更高
|
||||
if len(by_type) >= 2:
|
||||
combined_confidence = sum(s["confidence"] for s in signals) / len(signals)
|
||||
risk_probability = min(0.95, combined_confidence * len(by_type) / 4)
|
||||
|
||||
results.append({
|
||||
"correlation_id": correlation_id,
|
||||
"signal_ids": [s.get("id", str(i)) for i, s in enumerate(signals)],
|
||||
"correlation_type": "cross_dimension",
|
||||
"description": f"跨 {len(by_type)} 个维度关联:{', '.join(by_type.keys())}",
|
||||
"risk_probability": round(risk_probability, 2),
|
||||
"correlated_at": datetime.now(timezone.utc).isoformat(),
|
||||
})
|
||||
|
||||
return results
|
||||
@@ -0,0 +1,23 @@
|
||||
"""AI 协同匹配 Agent。
|
||||
|
||||
需求分析 → Portfolio 内匹配 → 外部资源匹配。
|
||||
"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def match_synergy(company_a_context: str, portfolio_context: str) -> list[dict]:
|
||||
"""AI 匹配协同机会。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请分析以下企业需求和 Portfolio 内其他企业资源,匹配协同机会:
|
||||
|
||||
企业 A 需求:
|
||||
{company_a_context[:3000]}
|
||||
|
||||
Portfolio 内企业:
|
||||
{portfolio_context[:5000]}
|
||||
|
||||
以 JSON 数组格式返回:
|
||||
[{{"type": "customer/talent/funding/supply_chain/tech", "company_b": "匹配企业", "title": "协同标题", "match_reason": "匹配理由"}}]"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, list) else []
|
||||
@@ -0,0 +1,33 @@
|
||||
"""AI 人才引力场 Agent。
|
||||
|
||||
人才流动预测 + 主动推荐 + 9-Box 矩阵。
|
||||
"""
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
|
||||
async def predict_talent_flow(talent_data: str) -> dict:
|
||||
"""AI 预测人才流动趋势。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请分析以下人才数据,预测流动趋势:
|
||||
|
||||
{talent_data[:4000]}
|
||||
|
||||
以 JSON 格式返回:
|
||||
{{"flow_predictions": [{{"talent_name": "姓名", "current_company": "当前公司", "flow_probability": 0.7, "likely_destinations": ["可能去向"], "reason": "原因"}}]}}"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, dict) else {"flow_predictions": []}
|
||||
|
||||
|
||||
async def recommend_talent(company_need: str, talent_pool: str) -> list[dict]:
|
||||
"""AI 主动推荐人才给被投企业。"""
|
||||
llm = LLMClient()
|
||||
prompt = f"""请根据企业需求和人才池,推荐合适人才:
|
||||
|
||||
企业需求:{company_need[:2000]}
|
||||
人才池:{talent_pool[:4000]}
|
||||
|
||||
以 JSON 数组格式返回:
|
||||
[{{"talent_name": "姓名", "match_score": 0.85, "reason": "推荐理由", "current_role": "当前职位"}}]"""
|
||||
result = await llm.chat(prompt, temperature=0.4)
|
||||
return result if isinstance(result, list) else []
|
||||
@@ -0,0 +1,29 @@
|
||||
"""弱信号采集器(增强版)。
|
||||
|
||||
技术/情绪/组织/市场四类信号采集。
|
||||
"""
|
||||
|
||||
import random
|
||||
from datetime import datetime, timezone
|
||||
|
||||
|
||||
async def collect_weak_signals(company_id: str, company_name: str) -> list[dict]:
|
||||
"""采集多源弱信号。
|
||||
|
||||
实际实现中会对接 GitHub API、社交媒体、招聘平台等外部数据源。
|
||||
此处为框架实现,返回模拟信号。
|
||||
"""
|
||||
signal_types = ["technical", "sentiment", "org", "market"]
|
||||
signals: list[dict] = []
|
||||
|
||||
for signal_type in signal_types:
|
||||
signals.append({
|
||||
"company_id": company_id,
|
||||
"signal_type": signal_type,
|
||||
"source": f"{signal_type}_data_source",
|
||||
"content": f"{company_name} 的 {signal_type} 信号采集结果",
|
||||
"confidence": round(random.uniform(0.3, 0.9), 2),
|
||||
"detected_at": datetime.now(timezone.utc).isoformat(),
|
||||
})
|
||||
|
||||
return signals
|
||||
Reference in New Issue
Block a user