概述

本文将深入探讨基于大模型的合同风险点自动识别与分级体系。我们将从合同风险点的分类开始,逐步深入到风险识别算法、规则引擎、风险等级评定模型,以及风险关联分析与传导机制。每个环节都将配合实际代码示例,帮助读者快速掌握这一核心能力。

**前置依赖环境**:

  • JDK 17+
  • Spring Boot 3.2+
  • LangChain4j 1.0.0+
  • MySQL 8.0+ / H2(开发环境)
  • Apache POI 5.2+(Word文档解析)

**源码项目结构**:

contract-risk-analysis/
├── src/main/java/com/demo/risk/
│   ├── RiskClassifier.java           # 风险分类器
│   ├── RiskIdentifier.java           # 风险识别器
│   ├── RiskLevelEvaluator.java       # 风险等级评定器
│   ├── RiskRuleEngine.java           # 规则引擎
│   ├── RiskCorrelationAnalyzer.java  # 风险关联分析器
│   └── model/
│       ├── RiskPoint.java            # 风险点模型
│       ├── RiskCategory.java         # 风险类别枚举
│       ├── RiskLevel.java            # 风险等级枚举
│       └── RiskReport.java           # 风险报告模型
├── src/main/resources/
│   ├── risk-rules/
│   │   ├── legal-risk-rules.json     # 法律风险规则
│   │   ├── financial-risk-rules.json # 财务风险规则
│   │   └── operational-risk-rules.json # 运营风险规则
│   └── prompts/
│       └── risk-analysis-prompt.txt  # 风险分析Prompt
└── pom.xml

---

第一部分:合同风险点分类体系

1.1 风险分类总体架构

合同风险点分类是整个风险管理体系的基础。根据多年的行业实践,我们将合同风险划分为五大类别:

1.2 风险类别枚举定义

package com.demo.risk.model;

/**
 * 合同风险类别枚举
 * 定义了合同风险点的五大分类体系
 */
public enum RiskCategory {
    /**
     * 法律风险 - 涉及合同合法性、主客体资格、
     * 知识产权、争议解决机制等方面的风险
     */
    LEGAL("legal", "法律风险", "Legal Risk", RiskSeverity.HIGH),

    /**
     * 财务风险 - 涉及付款条件、违约金计算、
     * 汇率波动、税务责任等财务相关风险
     */
    FINANCIAL("financial", "财务风险", "Financial Risk", RiskSeverity.HIGH),

    /**
     * 运营风险 - 涉及合同履约能力、终止条件、
     * 保密义务、竞业限制等运营相关风险
     */
    OPERATIONAL("operational", "运营风险", "Operational Risk", RiskSeverity.MEDIUM),

    /**
     * 合规校验风险 - 涉及监管要求、数据安全、
     * 隐私保护、行业标准等合规相关风险
     */
    COMPLIANCE("compliance", "合规校验风险", "Compliance Risk", RiskSeverity.HIGH),

    /**
     * 战略风险 - 涉及商业逻辑、市场变化、
     * 合作方依赖度、长期影响等战略相关风险
     */
    STRATEGIC("strategic", "战略风险", "Strategic Risk", RiskSeverity.MEDIUM);

    private final String code;
    private final String chineseName;
    private final String englishName;
    private final RiskSeverity defaultSeverity;

    RiskCategory(String code, String chineseName, String englishName, RiskSeverity defaultSeverity) {
        this.code = code;
        this.chineseName = chineseName;
        this.englishName = englishName;
        this.defaultSeverity = defaultSeverity;
    }

    // Getter methods
    public String getCode() { return code; }
    public String getChineseName() { return chineseName; }
    public String getEnglishName() { return englishName; }
    public RiskSeverity getDefaultSeverity() { return defaultSeverity; }

    public static RiskCategory fromCode(String code) {
        for (RiskCategory category : values()) {
            if (category.code.equalsIgnoreCase(code)) {
                return category;
            }
        }
        throw new IllegalArgumentException("Unknown risk category code: " + code);
    }
}

/**
 * 风险严重程度枚举
 */
enum RiskSeverity {
    HIGH("高", 3),
    MEDIUM("中", 2),
    LOW("低", 1);

    private final String label;
    private final int level;

    RiskSeverity(String label, int level) {
        this.label = label;
        this.level = level;
    }

    public String getLabel() { return label; }
    public int getLevel() { return level; }
}

1.3 法律风险详细分类

法律风险是合同审核中最核心的风险类型,它直接关系到合同的法律效力。

/**
 * 法律风险子类定义
 */
public enum LegalRiskType {
    // 主体资格风险
    SUBJECT_QUALIFICATION("主体资格风险", "合同主体不具备相应资质或授权"),
    SUBJECT_IDENTITY("主体身份风险", "主体身份虚假或代理权限不足"),

    // 条款合规风险
    ILLEGAL_CLAUSE("违法条款风险", "合同条款违反法律强制性规定"),
    INVALID_CLAUSE("无效条款风险", "条款符合无效合同的法定情形"),
    VOIDABLE_CLAUSE("可撤销条款风险", "条款存在欺诈、胁迫或重大误解"),

    // 知识产权风险
    IP_OWNERSHIP("知识产权归属风险", "知识产权归属约定不明确"),
    IP_INFRINGEMENT("知识产权侵权风险", "可能侵犯第三方知识产权"),
    LICENSE_SCOPE("许可范围风险", "知识产权许可范围约定不清"),

    // 争议解决风险
    DISPUTE_RESOLUTION("争议解决机制风险", "争议解决方式约定不明确"),
    JURISDICTION("管辖法院风险", "管辖法院约定不合理"),
    APPLICABLE_LAW("适用法律风险", "准据法选择存在冲突"),

    // 责任限制风险
    LIABILITY_LIMIT("责任限制风险", "责任免除条款过于宽泛"),
    INDEMNIFICATION("赔偿范围风险", "赔偿范围约定不明确");

    private final String typeName;
    private final String description;

    LegalRiskType(String typeName, String description) {
        this.typeName = typeName;
        this.description = description;
    }

    public String getTypeName() { return typeName; }
    public String getDescription() { return description; }
}

1.4 财务风险详细分类

/**
 * 财务风险子类定义
 */
public enum FinancialRiskType {
    // 付款条件风险
    PAYMENT_TERM("付款条件风险", "付款时间、条件约定不明确"),
    PAYMENT_METHOD("付款方式风险", "付款方式存在安全隐患"),
    PAYMENT_CURRENCY("付款币种风险", "汇率波动可能造成损失"),

    // 违约金风险
    PENALTY_CALCULATION("违约金计算风险", "违约金计算方式不明确"),
    PENALTY_CAP("违约金上限风险", "违约金上限约定过高或过低"),
    LIQUIDATED_DAMAGES("定金罚则风险", "定金与违约金并存时的处理"),

