Install any skill in seconds. Free to start, no credit card required.
Get Started Free →客户风险暴露诊断助手,适用于券商财富管理、投顾服务、客户风控、适当性管理等场景。 以下情况请主动触发此技能: - 用户提供了客户持仓数据、风险测评信息,问"这个客户风险怎么样""帮我诊断一下""风险暴露大吗" - 用户问"客户风险怎么评估""风险暴露怎么看""如何诊断客户风险" - 用户需要:客户风险诊断、风险暴露分析、适当性评估、风险预警 - 用户提到:客户风险、风险暴露、适当性、风险测评、持仓风险、客户预警 - 用户需要形成客户风险报告、投顾建议、风险预警、适当性核查 不要等用户明确说"客户风险诊断"——只要涉及客户风险评估、持仓风险分析、适当性判断,就应主动启动此技能。
.claude/skills/aifinlab-client-risk-exposure-diagnosis/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-03 | ✗→✓ | ▲ Improved | 51% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 67% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 102% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 97% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 99% | 0% |
你的核心职责:基于客户持仓、交易、风险测评等数据,全面诊断客户风险暴露情况,形成可落地的风险管理和投顾建议。
收到用户请求后,先做两个判断:
判断 1:是否有客户数据?
判断 2:用户需要哪种深度?
| 用户意图 | 适用模板 | |---------|---------| | "风险怎么样""快速看看" | 模板 A:快速诊断 | | "详细分析""有什么风险" | 模板 B:标准诊断 | | "投顾建议""风险报告" | 模板 C:报告版 | | 未明确说明 | 默认模板 A,再提供"需要详细诊断可继续" |
客户基本信息:
持仓数据:
交易数据:
风险数据:
1. 市场风险暴露
2. 流动性风险暴露
3. 信用风险暴露(如有两融)
4. 操作风险暴露
5. 适当性风险
持仓集中度 = 最大持仓市值 / 总资产 × 100%
行业集中度 = 最大行业持仓市值 / 总资产 × 100%
仓位水平 = 持仓市值 / 总资产 × 100%
持仓 Beta = ∑(个股权重 × 个股 Beta)
持仓波动率 = sqrt(∑(个股权重² × 个股波动率²) + 协方差项)
VaR = 在险价值(一定置信度下的最大可能损失)| 等级 | 持仓集中度 | 行业集中度 | 持仓 Beta | 仓位水平 | 适当性匹配 | |-----|------------|------------|-----------|---------|------------| | 低 | <20% | <30% | <0.8 | <50% | 匹配 | | 中 | 20%-40% | 30%-50% | 0.8-1.2 | 50%-70% | 基本匹配 | | 高 | 40%-60% | 50%-70% | 1.2-1.5 | 70%-90% | 偏高风险 | | 严重 | >60% | >70% | >1.5 | >90% | 严重不匹配 |
1. 集中度风险信号
2. 波动风险信号
3. 流动性风险信号
4. 适当性风险信号
> 适用:"风险怎么样""快速看看"
**客户风险诊断** | 客户 XXX
**风险等级**:[低/中/高/严重]
**关键指标**:
- 持仓集中度:XX%
- 行业集中度:XX%
- 持仓 Beta:XX
- 仓位水平:XX%
**适当性匹配**:[匹配/基本匹配/偏高风险/严重不匹配]
**主要风险点**:
1. xxx
2. xxx
**建议**:xxx> 适用:"详细分析""有什么风险"
**客户风险诊断** | 客户 XXX
## 一、客户基本信息
- 风险测评等级:XXX
- 投资经验:XX 年
- 资产规模:XX 万
## 二、持仓风险分析
**持仓概览**:
- 持仓市值:XX 万
- 持仓数量:XX 只
- 仓位水平:XX%
**集中度风险**:
- 最大持仓占比:XX%
- 前五大持仓占比:XX%
- 最大行业占比:XX%
**波动风险**:
- 持仓 Beta:XX
- 持仓波动率:XX%
- 历史最大回撤:XX%
**流动性风险**:
- 低流动性持仓占比:XX%
- 大额持仓占比:XX%
## 三、适当性评估
**风险匹配度**:[匹配/基本匹配/偏高风险/严重不匹配]
**不匹配点**(如有):
- xxx
## 四、风险信号
**触及风险信号**:
1. xxx
2. xxx
## 五、建议措施
**短期建议**:
1. xxx
**长期建议**:
1. xxx> 适用:"投顾建议""风险报告"
**客户风险诊断报告** | 客户 XXX | YYYY-MM-DD
**核心结论**:xxx
**风险等级评估**:
| 风险维度 | 等级 | 关键指标 | 状态 |
|---------|------|---------|------|
| 集中度风险 | xxx | xxx | xxx |
| 波动风险 | xxx | xxx | xxx |
| 流动性风险 | xxx | xxx | xxx |
| 适当性风险 | xxx | xxx | xxx |
**主要风险点**:
- 风险点 1:xxx(影响:xxx)
- 风险点 2:xxx(影响:xxx)
**适当性评估**:
- 风险测评等级:XXX
- 实际风险暴露:XXX
- 匹配度:xxx
- 不匹配说明:xxx
**投顾建议**:
**短期(1 周内)**:
1. xxx
2. xxx
**中期(1 月内)**:
1. xxx
2. xxx
**长期(持续)**:
1. xxx
2. xxx
**风险提示**:
- xxx
**后续跟踪**:
- 跟踪频率:xxx
- 跟踪指标:xxx数据不完整:基于已有数据生成诊断,说明"完整诊断需 XX 数据"
新客户/数据不足:说明"客户数据不足,建议补充 XX 信息后再诊断"
风险等级与测评严重不匹配:重点提示适当性风险,建议重新风险测评或调整持仓
高风险客户:形成专项报告,建议投顾介入沟通
监管要求:
风险测评标准:
行业实践:
Python 客户风险诊断示例:
pythonimport pandas as pd import numpy as np def calc_concentration_risk(holdings_df): """计算集中度风险""" total_value = holdings_df['market_value'].sum() max_position = holdings_df['market_value'].max() / total_value * 100 top5_position = holdings_df.nlargest(5, 'market_value')['market_value'].sum() / total_value * 100 # 行业集中度 sector_concentration = holdings_df.groupby('sector')['market_value'].sum() max_sector = sector_concentration.max() / total_value * 100 return { 'max_position_ratio': max_position, 'top5_position_ratio': top5_position, 'max_sector_ratio': max_sector } def calc_portfolio_beta(holdings_df): """计算组合 Beta""" total_value = holdings_df['market_value'].sum() holdings_df['weight'] = holdings_df['market_value'] / total_value portfolio_beta = (holdings_df['weight'] * holdings_df['beta']).sum() return portfolio_beta def assess_suitability(risk_level, portfolio_beta, holdings_volatility): """评估适当性""" # 风险等级映射 risk_map = {'C1': 0.5, 'C2': 0.8, 'C3': 1.0, 'C4': 1.3, 'C5': 1.8} max_allowed_beta = risk_map.get(risk_level, 1.0) if portfolio_beta > max_allowed_beta * 1.3: return '严重不匹配' elif portfolio_beta > max_allowed_beta: return '偏高风险' elif portfolio_beta > max_allowed_beta * 0.7: return '基本匹配' else: return '匹配' def generate_client_diagnosis(client_info, holdings_df, trade_df): """生成客户诊断报告""" concentration = calc_concentration_risk(holdings_df) portfolio_beta = calc_portfolio_beta(holdings_df) suitability = assess_suitability( client_info['risk_level'], portfolio_beta, holdings_df['volatility'].mean() ) return { 'client_id': client_info['client_id'], 'risk_level': client_info['risk_level'], 'concentration_risk': concentration, 'portfolio_beta': portfolio_beta, 'suitability': suitability, 'recommendations': generate_recommendations(concentration, portfolio_beta, suitability) }
SQL 查询示例:
sql-- 查询客户风险指标 SELECT c.client_id, c.risk_level, COUNT(DISTINCT h.stock_code) as position_count, SUM(h.market_value) as total_value, MAX(h.market_value) / SUM(h.market_value) * 100 as max_position_ratio, SUM(h.market_value * h.beta) / SUM(h.market_value) as portfolio_beta, AVG(h.volatility) as avg_volatility FROM client_info c JOIN holdings h ON c.client_id = h.client_id WHERE c.client_id = 'CLIENT001' GROUP BY c.client_id, c.risk_level;
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→fail | 10,178 | 9,884 | -3% | 1 | 1 | 0% | 1,760 | 4,793 | +172% | 0 | 0 | — |
case-02 | fail→fail | 22,522 | 20,751 | -8% | 1 | 1 | 0% | 3,833 | 6,529 | +70% | 0 | 0 | — |
case-03 | fail→pass | 27,668 | 21,446 | -22% | 1 | 1 | 0% | 4,248 | 6,424 | +51% | 0 | 0 | — |
case-04 | fail→pass | 18,692 | 9,383 | -50% | 1 | 1 | 0% | 2,699 | 4,497 | +67% | 0 | 0 | — |
case-05 | fail→pass | 19,113 | 14,906 | -22% | 1 | 1 | 0% | 2,565 | 5,187 | +102% | 0 | 0 | — |
case-06 | fail→fail | 20,084 | 16,480 | -18% | 1 | 1 | 0% | 3,005 | 5,488 | +83% | 0 | 0 | — |
case-07 | fail→pass | 17,681 | 16,402 | -7% | 1 | 1 | 0% | 2,835 | 5,571 | +97% | 0 | 0 | — |
case-08 | pass→fail | 19,064 | 19,059 | -0% | 1 | 1 | 0% | 3,031 | 6,064 | +100% | 0 | 0 | — |
case-09 | pass→pass | 15,145 | 10,976 | -28% | 1 | 1 | 0% | 2,373 | 4,728 | +99% | 0 | 0 | — |
case-10 | pass→pass | 15,267 | 15,059 | -1% | 1 | 1 | 0% | 2,508 | 5,561 | +122% | 0 | 0 | — |
case-11 | pass→pass | 25,349 | 21,802 | -14% | 1 | 1 | 0% | 4,210 | 6,570 | +56% | 0 | 0 | — |
case-12 | pass→pass | 17,877 | 14,923 | -17% | 1 | 1 | 0% | 2,605 | 5,260 | +102% | 0 | 0 | — |
case-13 | pass→pass | 17,399 | 14,193 | -18% | 1 | 1 | 0% | 2,628 | 5,194 | +98% | 0 | 0 | — |
case-14 | pass→pass | 19,882 | 14,241 | -28% | 1 | 1 | 0% | 3,940 | 6,001 | +52% | 0 | 0 | — |
case-15 | fail→pass | 11,466 | 7,920 | -31% | 1 | 1 | 0% | 2,280 | 4,542 | +99% | 0 | 0 | — |
case-16 | pass→pass | 19,078 | 20,930 | +10% | 1 | 1 | 0% | 2,694 | 6,020 | +123% | 0 | 0 | — |
case-17 | fail→fail | 14,714 | 14,840 | +1% | 1 | 1 | 0% | 2,279 | 5,251 | +130% | 0 | 0 | — |
case-18 | fail→pass | 19,879 | 11,825 | -41% | 1 | 1 | 0% | 2,928 | 4,974 | +70% | 0 | 0 | — |
case-19 | pass→pass | 19,702 | 13,470 | -32% | 1 | 1 | 0% | 3,185 | 5,186 | +63% | 0 | 0 | — |
case-20 | fail→pass | 20,948 | 15,426 | -26% | 1 | 1 | 0% | 3,083 | 5,372 | +74% | 0 | 0 | — |
case-21 | fail→fail | 22,436 | 20,163 | -10% | 1 | 1 | 0% | 3,667 | 6,523 | +78% | 0 | 0 | — |
case-22 | fail→fail | 27,277 | 28,353 | +4% | 1 | 1 | 0% | 4,406 | 7,580 | +72% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +23 percentage points is the difference between those two pass rates over the 22 comparable cases. 2 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.