金融风控 Ontology 建模:实时风险感知与关系网络分析
金融领域的关系复杂度远超其他行业:
Coomia发布于 2025年8月21日15 分钟阅读
分享本文Twitter / X
金融风控 Ontology 建模:实时风险感知与关系网络分析
“系列:S4 本体建模 · 第 17 篇 | 难度:中级 | 阅读时间:18 分钟
#TL;DR
- 金融风控 Ontology 以"客户-账户-交易"为核心三元组——个人、企业、账户、交易、产品、风险事件构成关系网络,coomia-dip 通过 RelationType 表达担保关系、资金流向、关联关系等复杂金融语义。
- 派生属性实现实时风险指标计算——客户的信用评分、账户的异常交易检测、产品的风险暴露度,全部通过派生属性自动计算,数据变更时毫秒级更新,消灭了"T+1 风控报表"的延迟。
- 关系图谱遍历发现隐性风险——通过 2~3 跳关系遍历发现"看似无关但实际关联"的客户群体、资金环路、担保链条,是传统规则引擎无法实现的风控能力。
#1. 金融数据的独特挑战
#1.1 关系复杂度
Code
金融领域的关系复杂度远超其他行业:
个人客户 张三:
├── 持有 3 个账户(储蓄、信用卡、理财)
├── 是 公司A 的法定代表人
├── 是 公司B 的股东(30%)
├── 为 公司C 提供了担保
├── 配偶 李四 也是客户
├── 李四 是 公司D 的法定代表人
├── 公司A 和 公司D 有资金往来
└── 公司B 为 公司A 提供了担保
问题:张三的贷款风险不仅取决于他个人的信用,
还取决于他关联的所有企业、担保链条、家庭成员。
传统方式:每种关系在不同系统中,分析需要手动关联
coomia-dip:所有关系在统一的 Ontology 模型中,一个查询搞定
#2. 核心 ObjectType 设计
#2.1 客户模型
Code
ObjectType: Individual(个人客户)
properties:
customerId: STRING (PK)
name: STRING
idNumber: STRING (SENSITIVE)
phone: STRING
email: STRING
occupation: STRING
annualIncome: DECIMAL
riskPreference: ENUM [CONSERVATIVE, MODERATE, AGGRESSIVE]
kycStatus: ENUM [PENDING, VERIFIED, REJECTED, EXPIRED]
kycVerifiedAt: TIMESTAMP
accounts: RELATION[] → Account
relatedCompanies: RELATION[] → CorporateRelation
familyMembers: RELATION[] → FamilyRelation
metrics:
monthlyTransactionVolume: METRIC(counter, source=core_banking)
avgDailyBalance: METRIC(gauge, source=core_banking)
loginFrequency: METRIC(counter, source=mobile_banking)
derivedProperties:
creditScore: DERIVED
expression: |
baseScore(annualIncome, occupation) * 0.3 +
paymentHistoryScore(accounts) * 0.35 +
utilizationScore(accounts) * 0.15 +
accountAgeScore(accounts) * 0.1 +
inquiryScore(creditInquiries) * 0.1
riskLevel: CASE
WHEN creditScore >= 750 THEN "LOW"
WHEN creditScore >= 600 THEN "MEDIUM"
WHEN creditScore >= 400 THEN "HIGH"
ELSE "VERY_HIGH"
END
totalAssets: SUM(Account.balance WHERE accountType IN ("SAVINGS","INVESTMENT"))
totalLiabilities: SUM(Account.balance WHERE accountType IN ("CREDIT","LOAN"))
debtToIncomeRatio: totalLiabilities / annualIncome
ObjectType: Corporate(企业客户)
properties:
companyId: STRING (PK)
companyName: STRING
registrationNumber: STRING
industry: STRING
registeredCapital: DECIMAL
establishedDate: DATE
legalRepresentative: RELATION → Individual
shareholders: RELATION[] → ShareholderRelation
accounts: RELATION[] → Account
guarantees: RELATION[] → GuaranteeRelation
metrics:
revenue: METRIC(counter, source=financial_reports)
netProfit: METRIC(gauge, source=financial_reports)
assetTurnoverRatio: METRIC(gauge, source=computed)
derivedProperties:
companyRiskScore: DERIVED
expression: |
financialHealthScore(revenue, netProfit) * 0.3 +
industryRiskScore(industry) * 0.2 +
guaranteeExposure(guarantees) * 0.2 +
paymentHistoryScore(accounts) * 0.3
isHighRisk: companyRiskScore < 50
totalGuaranteeAmount: SUM(GuaranteeRelation.amount)
guaranteeConcentration: MAX(GuaranteeRelation.amount) / totalGuaranteeAmount
#2.2 账户与交易
Code
ObjectType: Account(账户)
properties:
accountId: STRING (PK)
accountType: ENUM [SAVINGS, CHECKING, CREDIT, LOAN, INVESTMENT, MARGIN]
owner: RELATION → Individual | Corporate
currency: STRING
balance: DECIMAL
creditLimit: DECIMAL
interestRate: DECIMAL
openDate: DATE
status: ENUM [ACTIVE, FROZEN, CLOSED, DORMANT]
branch: RELATION → Branch
metrics:
dailyTransactionCount: METRIC(counter, source=core_banking)
dailyTransactionVolume: METRIC(counter, source=core_banking)
monthlyAvgBalance: METRIC(gauge, source=core_banking)
derivedProperties:
utilizationRate: balance / creditLimit (信用账户)
isOverLimit: balance > creditLimit
dormantDays: TODAY() - lastTransactionDate
isDormant: dormantDays > 180
averageTransactionSize: dailyTransactionVolume / dailyTransactionCount
ObjectType: Transaction(交易)
properties:
transactionId: STRING (PK)
fromAccount: RELATION → Account
toAccount: RELATION → Account
amount: DECIMAL
currency: STRING
transactionType: ENUM [TRANSFER, PAYMENT, WITHDRAWAL, DEPOSIT, FX, INVESTMENT]
channel: ENUM [COUNTER, ATM, MOBILE, ONLINE, API]
timestamp: TIMESTAMP
status: ENUM [PENDING, COMPLETED, FAILED, REVERSED]
description: STRING
location: STRING
deviceId: STRING
ipAddress: STRING (SENSITIVE)
derivedProperties:
isLargeTransaction: amount > threshold(fromAccount.accountType)
isCrossBoorder: fromAccount.currency != toAccount.currency
isUnusualTime: HOUR(timestamp) < 6 OR HOUR(timestamp) > 23
riskScore: DERIVED
expression: |
baseRisk(transactionType, amount) +
(IF(isLargeTransaction, 20, 0)) +
(IF(isCrossBoorder, 15, 0)) +
(IF(isUnusualTime, 10, 0)) +
velocityRisk(fromAccount, "1h") +
locationRisk(location, fromAccount.owner)
#2.3 风险关系模型
Code
RelationType: GuaranteeRelation(担保关系)
properties:
guarantor: RELATION → Individual | Corporate
borrower: RELATION → Individual | Corporate
guaranteeType: ENUM [JOINT, COLLATERAL, PLEDGE, LETTER_OF_CREDIT]
amount: DECIMAL
collateralType: STRING
collateralValue: DECIMAL
startDate: DATE
endDate: DATE
status: ENUM [ACTIVE, RELEASED, DEFAULTED]
RelationType: ShareholderRelation(股权关系)
properties:
shareholder: RELATION → Individual | Corporate
company: RELATION → Corporate
shareholdingPercentage: DECIMAL
shareType: ENUM [COMMON, PREFERRED]
beneficialOwner: BOOLEAN
RelationType: FamilyRelation(家庭关系)
properties:
person1: RELATION → Individual
person2: RELATION → Individual
relationship: ENUM [SPOUSE, PARENT, CHILD, SIBLING]
RelationType: FundFlow(资金流向)
properties:
from: RELATION → Account
to: RELATION → Account
totalAmount: DECIMAL
transactionCount: INT
timeRange: STRING
flowType: ENUM [REGULAR, OCCASIONAL, SUSPICIOUS]
#3. 实时风险指标计算
#3.1 客户级风险仪表盘
Code
Individual 的风险指标 DAG:
Level 0(源数据):
交易记录、账户余额、个人信息、外部征信
Level 1(账户级派生):
Account.utilizationRate
Account.overdueDay s
Account.averageTransactionSize
Level 2(客户级聚合):
Individual.totalAssets = SUM(Account.balance WHERE type IN savings/investment)
Individual.totalLiabilities = SUM(Account.balance WHERE type IN credit/loan)
Individual.maxOverdueDays = MAX(Account.overdueDays)
Level 3(客户级派生):
Individual.debtToIncomeRatio = totalLiabilities / annualIncome
Individual.creditScore = weighted_sum(...)
Individual.riskLevel = CASE(creditScore)
Level 4(关联风险):
Individual.guaranteeExposure = SUM(GuaranteeRelation.amount)
Individual.relatedCompanyRisk = MAX(Corporate.companyRiskScore)
Level 5(综合风险):
Individual.compositeRiskScore = creditScore * 0.6 + guaranteeExposure * 0.2 + relatedCompanyRisk * 0.2
交易发生时的级联更新:
新交易 → 账户余额变 → utilizationRate 变 → creditScore 变 → riskLevel 变
全链路毫秒级更新,无需等 T+1 报表
#3.2 反洗钱(AML)指标
Code
AML 相关的派生属性:
ObjectType: Individual(扩展 AML 属性)
derivedProperties:
# 交易速度检测
transactionVelocity_1h: COUNT(Transaction WHERE timestamp > NOW() - 1h)
transactionVelocity_24h: COUNT(Transaction WHERE timestamp > NOW() - 24h)
isHighVelocity: transactionVelocity_1h > 10 OR transactionVelocity_24h > 50
# 分散交易检测(Structuring / Smurfing)
nearThresholdTransactions: COUNT(Transaction WHERE amount BETWEEN 9000 AND 10000 AND timestamp > NOW() - 7d)
isStructuring: nearThresholdTransactions >= 3
# 跨境交易模式
crossBorderFrequency: COUNT(Transaction WHERE isCrossBoorder AND timestamp > NOW() - 30d)
highRiskCountryTransactions: COUNT(Transaction WHERE toAccount.country IN highRiskCountries)
# 资金环路检测(通过关系遍历)
hasFundCycle: EXISTS(
TRAVERSE fromAccount → Transaction.toAccount → Transaction.fromAccount
WHERE depth <= 3 AND endpoint == startpoint
)
# 综合 AML 风险
amlRiskScore: DERIVED
expression: |
(IF(isHighVelocity, 25, 0)) +
(IF(isStructuring, 30, 0)) +
(IF(crossBorderFrequency > 10, 15, 0)) +
(IF(highRiskCountryTransactions > 0, 20, 0)) +
(IF(hasFundCycle, 30, 0))
amlAlert: amlRiskScore >= 50
告警 Action:
ActionType: CreateSAR(可疑交易报告)
trigger: amlAlert == true
parameters:
customerId: REQUIRED
alertType: ENUM [STRUCTURING, HIGH_VELOCITY, FUND_CYCLE, HIGH_RISK_COUNTRY]
assignedAnalyst: RELATION → Employee
dueDate: NOW() + 5d
guards:
- NOT EXISTS(SAR WHERE customerId = this.customerId AND status = "OPEN")
#4. 关系图谱分析
#4.1 关联客户发现
Code
通过关系遍历发现隐性关联:
查询:找出与"张三"有关联的所有客户
API: POST /api/v1/objects/Individual/zhang-san/graph
{
"maxDepth": 3,
"relationTypes": ["FamilyRelation", "ShareholderRelation", "GuaranteeRelation"],
"includeProperties": ["name", "creditScore", "riskLevel"]
}
结果:
张三 (creditScore: 720, riskLevel: MEDIUM)
├── [配偶] 李四 (creditScore: 680, riskLevel: MEDIUM)
│ └── [法定代表人] 公司D (riskScore: 45, isHighRisk: true)
│ └── [资金往来] 公司A
├── [法定代表人] 公司A (riskScore: 72)
│ └── [担保] ← 公司B (riskScore: 55)
├── [股东30%] 公司B (riskScore: 55)
│ └── [担保] → 公司A
└── [担保人] → 公司C (riskScore: 38, isHighRisk: true)
风险发现:
├── 张三的配偶李四关联了高风险企业(公司D)
├── 公司A 和 公司B 形成了互保关系
├── 公司C 是高风险企业,张三为其提供了担保
└── 如果公司C 违约,张三需要承担担保责任
→ 这会影响张三的信用评分和贷款审批
#4.2 担保链分析
Code
担保链风险分析:
查询:分析企业 A 的担保链条
API: POST /api/v1/objects/Corporate/company-a/trace
{
"relationType": "GuaranteeRelation",
"direction": "BOTH",
"maxDepth": 5,
"includeRiskScores": true
}
结果:
担保链路可视化:
公司E (riskScore: 82)
↓ 担保 500万
公司B (riskScore: 55)
↓ 担保 1000万
公司A (riskScore: 72) ← 分析目标
↓ 担保 800万
公司C (riskScore: 38) ← 高风险!
↓ 担保 600万
公司F (riskScore: 25) ← 高风险!
风险分析:
├── 担保链深度:5 层
├── 链上高风险企业:2 家(公司C、公司F)
├── 公司A 的下游担保暴露:800万(直接)+ 600万(间接)= 1400万
├── 如果公司F 违约:公司C 需要代偿 600万
│ → 公司C 可能无法代偿(riskScore=38)
│ → 公司A 需要为公司C 代偿 800万
│ → 级联风险总额:1400万
└── 建议:降低公司A 的信用额度,要求补充担保物
#4.3 资金流向分析
Code
资金流向网络分析:
查询:分析账户 A001 的资金流向网络
API: POST /api/v1/objects/Account/A001/fund-flow
{
"timeRange": {"from": "2025-01-01", "to": "2025-01-31"},
"minAmount": 100000,
"maxDepth": 3,
"detectCycles": true
}
结果:
A001 (张三储蓄)
├──→ A002 (公司A 对公) ¥500,000 × 3次
│ ├──→ A005 (公司D 对公) ¥300,000 × 2次
│ │ └──→ A003 (李四储蓄) ¥200,000 × 1次
│ │ └──→ A001 (张三储蓄) ¥150,000 × 1次 ← 资金环路!
│ └──→ A006 (供应商E) ¥400,000 × 5次 (正常业务)
└──→ A004 (张三信用卡) ¥100,000 × 2次 (自有账户)
发现:
├── 资金环路:A001 → A002 → A005 → A003 → A001
├── 环路金额:¥150,000
├── 可疑性:资金通过 4 个账户 3 家关联企业回流
├── 可能目的:虚增交易量 / 洗钱 / 转移资产
└── 自动触发 SAR(可疑交易报告)
coomia-dip 的优势:
传统方式需要数据分析师手动追踪资金流向
coomia-dip 通过关系遍历 + 环检测自动发现
秒级完成,覆盖所有账户
#5. 风控规则引擎
#5.1 规则与 Ontology 的结合
Code
风控规则通过 Ontology 的 ActionType 实现:
ActionType: FreezeAccount(冻结账户)
trigger:
OR:
- account.overdueDays > 90
- account.owner.amlRiskScore >= 80
- account.owner.creditScore < 300
- manual_trigger
parameters:
accountId: REQUIRED
freezeReason: ENUM [OVERDUE, AML_ALERT, FRAUD_SUSPECT, LEGAL_ORDER]
freezeLevel: ENUM [DEBIT_ONLY, FULL_FREEZE]
duration: DURATION
guards:
- account.status != "FROZEN"
- account.balance >= 0 OR freezeReason == "LEGAL_ORDER"
approvalWorkflow:
- IF freezeLevel == "FULL_FREEZE": require_approval("risk_manager")
- IF freezeReason == "LEGAL_ORDER": require_approval("compliance_officer")
sideEffects:
- NOTIFY(account.owner, "ACCOUNT_FROZEN")
- UPDATE(account.status, "FROZEN")
- LOG(auditTrail)
ActionType: AdjustCreditLimit(调整信用额度)
trigger:
OR:
- creditScore 变化超过 50 分
- debtToIncomeRatio > 0.6
- guaranteeExposure 新增
parameters:
accountId: REQUIRED
newLimit: DECIMAL
adjustmentReason: STRING
guards:
- newLimit >= 0
- newLimit <= maxAllowedLimit(account.owner.creditScore)
#6. 信贷审批模型
Code
ObjectType: LoanApplication(贷款申请)
properties:
applicationId: STRING (PK)
applicant: RELATION → Individual | Corporate
loanType: ENUM [PERSONAL, MORTGAGE, AUTO, BUSINESS, CREDIT_LINE]
requestedAmount: DECIMAL
requestedTerm: INT (months)
purpose: STRING
collateral: RELATION[] → Collateral
guarantors: RELATION[] → Individual
status: ENUM [SUBMITTED, UNDER_REVIEW, APPROVED, REJECTED, DISBURSED]
submittedAt: TIMESTAMP
decisionAt: TIMESTAMP
assignedOfficer: RELATION → Employee
derivedProperties:
autoDecision: DERIVED
expression: |
CASE
WHEN applicant.creditScore >= 750 AND requestedAmount <= preApprovedLimit THEN "AUTO_APPROVE"
WHEN applicant.creditScore < 400 THEN "AUTO_REJECT"
WHEN applicant.amlRiskScore >= 50 THEN "MANUAL_REVIEW"
WHEN applicant.debtToIncomeRatio > 0.5 THEN "MANUAL_REVIEW"
WHEN guaranteeChainRisk > 0.7 THEN "MANUAL_REVIEW"
ELSE "MANUAL_REVIEW"
END
guaranteeChainRisk: DERIVED
expression: |
# 遍历担保链条,计算级联违约概率
TRAVERSE(applicant, "GuaranteeRelation", depth=3)
→ 统计链上高风险企业数量和占比
expectedLossRate: DERIVED
expression: |
PD(applicant.creditScore) * LGD(collateral) * EAD(requestedAmount)
riskAdjustedPricing: DERIVED
expression: |
baseRate + riskPremium(expectedLossRate) + operatingCostRate
#7. 监管合规模型
Code
ObjectType: RegulatoryReport(监管报表)
properties:
reportId: STRING (PK)
reportType: ENUM [CAR, LCR, NSFR, LR, SAR, CTR]
reportingPeriod: STRING
status: ENUM [DRAFT, SUBMITTED, ACCEPTED, REJECTED]
submittedAt: TIMESTAMP
dueDate: DATE
derivedProperties:
capitalAdequacyRatio: DERIVED(资本充足率)
expression: |
(tier1Capital + tier2Capital) / riskWeightedAssets * 100
liquidityCoverageRatio: DERIVED(流动性覆盖率)
expression: |
highQualityLiquidAssets / totalNetCashOutflows30d * 100
nonPerformingLoanRatio: DERIVED(不良贷款率)
expression: |
COUNT(Account WHERE overdueDays > 90 AND accountType = "LOAN") /
COUNT(Account WHERE accountType = "LOAN") * 100
所有监管指标都是 Ontology 派生属性:
├── 数据实时计算,随时可以查看最新值
├── 历史值自动保存,支持趋势分析
├── 数据血缘可追溯到每一笔交易
└── 审计时可以精确重现任何时间点的指标值
#8. 欺诈检测模型
Code
ObjectType: FraudAlert(欺诈告警)
properties:
alertId: STRING (PK)
alertType: ENUM [IDENTITY_THEFT, CARD_FRAUD, ACCOUNT_TAKEOVER,
APPLICATION_FRAUD, INSIDER_FRAUD]
relatedTransaction: RELATION → Transaction
relatedAccount: RELATION → Account
relatedCustomer: RELATION → Individual
confidence: DECIMAL
status: ENUM [OPEN, INVESTIGATING, CONFIRMED, FALSE_POSITIVE]
assignedAnalyst: RELATION → Employee
欺诈检测派生属性(实时计算):
Transaction 的欺诈评分:
fraudScore: DERIVED
expression: |
deviceRisk(deviceId, account.knownDevices) * 0.2 +
locationRisk(location, account.normalLocations) * 0.2 +
amountRisk(amount, account.averageTransactionSize) * 0.2 +
velocityRisk(account, "1h") * 0.2 +
behaviorRisk(transactionType, channel, timestamp) * 0.2
isFraudSuspect: fraudScore >= 70
告警规则:
当 isFraudSuspect == true:
1. 实时阻断交易(如果 fraudScore >= 90)
2. 发送短信验证(如果 fraudScore 70~90)
3. 创建 FraudAlert 记录
4. 通知反欺诈分析师
5. 冻结相关账户(如果确认为欺诈)
#9. 关系网络全景
Code
金融风控 Ontology 的关系网络:
Individual ──holds──→ Account
Corporate ──holds──→ Account
Individual ──represents──→ Corporate
Individual ──shareholderOf──→ Corporate
Individual ──guarantees──→ Corporate
Individual ──familyOf──→ Individual
Corporate ──guarantees──→ Corporate
Corporate ──subsidiaryOf──→ Corporate
Account ──transfers──→ Account (via Transaction)
Individual ──applies──→ LoanApplication
LoanApplication ──securedBy──→ Collateral
FraudAlert ──relatedTo──→ Transaction
FraudAlert ──involves──→ Account
SAR ──reportedFor──→ Individual
关系总数:14 种
ObjectType 总数:12 种
核心价值:
传统风控:基于规则,只看个体数据
coomia-dip 风控:基于关系网络,看个体 + 关联 + 传导
"张三是低风险,但他担保的公司C是高风险"
→ 这种关联风险只有关系图谱能发现
#10. 与传统风控的对比
Code
Ontology 风控 vs 传统风控:
┌──────────────────┬────────────────────┬──────────────────────┐
│ 维度 │ coomia-dip │ 传统风控系统 │
├──────────────────┼────────────────────┼──────────────────────┤
│ 数据模型 │ 统一 Ontology │ 多系统分散 │
│ 关系分析 │ 图遍历,N 跳 │ SQL JOIN,2~3 表 │
│ 指标计算 │ 实时派生属性 │ T+1 批量计算 │
│ 规则执行 │ ActionType + Guard │ 独立规则引擎 │
│ 环路检测 │ 内置图算法 │ 需要专用图数据库 │
│ 监管报表 │ 派生属性自动计算 │ 手动数据提取 │
│ 审计追溯 │ 属性级血缘 │ 报表级追溯 │
│ 扩展性 │ 新增 ObjectType │ 需要改表加字段 │
│ 开发效率 │ Schema 驱动 │ 需要开发 + 测试 │
└──────────────────┴────────────────────┴──────────────────────┘
#Key Takeaways
- 金融 Ontology 的核心是关系网络而非孤立实体——客户的风险不仅取决于自身数据,还取决于担保链条、股权关系、家庭关系、资金流向等网络结构,coomia-dip 的 RelationType 天然支持这种复杂关系建模。
- 派生属性实现了"实时风控"——信用评分、AML 指标、欺诈评分全部通过派生属性自动计算,交易发生时毫秒级更新,从"T+1 风控报表"升级为"实时风险感知"。
- 关系图谱遍历是 Ontology 风控的独特能力——通过 2~3 跳遍历发现隐性关联客户、资金环路、担保链条风险,这是传统 SQL JOIN 和规则引擎无法实现的。
- ActionType 实现了从"发现风险"到"处置风险"的闭环——账户冻结、额度调整、SAR 提交、贷款拒绝,全部通过 Ontology 的 Action 机制自动执行,带有审批流程和审计日志。
- 监管合规指标是派生属性的自然应用——资本充足率、流动性覆盖率、不良贷款率等监管指标通过 Ontology 自动计算,数据可追溯到每一笔交易,满足审计要求。
#Next Article
下一篇 S4-18 医疗健康 Ontology 建模 将讨论如何用 Ontology 模型表达医疗领域的复杂语义——患者、就诊、诊断、处方、检验、医疗设备,如何处理医疗数据的隐私合规要求,如何用关系网络实现疾病谱分析。
#ontology #financial-risk #aml #credit-scoring #fraud-detection #guarantee-chain #fund-flow #compliance #graph-analysis