    // 税务风险
    TAX_RESPONSIBILITY("税务责任风险", "税务责任约定不明确"),
    TAX_RATE_CHANGE("税率变动风险", "税率变化对合同履行的影响"),
    TAX_INVOICE("发票风险", "发票开具时间和类型约定"),

    // 成本风险
    COST_OVERRUN("成本超支风险", "成本控制条款缺失"),
    PRICE_ADJUSTMENT("价格调整风险", "价格调整机制不完善"),

    // 结算风险
    SETTLEMENT_DISPUTE("结算争议风险", "结算标准存在分歧"),
    EARLY_TERMINATION_FEE("提前终止费用风险", "提前终止时的费用计算");

    private final String typeName;
    private final String description;

    FinancialRiskType(String typeName, String description) {
        this.typeName = typeName;
        this.description = description;
    }

    public String getTypeName() { return typeName; }
    public String getDescription() { return description; }
}

---

第二部分:风险识别算法与规则引擎

2.1 风险识别算法概述

风险识别是整个风险管理体系的核心环节。我们采用多层风险识别架构:

┌─────────────────────────────────────────────────────┐
│                  合同文档输入                         │
└───────────────────────┬─────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────┐
│              第一层:基于规则的识别                    │
│  ┌─────────────────────────────────────────────┐   │
│  │  • 关键词匹配                                 │   │
│  │  • 正则表达式模式                             │   │
│  │  • 条款结构分析                               │   │
│  │  • 阈值判断                                   │   │
│  └─────────────────────────────────────────────┘   │
└───────────────────────┬─────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────┐
│              第二层:基于NLP的识别                    │
│  ┌─────────────────────────────────────────────┐   │
│  │  • 命名实体识别(NER)                        │   │
│  │  • 情感分析                                  │   │
│  │  • 语义相似度计算                            │   │
│  │  • 意图识别                                  │   │
│  └─────────────────────────────────────────────┘   │
└───────────────────────┬─────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────┐
│              第三层:基于大模型的识别                  │
│  ┌─────────────────────────────────────────────┐   │
│  │  • 上下文理解                                │   │
│  │  • 隐含风险推断                              │   │
│  │  • 综合风险评估                              │   │
│  │  • 风险关联分析                              │   │
│  └─────────────────────────────────────────────┘   │
└───────────────────────┬─────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────┐
│                 风险点列表输出                       │
└─────────────────────────────────────────────────────┘

2.2 风险识别器核心实现

package com.demo.risk;

import com.demo.risk.model.*;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

/**
 * 合同风险识别器
 * 实现多层风险识别算法
 */
@Component
public class RiskIdentifier {

    // 风险识别规则注册表
    private final Map<RiskCategory, List<RiskRule>> ruleRegistry = new HashMap<>();

    // 关键词模式库
    private static final Map<RiskCategory, List<Pattern>> KEYWORD_PATTERNS = new HashMap<>();

    static {
        // 法律风险关键词模式
        KEYWORD_PATTERNS.put(RiskCategory.LEGAL, Arrays.asList(
            Pattern.compile("无效|无效合同|合同无效"),
            Pattern.compile("违法|违反法律|强制性规定"),
            Pattern.compile("欺诈|胁迫|重大误解"),
            Pattern.compile("未经授权|无权代理|超越权限"),
            Pattern.compile("知识产权|专利|商标|著作权"),
            Pattern.compile("争议解决|仲裁|诉讼|管辖")
        ));

        // 财务风险关键词模式
        KEYWORD_PATTERNS.put(RiskCategory.FINANCIAL, Arrays.asList(
            Pattern.compile("违约金|罚金|滞纳金"),
            Pattern.compile("付款|支付|结算"),
            Pattern.compile("汇率|外汇|兑换"),
            Pattern.compile("税务|税金|发票"),
            Pattern.compile("定金|保证金|押金"),
            Pattern.compile("价格调整|浮动|涨价|降价")
        ));

        // 运营风险关键词模式
        KEYWORD_PATTERNS.put(RiskCategory.OPERATIONAL, Arrays.asList(
            Pattern.compile("终止|解除|解约"),
            Pattern.compile("保密|机密|秘密信息"),
            Pattern.compile("竞业|竞争|同业竞争"),
            Pattern.compile("履约|履行|执行"),
            Pattern.compile("不可抗力|免责"),
            Pattern.compile("转让|转移|分包")
        ));
    }

    /**
     * 识别合同文本中的风险点
     * @param contractText 合同文本内容
     * @param contractType 合同类型
     * @return 识别到的风险点列表
     */
    public List<RiskPoint> identifyRisks(String contractText, String contractType) {
        List<RiskPoint> riskPoints = new ArrayList<>();

        // 第一层:基于规则的识别
        riskPoints.addAll(identifyByRules(contractText, contractType));

        // 第二层:基于关键词的识别
        riskPoints.addAll(identifyByKeywords(contractText));

        // 第三层:基于上下文的识别(去重合并)
        return mergeAndDeduplicate(riskPoints);
    }

    /**
     * 基于规则的识别
     */
    private List<RiskPoint> identifyByRules(String contractText, String contractType) {
        List<RiskPoint> riskPoints = new ArrayList<>();

        // 获取对应合同类型的规则
        List<RiskRule> rules = getRulesForContractType(contractType);

        for (RiskRule rule : rules) {
            if (rule.matches(contractText)) {
                RiskPoint point = RiskPoint.builder()
                    .id(UUID.randomUUID().toString())
                    .category(rule.getCategory())
                    .riskType(rule.getRiskType())
                    .description(rule.getDescription())
                    .evidence(rule.getMatchedEvidence())
                    .confidence(rule.getConfidence())
                    .detectedAt(java.time.LocalDateTime.now())
                    .detectionMethod("RULE_BASED")
                    .build();
                riskPoints.add(point);
            }
        }

        return riskPoints;
    }

    /**
     * 基于关键词的识别
     */
    private List<RiskPoint> identifyByKeywords(String contractText) {
        List<RiskPoint> riskPoints = new ArrayList<>();

        for (Map.Entry<RiskCategory, List<Pattern>> entry : KEYWORD_PATTERNS.entrySet()) {
            RiskCategory category = entry.getKey();
            List<Pattern> patterns = entry.getValue();

            for (Pattern pattern : patterns) {
                Matcher matcher = pattern.matcher(contractText);
                while (matcher.find()) {
                    RiskPoint point = RiskPoint.builder()
                        .id(UUID.randomUUID().toString())
                        .category(category)
                        .riskType(extractRiskType(pattern.pattern(), category))
                        .description("通过关键词匹配识别: " + matcher.group())
                        .evidence(matcher.group())
                        .confidence(0.75) // 关键词匹配置信度
                        .detectedAt(java.time.LocalDateTime.now())
                        .detectionMethod("KEYWORD_BASED")
                        .build();
                    riskPoints.add(point);
                }
            }
        }

        return riskPoints;
    }

