feat: 初始提交 - 科创企业特有风险的识别与管理 (数智风控系统)

This commit is contained in:
Chen Xiao
2026-08-14 08:21:26 +08:00
commit a41576a8c0
190 changed files with 28531 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
"""多智能体辩论模块"""
+203
View File
@@ -0,0 +1,203 @@
# -*- coding: utf-8 -*-
"""
Agent 基类
支持逐 Token 实时流式打字机输出 (Token-level UI Streaming)
捕获思维链 (reasoning_content) 与最终生成结果 (content) 逐字推送到前端
"""
import json
import logging
import time
from typing import Optional, Callable
logger = logging.getLogger(__name__)
class BaseAgent:
"""智能体基类,支持 Token 级流式 LLM 推理与降级逻辑"""
def __init__(self, name: str, system_prompt: str, role_icon: str = "🤖"):
self.name = name
self.system_prompt = system_prompt
self.role_icon = role_icon
self._client = None
# 推理链记录
self.reasoning_trace = []
# 逐 Token 实时回调函数: callback(token_type: "reasoning"|"content", token_text: str)
self.on_token_callback: Optional[Callable[[str, str], None]] = None
def _get_client(self):
"""延迟初始化 OpenAI 客户端"""
if self._client is not None:
return self._client
try:
import httpx
from openai import OpenAI
import os
from config import (
DEEPSEEK_API_KEY, DEEPSEEK_BASE_URL, DEEPSEEK_MODEL,
VOLCENGINE_API_KEY, VOLCENGINE_BASE_URL, VOLCENGINE_MODEL,
OPENAI_API_KEY, OPENAI_BASE_URL, OPENAI_MODEL
)
api_key = os.environ.get("DEEPSEEK_API_KEY", "")
if api_key:
base_url = DEEPSEEK_BASE_URL
model = DEEPSEEK_MODEL
else:
api_key = VOLCENGINE_API_KEY
base_url = VOLCENGINE_BASE_URL
model = VOLCENGINE_MODEL
if not api_key:
api_key = OPENAI_API_KEY
base_url = OPENAI_BASE_URL
model = OPENAI_MODEL
if api_key:
http_client = httpx.Client(trust_env=False, timeout=60.0)
self._client = OpenAI(
api_key=api_key,
base_url=base_url,
http_client=http_client,
)
self._model = model
logger.info(f"[{self.name}] 已成功连接大模型服务")
return self._client
except ImportError:
logger.warning("openai 库未安装")
except Exception as e:
logger.warning(f"初始化 LLM 客户端失败: {e}")
return None
def _trace(self, step: str, content: str):
"""记录推理链步骤"""
entry = {
"timestamp": time.strftime("%H:%M:%S"),
"step": step,
"content": content,
"agent": self.name,
"icon": self.role_icon
}
self.reasoning_trace.append(entry)
def infer(self, prompt: str, temperature: float = 0.1, max_retries: int = 0) -> str:
"""
执行 SSE 流式 LLM 推理 (stream=True)
逐 Token 实时推送到 on_token_callback 渲染打字机效果
"""
self.reasoning_trace = []
self._trace("📝 构建 Context", f"准备【{self.name}】数据与 Prompt")
client = self._get_client()
if client is None:
self._trace("⚠️ 状态通知", "大模型未就绪,切换至专家规则引擎")
logger.info(f"[{self.name}] LLM 不可用,降级到规则引擎")
fallback = self.fallback_inference(prompt)
self._trace("🔧 专家引擎输出", fallback)
return fallback
self._trace("🔗 大模型连接", "已连接大模型推理服务")
for attempt in range(max_retries + 1):
try:
self._trace("🚀 发起流式推理", "正在建立 SSE 流式传输通道...")
t0 = time.time()
stream_resp = client.chat.completions.create(
model=self._model,
messages=[
{"role": "system", "content": self.system_prompt},
{"role": "user", "content": prompt},
],
temperature=temperature,
max_tokens=2048,
stream=True,
timeout=60,
)
full_content = []
reasoning_chunks = []
for chunk in stream_resp:
if not chunk.choices:
continue
delta = chunk.choices[0].delta
# 1. 逐 Token 提取深度思考过程 (reasoning_content)
reasoning_piece = getattr(delta, "reasoning_content", None) or getattr(delta, "reasoning", None)
if reasoning_piece:
reasoning_chunks.append(reasoning_piece)
if self.on_token_callback:
try:
self.on_token_callback("reasoning", reasoning_piece)
except Exception:
pass
# 2. 逐 Token 提取正式回答内容 (content)
content_piece = delta.content
if content_piece:
full_content.append(content_piece)
if self.on_token_callback:
try:
self.on_token_callback("content", content_piece)
except Exception:
pass
elapsed = time.time() - t0
final_text = "".join(full_content)
full_reasoning = "".join(reasoning_chunks)
if full_reasoning:
self._trace("🧠 完整思维链", full_reasoning)
if final_text.strip():
self._trace("✅ 流式生成完毕", f"耗时 {elapsed:.1f}s | 产出 {len(final_text)} 字符")
self._trace("📄 原始推理输出", final_text)
return final_text
else:
self._trace("⚠️ 输出为空", "流式生成无有效内容,降级到专家引擎")
except Exception as e:
error_msg = str(e)
self._trace("⚡ 流式传输异常", f"连接中断: {error_msg}")
logger.warning(f"[{self.name}] 流式调用失败: {e}")
self._trace("🛡️ 安全降级", "无缝切换至离线风控规则引擎")
fallback = self.fallback_inference(prompt)
self._trace("🔧 专家引擎输出", fallback)
return fallback
def infer_json(self, prompt: str, temperature: float = 0.1) -> dict:
"""
执行 LLM 推理并解析为 JSON
"""
result = self.infer(prompt, temperature)
try:
if "```json" in result:
json_str = result.split("```json")[1].split("```")[0].strip()
parsed = json.loads(json_str)
self._trace("✅ 结构解析", "从 Markdown 成功提取 JSON 数据")
return parsed
elif "```" in result:
json_str = result.split("```")[1].split("```")[0].strip()
parsed = json.loads(json_str)
self._trace("✅ 结构解析", "从代码块成功提取 JSON 数据")
return parsed
else:
parsed = json.loads(result)
self._trace("✅ 结构解析", "直接解析 JSON 成功")
return parsed
except (json.JSONDecodeError, IndexError):
self._trace("⚠️ 格式适配", "启用自动结构修正")
logger.warning(f"[{self.name}] JSON 解析失败,返回原始文本")
return {"raw_response": result, "parse_error": True}
def fallback_inference(self, prompt: str) -> str:
"""规则引擎降级推理"""
return json.dumps({"error": "大模型服务不可用,规则引擎未实现"}, ensure_ascii=False)
def __repr__(self):
return f"{self.role_icon} {self.name}"
+178
View File
@@ -0,0 +1,178 @@
# -*- coding: utf-8 -*-
"""
多智能体辩论编排引擎
流程:信息分发 → 独立研判 → 交叉质证 → 综合裁决
"""
import json
import logging
import time
from typing import Optional
from .law_agent import LawAgent
from .tech_agent import TechAgent
from .finance_agent import FinanceAgent
from .judge_agent import JudgeAgent
logger = logging.getLogger(__name__)
class DebateEngine:
"""多智能体辩论编排器"""
def __init__(self):
self.law_agent = LawAgent()
self.tech_agent = TechAgent()
self.finance_agent = FinanceAgent()
self.judge_agent = JudgeAgent()
self.debate_log = []
def run_debate(self, company_data: dict, callback=None) -> dict:
"""
执行完整的多智能体辩论流程
Args:
company_data: 企业数据字典
callback: 进度回调函数 callback(step, message, result)
"""
self.debate_log = []
company_name = company_data.get("short_name", company_data.get("company_name", "未知"))
start_time = time.time()
self._log(f"🏁 启动对 [{company_name}] 的多智能体交叉验证辩论")
# ==============================
# Phase 1: 独立研判
# ==============================
self._log("=" * 50)
self._log("📋 Phase 1: 各节点独立研判")
self._log("=" * 50)
# 法务节点
self._log("👩‍⚖️ 法务风控节点开始评估...")
if callback:
callback("law_start", "法务风控节点开始评估...", None)
law_result = self.law_agent.evaluate(company_data)
self._log(f"👩‍⚖️ 法务节点完成: 综合法务风险 {law_result.get('overall_law_risk', {}).get('score', '?')}")
if callback:
callback("law_done", "法务风控节点评估完成", law_result)
# 技术节点
self._log("👨‍🔬 技术风控节点开始评估...")
if callback:
callback("tech_start", "技术风控节点开始评估...", None)
tech_result = self.tech_agent.evaluate(company_data)
self._log(f"👨‍🔬 技术节点完成: 综合技术风险 {tech_result.get('overall_tech_risk', {}).get('score', '?')}")
if callback:
callback("tech_done", "技术风控节点评估完成", tech_result)
# 财务节点
self._log("👔 财务风控节点开始评估...")
if callback:
callback("fin_start", "财务风控节点开始评估...", None)
finance_result = self.finance_agent.evaluate(company_data)
self._log(f"👔 财务节点完成: 综合财务风险 {finance_result.get('overall_fin_risk', {}).get('score', '?')}")
if callback:
callback("fin_done", "财务风控节点评估完成", finance_result)
# ==============================
# Phase 2: 交叉质证(记录冲突点)
# ==============================
self._log("=" * 50)
self._log("🔄 Phase 2: 交叉质证")
self._log("=" * 50)
conflicts = self._identify_conflicts(law_result, tech_result, finance_result)
for conflict in conflicts:
self._log(f"⚠️ 冲突: {conflict}")
if not conflicts:
self._log("✅ 各节点意见一致,无冲突")
if callback:
callback("cross_validation", "交叉质证完成", {"conflicts": conflicts})
# ==============================
# Phase 3: 综合裁决
# ==============================
self._log("=" * 50)
self._log("⚖️ Phase 3: 综合裁决")
self._log("=" * 50)
if callback:
callback("judge_start", "综合裁决节点开始...", None)
judge_result = self.judge_agent.evaluate(
company_data, law_result, tech_result, finance_result
)
self._log(f"⚖️ 综合评分: {judge_result.get('comprehensive_score', '?')}")
self._log(f"⚖️ 核保建议: 【{judge_result.get('underwriting_decision', '?')}")
if callback:
callback("judge_done", "综合裁决完成", judge_result)
elapsed = time.time() - start_time
self._log(f"🏁 辩论完成,耗时 {elapsed:.1f}")
return {
"company": company_name,
"law_result": law_result,
"tech_result": tech_result,
"finance_result": finance_result,
"conflicts": conflicts,
"judge_result": judge_result,
"debate_log": self.debate_log,
"elapsed_seconds": round(elapsed, 1),
}
def _identify_conflicts(self, law_result: dict, tech_result: dict, finance_result: dict) -> list:
"""识别各节点之间的判定冲突"""
conflicts = []
# 检查法务和技术的冲突:例如法务认为合规但技术认为路线有风险
law_overall = law_result.get("overall_law_risk", {}).get("score", 50)
tech_overall = tech_result.get("overall_tech_risk", {}).get("score", 50)
fin_overall = finance_result.get("overall_fin_risk", {}).get("score", 50)
# 大幅分歧(差异超过30分)
if abs(law_overall - tech_overall) > 30:
if law_overall > tech_overall:
conflicts.append(
f"法务节点({law_overall}分)与技术节点({tech_overall}分)存在较大分歧: "
f"法务认为合规风险较高,但技术面评估相对乐观"
)
else:
conflicts.append(
f"技术节点({tech_overall}分)与法务节点({law_overall}分)存在较大分歧: "
f"技术风险较高,但法务合规状态相对可控"
)
if abs(tech_overall - fin_overall) > 30:
conflicts.append(
f"技术节点({tech_overall}分)与财务节点({fin_overall}分)存在分歧: "
f"需审查技术投入与财务表现的匹配度"
)
# 特定维度冲突:技术认为研发投入大=好事,财务可能认为是资本化操纵
tech_rd_view = tech_result.get("tech_iteration_pressure", {}).get("score", 50)
fin_rd_view = finance_result.get("rd_capitalization_risk", {}).get("score", 50)
if tech_rd_view < 40 and fin_rd_view > 60:
conflicts.append(
"技术节点认为研发投入合理,但财务节点发现研发资本化率异常,"
"存在通过资本化手段美化利润的嫌疑"
)
return conflicts
def _log(self, message: str):
"""记录辩论日志"""
entry = {"timestamp": time.strftime("%H:%M:%S"), "message": message}
self.debate_log.append(entry)
logger.info(message)
def run_debate(stock_code: str) -> dict:
"""便捷接口:通过股票代码直接运行辩论"""
from collectors.financial_collector import get_company_by_code
company_data = get_company_by_code(stock_code)
if not company_data:
return {"error": f"未找到股票代码 {stock_code} 的企业数据"}
engine = DebateEngine()
return engine.run_debate(company_data)
+174
View File
@@ -0,0 +1,174 @@
# -*- coding: utf-8 -*-
"""
财务风控节点
审查维度:研发资本化操纵、客户/供应商集中度、应收账款质量、现金流
"""
import json
from .base_agent import BaseAgent
FIN_SYSTEM_PROMPT = """你是一名精通科创板审计规则的注册会计师(CPA),同时是金融风控专家。
你的任务是基于提供的企业财务数据,从财务角度穿透审查以下风险:
1. 研发资本化操纵风险:研发资本化率是否异常,是否存在美化利润嫌疑
2. 客户/供应商集中风险:前五大客户/供应商占比是否过高
3. 应收账款质量:应收账款周转率是否异常,是否存在坏账风险
4. 现金流健康度:经营现金流是否能覆盖运营需求
评估标准参考:
- 科创板企业研发资本化率超过30%需重点关注
- 前五大客户占比超过50%存在集中风险
- 应收账款周转率低于4次/年需关注回款能力
- 经营现金流/营收比低于0.5需关注持续经营能力
请输出JSON格式:
{
"agent": "财务风控节点",
"rd_capitalization_risk": {"score": 0-100, "level": "高/中/低", "detail": "..."},
"concentration_risk": {"score": 0-100, "level": "高/中/低", "detail": "..."},
"receivable_risk": {"score": 0-100, "level": "高/中/低", "detail": "..."},
"cashflow_risk": {"score": 0-100, "level": "高/中/低", "detail": "..."},
"overall_fin_risk": {"score": 0-100, "level": "高/中/低"},
"key_findings": ["..."],
"recommendations": ["..."]
}"""
class FinanceAgent(BaseAgent):
"""财务风控节点"""
def __init__(self):
super().__init__(
name="财务风控节点",
system_prompt=FIN_SYSTEM_PROMPT,
role_icon="👔",
)
def evaluate(self, company_data: dict) -> dict:
"""执行财务风险评估"""
prompt = self._build_prompt(company_data)
result = self.infer_json(prompt)
if result.get("parse_error"):
result = self._rule_based_evaluation(company_data)
result["agent"] = "财务风控节点"
result["icon"] = self.role_icon
return result
def _build_prompt(self, company_data: dict) -> str:
financials = company_data.get("financials", {})
return f"""请对以下科创企业进行财务风险穿透审查:
企业名称:{company_data.get('short_name', '未知')}
行业:{company_data.get('industry', '未知')}
财务核心指标:
- 营业收入: {financials.get('revenue_2024', 0):,.0f}
- 净利润: {financials.get('net_profit_2024', 0):,.0f}
- 研发费用: {financials.get('rd_expense_2024', 0):,.0f}
- 研发资本化率: {financials.get('rd_capitalization_rate', 0):.1%}
- 研发/营收比: {financials.get('rd_revenue_ratio', 0):.1%}
- 前五大客户占比: {financials.get('top5_customer_ratio', 0):.1%}
- 前五大供应商占比: {financials.get('top5_supplier_ratio', 0):.1%}
- 应收账款周转率: {financials.get('receivable_turnover', 0):.1f} 次/年
- 经营现金流比率: {financials.get('cash_flow_ratio', 0):.2f}
请输出严格的JSON评估结果。"""
def _rule_based_evaluation(self, company_data: dict) -> dict:
"""基于规则的财务风险评估"""
fin = company_data.get("financials", {})
# 1. 研发资本化操纵风险
cap_rate = fin.get("rd_capitalization_rate", 0)
if cap_rate >= 0.4:
rd_score = 90
rd_detail = f"研发资本化率高达{cap_rate:.0%},严重怀疑美化利润"
elif cap_rate >= 0.3:
rd_score = 70
rd_detail = f"研发资本化率{cap_rate:.0%},超过行业警戒线(30%),需重点审查"
elif cap_rate >= 0.15:
rd_score = 45
rd_detail = f"研发资本化率{cap_rate:.0%},处于中等水平,建议关注趋势"
elif cap_rate > 0:
rd_score = 25
rd_detail = f"研发资本化率{cap_rate:.0%},处于合理范围"
else:
rd_score = 10
rd_detail = "研发费用全部费用化处理,财务政策审慎"
# 2. 集中度风险
customer_ratio = fin.get("top5_customer_ratio", 0)
supplier_ratio = fin.get("top5_supplier_ratio", 0)
max_concentration = max(customer_ratio, supplier_ratio)
if max_concentration >= 0.8:
conc_score = 90
conc_detail = f"前五大客户占比{customer_ratio:.0%},供应商占比{supplier_ratio:.0%},集中度极高"
elif max_concentration >= 0.6:
conc_score = 70
conc_detail = f"前五大客户占比{customer_ratio:.0%},供应商占比{supplier_ratio:.0%},集中度偏高"
elif max_concentration >= 0.4:
conc_score = 45
conc_detail = f"前五大客户占比{customer_ratio:.0%},供应商占比{supplier_ratio:.0%},中等集中度"
else:
conc_score = 20
conc_detail = f"客户和供应商分布较为分散"
# 3. 应收账款风险
turnover = fin.get("receivable_turnover", 8)
if turnover < 3:
recv_score = 80
recv_detail = f"应收账款周转率仅{turnover:.1f}次/年,回款能力极差"
elif turnover < 5:
recv_score = 55
recv_detail = f"应收账款周转率{turnover:.1f}次/年,回款速度偏慢"
elif turnover < 8:
recv_score = 30
recv_detail = f"应收账款周转率{turnover:.1f}次/年,回款能力尚可"
else:
recv_score = 15
recv_detail = f"应收账款周转率{turnover:.1f}次/年,回款能力良好"
# 4. 现金流风险
cf_ratio = fin.get("cash_flow_ratio", 1.0)
if cf_ratio < 0.5:
cf_score = 80
cf_detail = f"经营现金流比率仅{cf_ratio:.2f},存在持续经营风险"
elif cf_ratio < 0.8:
cf_score = 55
cf_detail = f"经营现金流比率{cf_ratio:.2f},现金流偏紧"
elif cf_ratio < 1.2:
cf_score = 30
cf_detail = f"经营现金流比率{cf_ratio:.2f},基本健康"
else:
cf_score = 15
cf_detail = f"经营现金流比率{cf_ratio:.2f},现金流充裕"
overall = int(rd_score * 0.30 + conc_score * 0.30 +
recv_score * 0.20 + cf_score * 0.20)
findings = [rd_detail, conc_detail]
if recv_score >= 50:
findings.append(recv_detail)
if cf_score >= 50:
findings.append(cf_detail)
return {
"rd_capitalization_risk": {"score": rd_score, "level": self._level(rd_score), "detail": rd_detail},
"concentration_risk": {"score": conc_score, "level": self._level(conc_score), "detail": conc_detail},
"receivable_risk": {"score": recv_score, "level": self._level(recv_score), "detail": recv_detail},
"cashflow_risk": {"score": cf_score, "level": self._level(cf_score), "detail": cf_detail},
"overall_fin_risk": {"score": overall, "level": self._level(overall)},
"key_findings": findings,
"recommendations": ["关注研发资本化率变化趋势", "降低客户集中度风险"],
}
@staticmethod
def _level(score: int) -> str:
if score >= 70:
return ""
elif score >= 40:
return ""
return ""
+176
View File
@@ -0,0 +1,176 @@
# -*- coding: utf-8 -*-
"""
综合裁决节点
汇总法务/技术/财务三方意见,消解冲突,输出最终综合评级
"""
import json
from .base_agent import BaseAgent
JUDGE_SYSTEM_PROMPT = """你是一名资深的风险管理委员会主席,负责汇总法务、技术、财务三方专家的研判意见。
你的任务是:
1. 审阅三方专家的评估报告
2. 识别各方意见的冲突点
3. 基于优先级原则消解冲突(合规风险 > 技术风险 > 财务风险)
4. 输出 0-100 的综合风险评分
5. 给出最终核保建议
核保决策标准:
- 综合风险 ≥ 80分:建议【拒绝承保】
- 60 ≤ 综合风险 < 80分:建议【附条件承保】(高免赔额/限额)
- 40 ≤ 综合风险 < 60分:建议【标准承保】(标准费率上浮)
- 综合风险 < 40分:建议【优先承保】(可享费率优惠)
请输出JSON格式:
{
"comprehensive_score": 0-100,
"risk_level": "极高/高/中/低",
"underwriting_decision": "拒绝承保/附条件承保/标准承保/优先承保",
"six_dimension_scores": {
"tech_disruption": 0-100,
"talent_loss": 0-100,
"algo_compliance": 0-100,
"geopolitical": 0-100,
"rd_capitalization": 0-100,
"concentration": 0-100
},
"conflict_resolution": "...",
"key_risks": ["..."],
"underwriting_conditions": ["..."],
"summary": "..."
}"""
class JudgeAgent(BaseAgent):
"""综合裁决节点"""
def __init__(self):
super().__init__(
name="综合裁决节点",
system_prompt=JUDGE_SYSTEM_PROMPT,
role_icon="⚖️",
)
def evaluate(self, company_data: dict, law_result: dict,
tech_result: dict, finance_result: dict) -> dict:
"""汇总三方意见,输出综合裁决"""
prompt = self._build_prompt(company_data, law_result, tech_result, finance_result)
result = self.infer_json(prompt)
if result.get("parse_error"):
result = self._rule_based_evaluation(company_data, law_result, tech_result, finance_result)
result["agent"] = "综合裁决节点"
result["icon"] = self.role_icon
return result
def _build_prompt(self, company_data: dict, law_result: dict,
tech_result: dict, finance_result: dict) -> str:
return f"""请对以下科创企业的三方评估结果进行综合裁决:
企业名称:{company_data.get('short_name', '未知')}
行业:{company_data.get('industry', '未知')}
=== 👩‍⚖️ 法务风控节点评估 ===
{json.dumps(law_result, ensure_ascii=False, indent=2)}
=== 👨‍🔬 技术风控节点评估 ===
{json.dumps(tech_result, ensure_ascii=False, indent=2)}
=== 👔 财务风控节点评估 ===
{json.dumps(finance_result, ensure_ascii=False, indent=2)}
请消解可能存在的判定冲突,输出综合裁决JSON。"""
def _rule_based_evaluation(self, company_data: dict, law_result: dict,
tech_result: dict, finance_result: dict) -> dict:
"""规则引擎综合裁决"""
# 提取各维度得分
def safe_score(result: dict, key: str) -> int:
item = result.get(key, {})
if isinstance(item, dict):
return item.get("score", 50)
return 50
# 六维评分
scores = {
"tech_disruption": safe_score(tech_result, "tech_disruption_risk"),
"talent_loss": safe_score(tech_result, "talent_loss_risk"),
"algo_compliance": safe_score(law_result, "algo_compliance_risk"),
"geopolitical": safe_score(law_result, "geopolitical_risk"),
"rd_capitalization": safe_score(finance_result, "rd_capitalization_risk"),
"concentration": safe_score(finance_result, "concentration_risk"),
}
# 加权综合得分
weights = {
"tech_disruption": 0.20,
"talent_loss": 0.15,
"algo_compliance": 0.15,
"geopolitical": 0.20,
"rd_capitalization": 0.15,
"concentration": 0.15,
}
comprehensive_score = int(
sum(scores[k] * weights[k] for k in scores)
)
# 裁决
if comprehensive_score >= 80:
decision = "拒绝承保"
risk_level = "极高"
elif comprehensive_score >= 60:
decision = "附条件承保"
risk_level = ""
elif comprehensive_score >= 40:
decision = "标准承保"
risk_level = ""
else:
decision = "优先承保"
risk_level = ""
# 收集关键风险
key_risks = []
for dim, score in sorted(scores.items(), key=lambda x: x[1], reverse=True):
if score >= 60:
dim_names = {
"tech_disruption": "技术路线颠覆",
"talent_loss": "核心人员流失",
"algo_compliance": "算法/数据合规",
"geopolitical": "地缘政治/出口管制",
"rd_capitalization": "研发资本化操纵",
"concentration": "客户/供应商集中",
}
key_risks.append(f"{dim_names.get(dim, dim)}风险({score}分)")
# 核保条件
conditions = []
if scores["geopolitical"] >= 70:
conditions.append("要求提供出口管制合规声明及供应链替代方案")
if scores["rd_capitalization"] >= 60:
conditions.append("要求额外提供研发资本化会计政策说明及审计意见")
if scores["concentration"] >= 60:
conditions.append("要求提供客户分散化计划或前五大客户信用报告")
if scores["talent_loss"] >= 60:
conditions.append("要求核心技术人员签署竞业协议且公司有留任激励计划")
company_name = company_data.get("short_name", "该企业")
summary = (
f"{company_name}综合风险评分{comprehensive_score}分(风险等级:{risk_level})。"
f"核保建议:【{decision}】。"
f"主要风险集中在{''.join(key_risks[:3]) if key_risks else '无突出风险'}"
)
return {
"comprehensive_score": comprehensive_score,
"risk_level": risk_level,
"underwriting_decision": decision,
"six_dimension_scores": scores,
"conflict_resolution": "基于优先级原则(合规>技术>财务)进行加权裁决",
"key_risks": key_risks,
"underwriting_conditions": conditions,
"summary": summary,
}
+145
View File
@@ -0,0 +1,145 @@
# -*- coding: utf-8 -*-
"""
法务风控节点
审查维度:算法备案状态、实体清单命中、数据出境风险、知识产权诉讼
"""
import json
from .base_agent import BaseAgent
LAW_SYSTEM_PROMPT = """你是一名资深法务风控专家,精通以下法律法规:
- 《生成式人工智能服务管理暂行办法》
- 《互联网信息服务算法推荐管理规定》
- 《数据安全法》《个人信息保护法》
- 《出口管制法》及美国 BIS 实体清单相关规则
- 《科创板上市规则》中的合规要求
你的任务是基于提供的企业数据,从法律合规角度评估以下风险:
1. 算法备案合规风险:企业是否涉及AI业务但未完成算法备案
2. 地缘政治与出口管制风险:企业或其供应链是否受到制裁
3. 数据合规风险:是否存在数据出境、数据安全方面的隐患
4. 知识产权诉讼风险:是否面临重大IP纠纷
请以严谨的法律视角进行评估,输出JSON格式:
{
"agent": "法务风控节点",
"algo_compliance_risk": {"score": 0-100, "level": "高/中/低", "detail": "..."},
"geopolitical_risk": {"score": 0-100, "level": "高/中/低", "detail": "..."},
"data_compliance_risk": {"score": 0-100, "level": "高/中/低", "detail": "..."},
"ip_litigation_risk": {"score": 0-100, "level": "高/中/低", "detail": "..."},
"overall_law_risk": {"score": 0-100, "level": "高/中/低"},
"key_findings": ["..."],
"recommendations": ["..."]
}"""
class LawAgent(BaseAgent):
"""法务风控节点"""
def __init__(self):
super().__init__(
name="法务风控节点",
system_prompt=LAW_SYSTEM_PROMPT,
role_icon="👩‍⚖️",
)
def evaluate(self, company_data: dict) -> dict:
"""执行法务风险评估"""
prompt = self._build_prompt(company_data)
result = self.infer_json(prompt)
# 如果 JSON 解析失败,使用规则引擎
if result.get("parse_error"):
result = self._rule_based_evaluation(company_data)
result["agent"] = "法务风控节点"
result["icon"] = self.role_icon
return result
def _build_prompt(self, company_data: dict) -> str:
"""构建评估提示词"""
return f"""请对以下科创企业进行法务风险评估:
企业名称:{company_data.get('short_name', company_data.get('company_name', '未知'))}
行业:{company_data.get('industry', '未知')}
领域:{company_data.get('sector', '未知')}
合规状态:
- 算法备案:{json.dumps(company_data.get('compliance', {}), ensure_ascii=False)}
供应链信息:
- 关键供应商:{json.dumps(company_data.get('supply_chain', {}).get('key_suppliers', []), ensure_ascii=False)}
- 供应商集中度风险:{company_data.get('supply_chain', {}).get('supplier_concentration_risk', '未知')}
技术路线:
{json.dumps(company_data.get('tech_route', {}), ensure_ascii=False)}
请输出严格的JSON评估结果。"""
def fallback_inference(self, prompt: str) -> str:
"""规则引擎降级"""
return json.dumps(self._rule_based_evaluation({}), ensure_ascii=False)
def _rule_based_evaluation(self, company_data: dict) -> dict:
"""基于规则的法务风险评估"""
compliance = company_data.get("compliance", {})
supply_chain = company_data.get("supply_chain", {})
sector = company_data.get("sector", "")
# 算法备案风险
algo_status = compliance.get("algo_filing_status", "")
algo_score = 20
algo_detail = "合规状态正常"
if sector in ["AI", "软件", "互联网"] and algo_status == "不适用":
algo_score = 60
algo_detail = "涉及AI业务但标注为不适用,建议核实"
elif "" in algo_status or not algo_status:
algo_score = 80
algo_detail = "未查到算法备案记录,存在合规风险"
elif "已备案" in algo_status:
algo_score = 10
algo_detail = "已完成算法备案"
# 地缘政治风险
entity_status = compliance.get("entity_list_status", "")
geo_score = 15
geo_detail = "未受出口管制影响"
if "被列入" in entity_status:
geo_score = 95
geo_detail = f"已被列入实体清单: {compliance.get('sanctions_detail', '')}"
elif supply_chain.get("supplier_concentration_risk") == "极高":
geo_score = 70
geo_detail = "核心供应链高度依赖海外,存在间接制裁风险"
# 数据合规风险
data_risk = compliance.get("data_export_risk", "")
data_score = {"": 75, "": 45, "": 15}.get(data_risk, 20)
data_detail = f"数据出境风险等级: {data_risk}"
# 知识产权风险
ip_score = 25
ip_detail = "未发现重大IP纠纷"
# 综合法务风险
overall_score = int(
algo_score * 0.25 + geo_score * 0.35 +
data_score * 0.25 + ip_score * 0.15
)
return {
"algo_compliance_risk": {"score": algo_score, "level": self._level(algo_score), "detail": algo_detail},
"geopolitical_risk": {"score": geo_score, "level": self._level(geo_score), "detail": geo_detail},
"data_compliance_risk": {"score": data_score, "level": self._level(data_score), "detail": data_detail},
"ip_litigation_risk": {"score": ip_score, "level": self._level(ip_score), "detail": ip_detail},
"overall_law_risk": {"score": overall_score, "level": self._level(overall_score)},
"key_findings": [algo_detail, geo_detail, data_detail],
"recommendations": ["建议定期审查合规状态", "关注实体清单更新动态"],
}
@staticmethod
def _level(score: int) -> str:
if score >= 70:
return ""
elif score >= 40:
return ""
return ""
+147
View File
@@ -0,0 +1,147 @@
# -*- coding: utf-8 -*-
"""
技术风控节点
审查维度:技术路线竞争态势、核心人员稳定性、专利布局、技术替代风险
"""
import json
from .base_agent import BaseAgent
TECH_SYSTEM_PROMPT = """你是一名资深科技行业分析师和技术风控专家。
你精通半导体、人工智能、新能源、生物医疗等前沿科技领域的技术演进趋势。
你的任务是基于提供的企业数据,从技术角度评估以下风险:
1. 技术路线颠覆风险:企业押注的技术路线是否面临被替代的风险
2. 核心人员流失风险:关键技术人员的稳定性和不可替代性
3. 专利/技术壁垒:技术护城河的深度和可持续性
4. 技术迭代压力:行业技术迭代速度对企业的冲击
请以技术专家的视角进行深度评估,输出JSON格式:
{
"agent": "技术风控节点",
"tech_disruption_risk": {"score": 0-100, "level": "高/中/低", "detail": "..."},
"talent_loss_risk": {"score": 0-100, "level": "高/中/低", "detail": "..."},
"patent_moat": {"score": 0-100, "level": "强/中/弱", "detail": "..."},
"tech_iteration_pressure": {"score": 0-100, "level": "高/中/低", "detail": "..."},
"overall_tech_risk": {"score": 0-100, "level": "高/中/低"},
"key_findings": ["..."],
"recommendations": ["..."]
}"""
class TechAgent(BaseAgent):
"""技术风控节点"""
def __init__(self):
super().__init__(
name="技术风控节点",
system_prompt=TECH_SYSTEM_PROMPT,
role_icon="👨‍🔬",
)
def evaluate(self, company_data: dict) -> dict:
"""执行技术风险评估"""
prompt = self._build_prompt(company_data)
result = self.infer_json(prompt)
if result.get("parse_error"):
result = self._rule_based_evaluation(company_data)
result["agent"] = "技术风控节点"
result["icon"] = self.role_icon
return result
def _build_prompt(self, company_data: dict) -> str:
return f"""请对以下科创企业进行技术风险评估:
企业名称:{company_data.get('short_name', '未知')}
行业:{company_data.get('industry', '未知')}
领域:{company_data.get('sector', '未知')}
企业描述:{company_data.get('description', '')}
技术路线信息:
{json.dumps(company_data.get('tech_route', {}), ensure_ascii=False, indent=2)}
核心技术人员:
{json.dumps(company_data.get('core_tech_personnel', []), ensure_ascii=False, indent=2)}
财务中的研发指标:
- 研发费用: {company_data.get('financials', {}).get('rd_expense_2024', 0)}
- 研发营收比: {company_data.get('financials', {}).get('rd_revenue_ratio', 0)}
请输出严格的JSON评估结果。"""
def _rule_based_evaluation(self, company_data: dict) -> dict:
"""基于规则的技术风险评估"""
tech_route = company_data.get("tech_route", {})
personnel = company_data.get("core_tech_personnel", [])
financials = company_data.get("financials", {})
# 技术路线颠覆风险
competing_techs = tech_route.get("competing_techs", [])
disruption_score = min(20 + len(competing_techs) * 15, 90)
tech_moat = tech_route.get("tech_moat", "")
if "差距" in tech_moat or "受制" in tech_moat:
disruption_score = min(disruption_score + 20, 95)
disruption_detail = f"面临 {len(competing_techs)} 条竞争技术路线: {', '.join(competing_techs[:3])}"
# 核心人员流失风险
talent_score = 20
talent_detail = "核心团队稳定"
departed = [p for p in personnel if "离职" in p.get("status", "")]
high_importance = [p for p in personnel if p.get("importance") == "极高"]
if departed:
talent_score = 80
talent_detail = f"已有核心人员离职: {', '.join(p['name'] for p in departed)}"
elif len(high_importance) == 1:
talent_score = 55
talent_detail = f"高度依赖单一核心人员: {high_importance[0]['name']}"
elif len(personnel) <= 2:
talent_score = 45
talent_detail = "核心技术团队规模偏小"
# 专利壁垒
patent_count = tech_route.get("patent_count", 0)
if patent_count > 5000:
patent_score = 20
patent_detail = f"专利数量充足({patent_count}件),技术壁垒较强"
elif patent_count > 1000:
patent_score = 35
patent_detail = f"专利数量中等({patent_count}件)"
else:
patent_score = 60
patent_detail = f"专利数量偏少({patent_count}件),技术壁垒偏弱"
# 技术迭代压力(基于研发投入比)
rd_ratio = financials.get("rd_revenue_ratio", 0)
if rd_ratio > 0.3:
iter_score = 65
iter_detail = f"研发营收比极高({rd_ratio:.1%}),说明行业技术迭代压力大"
elif rd_ratio > 0.15:
iter_score = 45
iter_detail = f"研发投入较高({rd_ratio:.1%}),需持续技术投入"
else:
iter_score = 25
iter_detail = f"研发投入适中({rd_ratio:.1%})"
overall = int(disruption_score * 0.35 + talent_score * 0.25 +
patent_score * 0.15 + iter_score * 0.25)
return {
"tech_disruption_risk": {"score": disruption_score, "level": self._level(disruption_score), "detail": disruption_detail},
"talent_loss_risk": {"score": talent_score, "level": self._level(talent_score), "detail": talent_detail},
"patent_moat": {"score": patent_score, "level": "" if patent_score >= 50 else ("" if patent_score >= 30 else ""), "detail": patent_detail},
"tech_iteration_pressure": {"score": iter_score, "level": self._level(iter_score), "detail": iter_detail},
"overall_tech_risk": {"score": overall, "level": self._level(overall)},
"key_findings": [disruption_detail, talent_detail, patent_detail],
"recommendations": ["关注竞争技术路线发展", "加强核心人员留任激励"],
}
@staticmethod
def _level(score: int) -> str:
if score >= 70:
return ""
elif score >= 40:
return ""
return ""