179 lines
7.1 KiB
Python
179 lines
7.1 KiB
Python
# -*- 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)
|