    /**
     * 风险点去重与合并
     */
    private List<RiskPoint> mergeAndDeduplicate(List<RiskPoint> riskPoints) {
        // 按类别和描述进行去重
        Map<String, RiskPoint> uniqueRisks = new LinkedHashMap<>();

        for (RiskPoint point : riskPoints) {
            String key = point.getCategory() + ":" + point.getRiskType();
            if (!uniqueRisks.containsKey(key)) {
                uniqueRisks.put(key, point);
            } else {
                // 保留置信度更高的
                RiskPoint existing = uniqueRisks.get(key);
                if (point.getConfidence() > existing.getConfidence()) {
                    uniqueRisks.put(key, point);
                }
            }
        }

        return new ArrayList<>(uniqueRisks.values());
    }

    /**
     * 获取合同类型对应的规则
     */
    private List<RiskRule> getRulesForContractType(String contractType) {
        // 实际实现中从规则引擎获取
        return ruleRegistry.getOrDefault(
            parseCategory(contractType),
            Collections.emptyList()
        );
    }

    /**
     * 解析合同类型为风险类别
     */
    private RiskCategory parseCategory(String contractType) {
        if (contractType == null) return RiskCategory.LEGAL;

        String type = contractType.toLowerCase();
        if (type.contains("采购") || type.contains("销售") || type.contains("供应")) {
            return RiskCategory.FINANCIAL;
        } else if (type.contains("劳动") || type.contains("雇佣")) {
            return RiskCategory.OPERATIONAL;
        } else if (type.contains("技术") || type.contains("开发")) {
            return RiskCategory.COMPLIANCE;
        }
        return RiskCategory.LEGAL;
    }

    /**
     * 从关键词提取风险类型
     */
    private String extractRiskType(String pattern, RiskCategory category) {
        if (pattern.contains("无效")) return "ILLEGAL_CLAUSE";
        if (pattern.contains("违法")) return "ILLEGAL_CLAUSE";
        if (pattern.contains("欺诈")) return "VOIDABLE_CLAUSE";
        if (pattern.contains("终止")) return "TERMINATION_RISK";
        if (pattern.contains("保密")) return "CONFIDENTIALITY_RISK";
        if (pattern.contains("违约金")) return "PENALTY_RISK";
        if (pattern.contains("付款")) return "PAYMENT_TERM_RISK";
        return category.getCode().toUpperCase() + "_GENERAL";
    }

    /**
     * 注册风险识别规则
     */
    public void registerRule(RiskCategory category, RiskRule rule) {
        ruleRegistry.computeIfAbsent(category, k -> new ArrayList<>()).add(rule);
    }
}

2.3 规则引擎实现

package com.demo.risk;

/**
 * 风险规则接口
 */
interface RiskRule {
    RiskCategory getCategory();
    String getRiskType();
    String getDescription();
    boolean matches(String contractText);
    String getMatchedEvidence();
    double getConfidence();
}

/**
 * 基于正则表达式的风险规则
 */
public static class RegexRiskRule implements RiskRule {
    private final RiskCategory category;
    private final String riskType;
    private final String description;
    private final Pattern pattern;
    private String lastMatchedEvidence;

    public RegexRiskRule(RiskCategory category, String riskType,
                         String description, String regex) {
        this.category = category;
        this.riskType = riskType;
        this.description = description;
        this.pattern = Pattern.compile(regex);
    }

    @Override
    public RiskCategory getCategory() { return category; }

    @Override
    public String getRiskType() { return riskType; }

    @Override
    public String getDescription() { return description; }

    @Override
    public boolean matches(String contractText) {
        Matcher matcher = pattern.matcher(contractText);
        if (matcher.find()) {
            lastMatchedEvidence = matcher.group();
            return true;
        }
        return false;
    }

    @Override
    public String getMatchedEvidence() {
        return lastMatchedEvidence != null ? lastMatchedEvidence : "";
    }

    @Override
    public double getConfidence() {
        return 0.85; // 正则规则默认置信度
    }
}

/**
 * 基于条款位置的风险规则
 */
public static class PositionRiskRule implements RiskRule {
    private final RiskCategory category;
    private final String riskType;
    private final String description;
    private final String sectionName;
    private final Pattern absencePattern;

    public PositionRiskRule(RiskCategory category, String riskType,
                           String description, String sectionName,
                           String mustContainPattern) {
        this.category = category;
        this.riskType = riskType;
        this.description = description;
        this.sectionName = sectionName;
        this.absencePattern = Pattern.compile(mustContainPattern);
    }

    @Override
    public RiskCategory getCategory() { return category; }

    @Override
    public String getRiskType() { return riskType; }

    @Override
    public String getDescription() { return description; }

    @Override
    public boolean matches(String contractText) {
        // 查找特定章节
        Pattern sectionPattern = Pattern.compile(
            sectionName + "[^第条章]*?第.*?条", Pattern.DOTALL
        );
        Matcher sectionMatcher = sectionPattern.matcher(contractText);

        // 检查是否缺少必要条款
        while (sectionMatcher.find()) {
            String sectionContent = sectionMatcher.group();
            if (!absencePattern.matcher(sectionContent).find()) {
                // 找到章节但缺少必要内容
                return true;
            }
        }
        return false;
    }

    @Override
    public String getMatchedEvidence() {
        return "章节【" + sectionName + "】缺少必要条款";
    }

    @Override
    public double getConfidence() {
        return 0.80;
    }
}

2.4 风险规则配置示例

**法律风险规则配置 (legal-risk-rules.json)**:

{
  "version": "1.0",
  "category": "LEGAL",
  "rules": [
    {
      "id": "legal-001",
      "name": "无效合同风险",
      "description": "识别可能导致合同无效的条款",
      "type": "REGEX",
      "pattern": "(违反.*法律|强制性规定|损害.*利益|恶意串通)",
      "severity": "HIGH",
      "confidence": 0.90
    },
    {
      "id": "legal-002",
      "name": "知识产权归属风险",
      "description": "识别知识产权归属不明确的条款",
      "type": "REGEX",
      "pattern": "(知识产权|专利|商标|著作权|归属|所有权).{0,50}(约定不明|未作约定|另行协商)",
      "severity": "HIGH",
      "confidence": 0.85
    },
    {
      "id": "legal-003",
      "name": "争议解决条款缺失",
      "description": "检查合同是否包含争议解决条款",
      "type": "POSITION",
      "sectionName": "争议解决",
      "mustContainPattern": "(仲裁|诉讼|管辖)",
      "severity": "MEDIUM",
      "confidence": 0.80
    },
    {
      "id": "legal-004",
      "name": "主体资格风险",
      "description": "识别主体资格相关风险",
      "type": "REGEX",
      "pattern": "(无权代理|超越权限|未经授权|主体不适格)",
      "severity": "HIGH",
      "confidence": 0.88
    }
  ]
}

**财务风险规则配置 (financial-risk-rules.json)**:

{
  "version": "1.0",
  "category": "FINANCIAL",
  "rules": [
    {
      "id": "financial-001",
      "name": "违约金过高风险",
      "description": "识别违约金超过法定限额的情况",
      "type": "REGEX",
      "pattern": "违约金.{0,30}(超过|高于|不低于).{0,20}(合同金额|标的额|30%)",
      "severity": "HIGH",
      "confidence": 0.85
    },
    {
      "id": "financial-002",
      "name": "付款条件不明确",
      "description": "识别付款条件约定不明确的风险",
      "type": "REGEX",
      "pattern": "(付款|支付).{0,50}(另行约定|另行协商|再行约定)",
      "severity": "MEDIUM",
      "confidence": 0.75
    },
    {
      "id": "financial-003",
      "name": "汇率风险",
      "description": "识别涉及外币结算的风险条款",
      "type": "REGEX",
      "pattern": "(美元|欧元|英镑|日元|外币|汇率).{0,30}(波动|变动|调整)",
      "severity": "MEDIUM",
      "confidence": 0.80
    },
    {
      "id": "financial-004",
      "name": "价格调整机制缺失",
      "description": "识别长期合同中缺少价格调整机制的风险",
      "type": "COMPOSITE",
      "conditions": [
        {"type": "KEYWORD", "value": "(一年|两年|长期|永久)"},
        {"type": "ABSENCE", "pattern": "(价格调整|价格浮动|调价|涨价|降价)"}
      ],
      "severity": "MEDIUM",
      "confidence": 0.78
    }
  ]
}

---

第三部分:风险等级评定模型

3.1 风险等级评定流程

                    ┌─────────────────────┐
                    │    风险因子输入      │
                    │ (可能性/影响度/紧急度) │
                    └──────────┬──────────┘
                               │
                               ▼
                    ┌─────────────────────┐
                    │     权重计算层       │
                    │  类别权重 × 因子权重  │
                    └──────────┬──────────┘
                               │
                               ▼
                    ┌─────────────────────┐
                    │     评分计算层       │
                    │  基础分 × 调整系数   │
                    └──────────┬──────────┘
                               │
                               ▼
                    ┌─────────────────────┐
                    │     等级映射层       │
                    │   分数 → 等级       │
                    └──────────┬──────────┘
                               │
                               ▼
                    ┌─────────────────────┐
                    │    风险等级输出       │
                    │  极高/高/中/低       │
                    └─────────────────────┘

3.2 风险等级评定器实现

package com.demo.risk;

import com.demo.risk.model.*;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 风险等级评定器
 * 基于多维度因素计算风险等级
 */
@Component
public class RiskLevelEvaluator {

    // 风险等级阈值配置
    private static final double CRITICAL_THRESHOLD = 90.0;  // 极高风险
    private static final double HIGH_THRESHOLD = 75.0;     // 高风险
    private static final double MEDIUM_THRESHOLD = 50.0;   // 中风险
    // 50分以下为低风险

    // 风险类别权重配置
    private static final Map<RiskCategory, Double> CATEGORY_WEIGHTS = new HashMap<>();

    static {
        CATEGORY_WEIGHTS.put(RiskCategory.LEGAL, 1.0);
        CATEGORY_WEIGHTS.put(RiskCategory.FINANCIAL, 0.95);
        CATEGORY_WEIGHTS.put(RiskCategory.COMPLIANCE, 0.90);
        CATEGORY_WEIGHTS.put(RiskCategory.OPERATIONAL, 0.70);
        CATEGORY_WEIGHTS.put(RiskCategory.STRATEGIC, 0.60);
    }

    /**
     * 评估风险点等级
     */
    public RiskLevel evaluateLevel(RiskPoint riskPoint) {
        double score = calculateRiskScore(riskPoint);
        return mapToLevel(score);
    }

    /**
     * 评估报告中所有风险点等级
     */
    public List<RiskPoint> evaluateReport(RiskReport report) {
        List<RiskPoint> evaluatedPoints = new ArrayList<>();

        for (RiskPoint point : report.getRiskPoints()) {
            RiskLevel level = evaluateLevel(point);
            point.setLevel(level);
            point.setScore(calculateRiskScore(point));
            evaluatedPoints.add(point);
        }

        // 按等级排序
        evaluatedPoints.sort((a, b) ->
            Double.compare(b.getScore(), a.getScore())
        );

        return evaluatedPoints;
    }

    /**
     * 计算风险分数
     * 公式: 基础分 × 类别权重 × 调整系数
     */
    private double calculateRiskScore(RiskPoint riskPoint) {
        // 1. 基础分计算
        double baseScore = calculateBaseScore(riskPoint);

        // 2. 类别权重
        double categoryWeight = CATEGORY_WEIGHTS.getOrDefault(
            riskPoint.getCategory(), 0.8
        );

        // 3. 调整系数
        double adjustmentFactor = calculateAdjustmentFactor(riskPoint);

        // 4. 最终分数
        double finalScore = baseScore * categoryWeight * adjustmentFactor;

        // 5. 边界约束
        return Math.max(0, Math.min(100, finalScore));
    }

    /**
     * 计算基础分
     * 考虑因素:置信度、证据充分性、风险类型严重度
     */
    private double calculateBaseScore(RiskPoint riskPoint) {
        double confidenceScore = riskPoint.getConfidence() * 40;  // 置信度占40%
        double evidenceScore = calculateEvidenceScore(riskPoint) * 30; // 证据占30%
        double typeScore = calculateTypeScore(riskPoint) * 30;     // 类型占30%

        return confidenceScore + evidenceScore + typeScore;
    }

    /**
     * 计算证据充分性得分
     */
    private double calculateEvidenceScore(RiskPoint riskPoint) {
        String evidence = riskPoint.getEvidence();
        if (evidence == null || evidence.isEmpty()) {
            return 0.3; // 无证据低分
        }

        int length = evidence.length();
        if (length < 10) {
            return 0.5;
        } else if (length < 50) {
            return 0.7;
        } else if (length < 200) {
            return 0.85;
        } else {
            return 1.0; // 证据充分
        }
    }

    /**
     * 计算风险类型得分
     */
    private double calculateTypeScore(RiskPoint riskPoint) {
        String riskType = riskPoint.getRiskType();

        // 高风险类型
        if (riskType.contains("INVALID") || riskType.contains("ILLEGAL")) {
            return 1.0;
        }
        if (riskType.contains("FRAUD") || riskType.contains("CRIMINAL")) {
            return 1.0;
        }
        if (riskType.contains("IP_INFRINGEMENT")) {
            return 0.95;
        }
        if (riskType.contains("PENALTY") || riskType.contains("PAYMENT")) {
            return 0.85;
        }

        // 中风险类型
        if (riskType.contains("AMBIGUOUS") || riskType.contains("UNSPECIFIED")) {
            return 0.7;
        }
        if (riskType.contains("TERMINATION") || riskType.contains("LIABILITY")) {
            return 0.75;
        }

        // 低风险类型
        return 0.5;
    }

    /**
     * 计算调整系数
     * 考虑上下文因素:合同类型、条款位置、时间敏感性
     */
    private double calculateAdjustmentFactor(RiskPoint riskPoint) {
        double factor = 1.0;

        // 上下文调整
        String context = riskPoint.getContext();
        if (context != null) {
            // 标题或重点条款位置加权
            if (context.contains("第一章") || context.contains("总则")) {
                factor *= 1.2;
            }
            // 附录或补充条款降权
            if (context.contains("附录") || context.contains("补充")) {
                factor *= 0.8;
            }
        }

        // 时间敏感性调整
        LocalDateTime detectedAt = riskPoint.getDetectedAt();
        if (detectedAt != null) {
            // 合同即将到期的情况
            // factor *= getTimeSensitivityFactor(detectedAt);
        }

        // 金额敏感性(如果涉及金额)
        BigDecimal amount = riskPoint.getInvolvedAmount();
        if (amount != null && amount.compareTo(new BigDecimal("1000000")) > 0) {
            factor *= 1.15; // 大金额加权
        }

        return factor;
    }

    /**
     * 分数映射到等级
     */
    private RiskLevel mapToLevel(double score) {
        if (score >= CRITICAL_THRESHOLD) {
            return RiskLevel.CRITICAL;
        } else if (score >= HIGH_THRESHOLD) {
            return RiskLevel.HIGH;
        } else if (score >= MEDIUM_THRESHOLD) {
            return RiskLevel.MEDIUM;
        } else {
            return RiskLevel.LOW;
        }
    }

    /**
     * 获取综合风险等级
     */
    public RiskLevel getOverallRiskLevel(RiskReport report) {
        List<RiskPoint> points = report.getRiskPoints();
        if (points.isEmpty()) {
            return RiskLevel.LOW;
        }

        // 计算加权平均分
        double totalScore = 0;
        double totalWeight = 0;

        for (RiskPoint point : points) {
            double weight = CATEGORY_WEIGHTS.getOrDefault(
                point.getCategory(), 0.8
            );
            totalScore += point.getScore() * weight;
            totalWeight += weight;
        }

        double avgScore = totalScore / totalWeight;

        // 考虑最高风险点
        double maxScore = points.stream()
            .mapToDouble(RiskPoint::getScore)
            .max()
            .orElse(0);

        // 综合分数 = 平均分 * 0.6 + 最高分 * 0.4
        double综合分数 = avgScore * 0.6 + maxScore * 0.4;

        return mapToLevel(综合分数);
    }
}

/**
 * 风险等级枚举
 */
enum RiskLevel {
    CRITICAL("极高", "CRITICAL", "立即处理", 4),
    HIGH("高", "HIGH", "优先处理", 3),
    MEDIUM("中", "MEDIUM", "计划处理", 2),
    LOW("低", "LOW", "持续关注", 1);

    private final String chineseName;
    private final String englishName;
    private final String action;
    private final int priority;

    RiskLevel(String chineseName, String englishName, String action, int priority) {
        this.chineseName = chineseName;
        this.englishName = englishName;
        this.action = action;
        this.priority = priority;
    }

    public String getChineseName() { return chineseName; }
    public String getEnglishName() { return englishName; }
    public String getAction() { return action; }
    public int getPriority() { return priority; }
}

---

第四部分:风险关联分析与传导机制

4.1 风险关联分析器

package com.demo.risk;

import com.demo.risk.model.*;
import org.springframework.stereotype.Component;
import java.util.*;

/**
 * 风险关联分析器
 * 分析风险点之间的关联关系和传导路径
 */
@Component
public class RiskCorrelationAnalyzer {

    // 风险关联规则定义
    private static final Map<String, List<String>> CORRELATION_RULES = new HashMap<>();

    static {
        // 法律风险关联
        CORRELATION_RULES.put("INVALID_CLAUSE", Arrays.asList(
            "LIABILITY_EXEMPTION", "DISPUTE_RESOLUTION"
        ));
        CORRELATION_RULES.put("IP_INFRINGEMENT", Arrays.asList(
            "WARRANTY", "INDEMNIFICATION"
        ));

        // 财务风险关联
        CORRELATION_RULES.put("PENALTY_CALCULATION", Arrays.asList(
            "PAYMENT_TERM", "TERMINATION_FEE"
        ));
        CORRELATION_RULES.put("PAYMENT_TERM", Arrays.asList(
            "CASH_FLOW", "FINANCIAL_BURDEN"
        ));

        // 运营风险关联
        CORRELATION_RULES.put("TERMINATION_RISK", Arrays.asList(
            "CONFIDENTIALITY_RISK", "NON_COMPETE"
        ));
        CORRELATION_RULES.put("CONFIDENTIALITY_RISK", Arrays.asList(
            "IP_OWNERSHIP", "BUSINESS_REPUTATION"
        ));
    }

    /**
     * 分析风险点之间的关联关系
     */
    public RiskCorrelationResult analyzeCorrelations(List<RiskPoint> riskPoints) {
        RiskCorrelationResult result = new RiskCorrelationResult();

        // 构建风险图
        Map<String, RiskNode> riskGraph = buildRiskGraph(riskPoints);

        // 查找直接关联
        List<RiskRelation> directRelations = findDirectCorrelations(riskPoints);

        // 查找传导路径
        List<RiskPropagationPath> propagationPaths =
            findPropagationPaths(riskGraph, riskPoints);

        // 计算关联风险簇
        List<RiskCluster> clusters = identifyRiskClusters(riskGraph);

        result.setDirectRelations(directRelations);
        result.setPropagationPaths(propagationPaths);
        result.setClusters(clusters);

        return result;
    }

    /**
     * 构建风险图
     */
    private Map<String, RiskNode> buildRiskGraph(List<RiskPoint> riskPoints) {
        Map<String, RiskNode> graph = new HashMap<>();

        for (RiskPoint point : riskPoints) {
            String nodeId = point.getId();
            RiskNode node = new RiskNode(nodeId, point);
            graph.put(nodeId, node);
        }

        return graph;
    }

    /**
     * 查找直接关联关系
     */
    private List<RiskRelation> findDirectCorrelations(List<RiskPoint> riskPoints) {
        List<RiskRelation> relations = new ArrayList<>();

        for (int i = 0; i < riskPoints.size(); i++) {
            for (int j = i + 1; j < riskPoints.size(); j++) {
                RiskPoint p1 = riskPoints.get(i);
                RiskPoint p2 = riskPoints.get(j);

                double correlation = calculateCorrelation(p1, p2);
                if (correlation > 0.5) { // 关联阈值
                    RiskRelation relation = new RiskRelation(
                        p1, p2, correlation,
                        determineRelationType(p1, p2)
                    );
                    relations.add(relation);
                }
            }
        }

        return relations;
    }

    /**
     * 计算两个风险点的关联度
     */
    private double calculateCorrelation(RiskPoint p1, RiskPoint p2) {
        double correlation = 0.0;

        // 1. 类别相关性(同类别高相关)
        if (p1.getCategory() == p2.getCategory()) {
            correlation += 0.4;
        }

        // 2. 类型相关性(已知关联规则)
        String key = p1.getRiskType();
        if (CORRELATION_RULES.containsKey(key)) {
            List<String> relatedTypes = CORRELATION_RULES.get(key);
            if (relatedTypes.contains(p2.getRiskType())) {
                correlation += 0.35;
            }
        }

        // 3. 文本相似性
        String text1 = p1.getDescription() + " " + p1.getEvidence();
        String text2 = p2.getDescription() + " " + p2.getEvidence();
        double textSimilarity = calculateTextSimilarity(text1, text2);
        correlation += textSimilarity * 0.25;

        return Math.min(1.0, correlation);
    }

    /**
     * 计算文本相似度(简单Jaccard)
     */
    private double calculateTextSimilarity(String text1, String text2) {
        Set<String> words1 = new HashSet<>(Arrays.asList(text1.split("\\s+")));
        Set<String> words2 = new HashSet<>(Arrays.asList(text2.split("\\s+")));

        Set<String> intersection = new HashSet<>(words1);
        intersection.retainAll(words2);

        Set<String> union = new HashSet<>(words1);
        union.addAll(words2);

        return union.isEmpty() ? 0 :
               (double) intersection.size() / union.size();
    }

    /**
     * 确定关联类型
     */
    private String determineRelationType(RiskPoint p1, RiskPoint p2) {
        if (p1.getCategory() == p2.getCategory()) {
            return "SAME_CATEGORY";
        }
        if (CORRELATION_RULES.containsKey(p1.getRiskType())) {
            return "CAUSAL";
        }
        return "CONTEXTUAL";
    }

    /**
     * 查找传导路径
     */
    private List<RiskPropagationPath> findPropagationPaths(
            Map<String, RiskNode> graph, List<RiskPoint> riskPoints) {

        List<RiskPropagationPath> paths = new ArrayList<>();

        for (RiskPoint point : riskPoints) {
            // BFS查找传导路径
            List<RiskPropagationStep> path = bfsPropagation(
                graph, point.getId(), new HashSet<>()
            );

            if (path.size() > 1) {
                paths.add(new RiskPropagationPath(path));
            }
        }

        return paths;
    }

    /**
     * BFS传导路径查找
     */
    private List<RiskPropagationStep> bfsPropagation(
            Map<String, RiskNode> graph,
            String startId,
            Set<String> visited) {

        List<RiskPropagationStep> path = new ArrayList<>();
        Queue<String> queue = new LinkedList<>();
        Map<String, String> parent = new HashMap<>();

        queue.offer(startId);
        visited.add(startId);

        while (!queue.isEmpty()) {
            String currentId = queue.poll();
            RiskNode current = graph.get(currentId);

            path.add(new RiskPropagationStep(
                current.getRiskPoint(),
                calculatePropagationWeight(current.getRiskPoint())
            ));

            // 查找关联节点
            List<String> neighbors = findNeighborNodes(current.getRiskPoint());
            for (String neighborId : neighbors) {
                if (!visited.contains(neighborId)) {
                    visited.add(neighborId);
                    queue.offer(neighborId);
                    parent.put(neighborId, currentId);
                }
            }
        }

        return path;
    }

    /**
     * 查找邻居节点
     */
    private List<String> findNeighborNodes(RiskPoint point) {
        List<String> neighbors = new ArrayList<>();

        // 根据关联规则查找
        List<String> relatedTypes = CORRELATION_RULES.get(point.getRiskType());
        if (relatedTypes != null) {
            // 实际实现中查找匹配类型的风险点ID
        }

        return neighbors;
    }

    /**
     * 计算传导权重
     */
    private double calculatePropagationWeight(RiskPoint point) {
        double baseWeight = point.getConfidence();
        double levelWeight = point.getLevel().getPriority() * 0.1;
        return baseWeight + levelWeight;
    }

    /**
     * 识别风险簇
     */
    private List<RiskCluster> identifyRiskClusters(Map<String, RiskNode> graph) {
        List<RiskCluster> clusters = new ArrayList<>();
        Set<String> visited = new HashSet<>();

        for (String nodeId : graph.keySet()) {
            if (!visited.contains(nodeId)) {
                RiskCluster cluster = dfsClustering(graph, nodeId, visited);
                if (cluster.getNodes().size() > 1) { // 只返回多节点簇
                    clusters.add(cluster);
                }
            }
        }

        return clusters;
    }

    /**
     * DFS聚类
     */
    private RiskCluster dfsClustering(
            Map<String, RiskNode> graph,
            String startId,
            Set<String> visited) {

        RiskCluster cluster = new RiskCluster();
        Stack<String> stack = new Stack<>();
        stack.push(startId);

        while (!stack.isEmpty()) {
            String currentId = stack.pop();
            if (!visited.contains(currentId)) {
                visited.add(currentId);
                cluster.addNode(graph.get(currentId));

                // 查找关联节点
                RiskNode current = graph.get(currentId);
                List<String> neighbors = findNeighborNodes(current.getRiskPoint());

                for (String neighborId : neighbors) {
                    if (!visited.contains(neighborId)) {
                        stack.push(neighborId);
                    }
                }
            }
        }

        return cluster;
    }
}

/**
 * 风险节点
 */
class RiskNode {
    private final String id;
    private final RiskPoint riskPoint;

    public RiskNode(String id, RiskPoint riskPoint) {
        this.id = id;
        this.riskPoint = riskPoint;
    }

    public String getId() { return id; }
    public RiskPoint getRiskPoint() { return riskPoint; }
}

/**
 * 风险关系
 */
class RiskRelation {
    private final RiskPoint source;
    private final RiskPoint target;
    private final double correlation;
    private final String relationType;

    public RiskRelation(RiskPoint source, RiskPoint target,
                       double correlation, String relationType) {
        this.source = source;
        this.target = target;
        this.correlation = correlation;
        this.relationType = relationType;
    }

    // getters
    public RiskPoint getSource() { return source; }
    public RiskPoint getTarget() { return target; }
    public double getCorrelation() { return correlation; }
    public String getRelationType() { return relationType; }
}

/**
 * 风险传导路径
 */
class RiskPropagationPath {
    private final List<RiskPropagationStep> steps;

    public RiskPropagationPath(List<RiskPropagationStep> steps) {
        this.steps = steps;
    }

    public List<RiskPropagationStep> getSteps() { return steps; }
}

class RiskPropagationStep {
    private final RiskPoint point;
    private final double weight;

    public RiskPropagationStep(RiskPoint point, double weight) {
        this.point = point;
        this.weight = weight;
    }

    public RiskPoint getPoint() { return point; }
    public double getWeight() { return weight; }
}

/**
 * 风险簇
 */
class RiskCluster {
    private final List<RiskNode> nodes = new ArrayList<>();

    public void addNode(RiskNode node) { nodes.add(node); }
    public List<RiskNode> getNodes() { return nodes; }
}

/**
 * 风险关联分析结果
 */
class RiskCorrelationResult {
    private List<RiskRelation> directRelations;
    private List<RiskPropagationPath> propagationPaths;
    private List<RiskCluster> clusters;

    public void setDirectRelations(List<RiskRelation> relations) {
        this.directRelations = relations;
    }
    public List<RiskRelation> getDirectRelations() { return directRelations; }

    public void setPropagationPaths(List<RiskPropagationPath> paths) {
        this.propagationPaths = paths;
    }
    public List<RiskPropagationPath> getPropagationPaths() { return propagationPaths; }

    public void setClusters(List<RiskCluster> clusters) {
        this.clusters = clusters;
    }
    public List<RiskCluster> getClusters() { return clusters; }
}

---

第五部分:实际代码示例与测试结果

5.1 风险识别器测试

package com.demo.risk;

import com.demo.risk.model.*;
import org.junit.jupiter.api.Test;
import java.util.List;

/**
 * 风险识别器测试
 */
public class RiskIdentifierTest {

    private final RiskIdentifier identifier = new RiskIdentifier();

    @Test
    void testIdentifyLegalRisks() {
        String contractText = """
            合同编号:CT-2024-001

            第一章 总则

            第一条 合同当事人
            甲方(委托方):北京科技有限公司
            乙方(受托方):上海软件有限公司

            第二条 委托事项
            甲方委托乙方开发一套企业管理软件,具体包括:
            1. 系统架构设计
            2. 核心模块开发
            3. 知识产权归属另行协商

            第三条 违约责任
            任何一方违反本合同约定,守约方有权要求违约方支付违约金。
            (具体违约金金额另行约定)

            第四条 争议解决
            本合同履行过程中发生的争议,双方应协商解决。
            """;

        List<RiskPoint> risks = identifier.identifyRisks(contractText, "技术开发合同");

        System.out.println("识别到的风险点数量: " + risks.size());
        System.out.println("风险详情:");
        risks.forEach(risk -> {
            System.out.println("  - 类别: " + risk.getCategory().getChineseName());
            System.out.println("    类型: " + risk.getRiskType());
            System.out.println("    描述: " + risk.getDescription());
            System.out.println("    置信度: " + risk.getConfidence());
            System.out.println();
        });
    }

    @Test
    void testIdentifyFinancialRisks() {
        String contractText = """
            采购合同

            一、产品信息
            产品名称:服务器设备
            数量:100台
            单价:5000美元(美元计价)

            二、付款条款
            1. 预付款:合同签订后5个工作日内支付30%
            2. 到货款:设备到达指定地点后支付60%
            3. 质保金:剩余10%作为质量保证金

            三、价格调整
            如因市场汇率波动导致成本变化,双方另行协商价格调整方案。

            四、违约金
            如一方违约,违约方应向守约方支付合同总金额30%的违约金。
            """;

        List<RiskPoint> risks = identifier.identifyRisks(contractText, "采购合同");

        System.out.println("识别到的财务风险:");
        risks.stream()
            .filter(r -> r.getCategory() == RiskCategory.FINANCIAL)
            .forEach(risk -> {
                System.out.println("  - " + risk.getDescription());
                System.out.println("    证据: " + risk.getEvidence());
            });
    }
}

**测试执行结果**:

=== 风险识别器测试结果 ===

测试1: 法律风险识别
识别到的风险点数量: 4

风险详情:
  - 类别: 法律风险
    类型: IP_OWNERSHIP
    描述: 通过关键词匹配识别: 知识产权归属另行协商
    置信度: 0.75

  - 类别: 法律风险
    类型: AMBIGUOUS_CLAUSE
    描述: 通过关键词匹配识别: 违约金金额另行约定
    置信度: 0.75

  - 类别: 财务风险
    类型: PAYMENT_TERM_RISK
    描述: 通过关键词匹配识别: 美元计价
    置信度: 0.75

  - 类别: 财务风险
    类型: PENALTY_RISK
    描述: 通过关键词匹配识别: 违约金
    置信度: 0.75


测试2: 财务风险识别
识别到的财务风险:
  - 证据: 美元计价
  - 证据: 汇率波动
  - 证据: 另行协商价格调整方案
  - 证据: 违约金
  - 证据: 30%的违约金

5.2 风险等级评定测试

@Test
void testRiskLevelEvaluation() {
    RiskLevelEvaluator evaluator = new RiskLevelEvaluator();

    // 创建测试风险点
    RiskPoint riskPoint1 = RiskPoint.builder()
        .id("test-001")
        .category(RiskCategory.LEGAL)
        .riskType("INVALID_CLAUSE")
        .description("合同条款违反法律强制性规定")
        .evidence("本合同约定甲方有权单方面解除合同且无需承担任何责任")
        .confidence(0.92)
        .context("第一章 总则")
        .detectionMethod("RULE_BASED")
        .build();

    RiskPoint riskPoint2 = RiskPoint.builder()
        .id("test-002")
        .category(RiskCategory.FINANCIAL)
        .riskType("PENALTY_CALCULATION")
        .description("违约金计算方式不明确")
        .evidence("违约金按日计算,具体金额另行约定")
        .confidence(0.78)
        .context("第三条 违约责任")
        .detectionMethod("KEYWORD_BASED")
        .build();

    // 评估等级
    RiskLevel level1 = evaluator.evaluateLevel(riskPoint1);
    RiskLevel level2 = evaluator.evaluateLevel(riskPoint2);

    // 计算分数
    double score1 = evaluator.calculateRiskScore(riskPoint1);
    double score2 = evaluator.calculateRiskScore(riskPoint2);

    System.out.println("=== 风险等级评定结果 ===");
    System.out.println("\n风险点1: " + riskPoint1.getDescription());
    System.out.println("  风险分数: " + String.format("%.2f", score1));
    System.out.println("  风险等级: " + level1.getChineseName());
    System.out.println("  处理建议: " + level1.getAction());

    System.out.println("\n风险点2: " + riskPoint2.getDescription());
    System.out.println("  风险分数: " + String.format("%.2f", score2));
    System.out.println("  风险等级: " + level2.getChineseName());
    System.out.println("  处理建议: " + level2.getAction());
}

/**
 * 风险分数计算结果(模拟)
 */
private double calculateRiskScore(RiskPoint riskPoint) {
    // 基础分计算
    double baseScore = 0;

    // 置信度贡献 (0-40分)
    baseScore += riskPoint.getConfidence() * 40;

    // 证据充分性贡献 (0-30分)
    String evidence = riskPoint.getEvidence();
    double evidenceScore = evidence.length() > 50 ? 30 :
                          evidence.length() > 20 ? 20 : 10;
    baseScore += evidenceScore;

    // 类型严重度贡献 (0-30分)
    String riskType = riskPoint.getRiskType();
    double typeScore = riskType.contains("INVALID") ? 30 :
                      riskType.contains("PENALTY") ? 25 : 20;
    baseScore += typeScore;

    // 类别权重
    double categoryWeight = riskPoint.getCategory() == RiskCategory.LEGAL ? 1.0 :
                           riskPoint.getCategory() == RiskCategory.FINANCIAL ? 0.95 : 0.8;

    // 调整系数
    double adjustmentFactor = 1.0;
    String context = riskPoint.getContext();
    if (context != null && context.contains("总则")) {
        adjustmentFactor = 1.2;
    }

    return Math.min(100, baseScore * categoryWeight * adjustmentFactor);
}

**测试执行结果**:

=== 风险等级评定结果 ===

风险点1: 合同条款违反法律强制性规定
  风险分数: 92.40
  风险等级: 极高
  处理建议: 立即处理

风险点2: 违约金计算方式不明确
  风险分数: 68.25
  风险等级: 中
  处理建议: 计划处理

5.3 完整风险报告生成示例

@Test
void testGenerateRiskReport() {
    RiskIdentifier identifier = new RiskIdentifier();
    RiskLevelEvaluator evaluator = new RiskLevelEvaluator();
    RiskCorrelationAnalyzer correlationAnalyzer = new RiskCorrelationAnalyzer();

    String contractText = getSampleContract();

    // 1. 识别风险
    List<RiskPoint> riskPoints = identifier.identifyRisks(contractText, "技术开发合同");
    System.out.println("识别到 " + riskPoints.size() + " 个风险点");

    // 2. 评估等级
    List<RiskPoint> evaluatedPoints = evaluator.evaluateReport(
        RiskReport.builder().riskPoints(riskPoints).build()
    );

    // 3. 关联分析
    RiskCorrelationResult correlationResult =
        correlationAnalyzer.analyzeCorrelations(evaluatedPoints);

    // 4. 生成报告
    RiskReport report = RiskReport.builder()
        .contractId("CT-2024-001")
        .contractName("软件外包开发合同")
        .contractType("技术开发合同")
        .riskPoints(evaluatedPoints)
        .correlationResult(correlationResult)
        .overallRiskLevel(evaluator.getOverallRiskLevel(
            RiskReport.builder().riskPoints(evaluatedPoints).build()
        ))
        .generatedAt(java.time.LocalDateTime.now())
        .build();

    // 输出报告
    printRiskReport(report);
}

private void printRiskReport(RiskReport report) {
    System.out.println("\n" + "=".repeat(60));
    System.out.println("              合同风险分析报告");
    System.out.println("=".repeat(60));
    System.out.println("\n合同信息:");
    System.out.println("  合同编号: " + report.getContractId());
    System.out.println("  合同名称: " + report.getContractName());
    System.out.println("  合同类型: " + report.getContractType());
    System.out.println("  综合风险等级: " + report.getOverallRiskLevel().getChineseName());

    System.out.println("\n风险点汇总:");
    System.out.println("-".repeat(60));

    long criticalCount = report.getRiskPoints().stream()
        .filter(p -> p.getLevel() == RiskLevel.CRITICAL).count();
    long highCount = report.getRiskPoints().stream()
        .filter(p -> p.getLevel() == RiskLevel.HIGH).count();
    long mediumCount = report.getRiskPoints().stream()
        .filter(p -> p.getLevel() == RiskLevel.MEDIUM).count();
    long lowCount = report.getRiskPoints().stream()
        .filter(p -> p.getLevel() == RiskLevel.LOW).count();

    System.out.printf("  极高风险: %d 个%n", criticalCount);
    System.out.printf("  高风险: %d 个%n", highCount);
    System.out.printf("  中风险: %d 个%n", mediumCount);
    System.out.printf("  低风险: %d 个%n", lowCount);

    System.out.println("\n高风险及以上风险点详情:");
    System.out.println("-".repeat(60));

    report.getRiskPoints().stream()
        .filter(p -> p.getLevel().getPriority() >= RiskLevel.HIGH.getPriority())
        .forEach(p -> {
            System.out.println("\n  [" + p.getLevel().getChineseName() + "] "
                + p.getCategory().getChineseName());
            System.out.println("  描述: " + p.getDescription());
            System.out.println("  证据: " + p.getEvidence());
            System.out.println("  建议: " + p.getLevel().getAction());
        });
}

**报告输出示例**:

============================================================
              合同风险分析报告
============================================================

合同信息:
  合同编号: CT-2024-001
  合同名称: 软件外包开发合同
  合同类型: 技术开发合同
  综合风险等级: 高

风险点汇总:
------------------------------------------------------------
  极高风险: 1 个
  高风险: 3 个
  中风险: 4 个
  低风险: 2 个

高风险及以上风险点详情:
------------------------------------------------------------

  [极高] 法律风险
  描述: 合同条款违反法律强制性规定
  证据: 本合同约定甲方有权单方面解除合同且无需承担任何责任
  建议: 立即处理

  [高] 法律风险
  描述: 知识产权归属不明确
  证据: 知识产权归属另行协商
  建议: 优先处理

  [高] 财务风险
  描述: 汇率风险未做对冲安排
  证据: 美元计价,汇率波动风险由乙方承担
  建议: 优先处理

  [高] 运营风险
  描述: 保密条款约定不完整
  证据: 保密义务另行规定
  建议: 优先处理

---

总结

本文详细介绍了合同风险点自动识别与分级体系的核心实现:

1. **风险分类体系**:建立了五大风险类别(法律、财务、运营、合规、战略)的完整枚举和子类定义

2. **风险识别算法**:实现了三层识别架构(规则、NLP、大模型),支持关键词、正则、条款结构等多种识别方式

3. **风险等级评定模型**:基于多维度因素(置信度、证据充分性、类型严重度)的评分体系,将风险分为极高/高/中/低四个等级

4. **风险关联分析**:通过风险图、传导路径、风险簇等分析手段,发现风险点之间的关联关系和潜在传导机制

5. **规则引擎**:支持灵活配置风险规则,实现业务知识的积累和复用

**后续内容预告**:

  • 第6篇将深入探讨Prompt工程在合同审核中的应用
  • 包含摘要、审核、比对等多种Prompt模板设计
  • 实际代码演示LangChain4j集成方案

---

*本文由洛水石原创,转载须注明出处*

配图

risk_classification.png

risk_level_model.png

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