Aloudata CAN SKILLS - metric-attribution
对指标波动进行综合归因诊断,定位导致指标变化的关键因子、维度和外部事件。当用户需要分析指标波动原因、定位指标变化的根因、做因子拆解归因(如 GMV = UV × 转化率 × 客单价)、或理解指标为什么涨跌时,必须使用此 Skill。 触发场景包括但不限于:用户提到"归因""归因分析""波动分析""波动归因""根因分析""根因""下钻分析""下钻归因""为什么涨了""为什么跌了""为什么下降""为什么增长""什么原因""哪个维度导致""贡献度分析""贡献度""因子拆解""因子分解""驱动因素""影响因素""变化原因""差异分析",或用户对某个指标的变化表达了疑问、希望了解变化背后的原因时,都应使用此 Skill。 即使用户没有直接说"归因"二字,只要其意图是理解指标变化的原因或定位问题维度,也应触发此 Skill。 **重要:本 Skill 通过组合调用 Gateway API 获取指标数据,在本地进行归因计算,结合外部事件检索,最终输出综合归因诊断报告。构建查询前,必须先通过 Gateway API 检索相关指标和维度信息,禁止凭记忆猜测指标名或维度名。**
安装 / 下载方式
TotalClaw CLI推荐
totalclaw install clawskills:jackyujun~metric-attributioncURL直接下载,无需登录
curl -fsSL https://skills.taituai.com/api/skills/clawskills%3Ajackyujun~metric-attribution/file -o metric-attribution.mdGit 仓库获取源码
git clone https://github.com/openclaw/skills/commit/5ea135e4779c46c1058ebf9bad9b6a74e0c5af4a# 指标波动归因诊断 Skill
归因分析的核心目标是回答"指标为什么变了"。这不是单一步骤能完成的任务——它是一个**诊断流程**,需要综合运用多种分析手段,最终汇聚为一个完整的归因结论。
诊断遵循"先定性再定位再找因"的逻辑:先搞清楚变了多少(Step 1),再拆解是哪个业务环节出了问题(Step 2),然后定位到具体的维度和维度值(Step 3),接着关联外部事件寻找根因(Step 4),最后综合所有发现给出结论(Step 5)。
```
┌───────────────────────────────────────────────────────────────┐
│ 归因诊断全流程 │
│ │
│ Step 1 确认波动事实 → 变了多少?跟什么比? │
│ ↓ │
│ Step 2 因子拆解 → 哪个业务环节出了问题?(定性) │
│ ↓ │
│ Step 3 维度归因 → 问题环节在哪些维度上集中?(定位) │
│ ↓ ↘ 发现集中点 → 继续下钻到更细维度 │
│ Step 4 外部事件关联 → 天气?节假日?竞对?行业政策?(找因) │
│ ↓ │
│ Step 5 综合诊断结论 → 汇总所有发现,输出归因报告 │
│ │
│ * 并非每次都需走完全部步骤,根据复杂度灵活调整 │
│ * 每步的发现逐步积累,最终在 Step 5 统一收口 │
└───────────────────────────────────────────────────────────────┘
```
**为什么先因子拆解(Step 2)再维度归因(Step 3)?**
因子拆解回答的是"哪个环节坏了"(流量?转化?客单价?),维度归因回答的是"在哪里坏了"(哪个渠道?哪个地区?)。先知道是哪个环节出了问题,维度归因才有方向——不用对着总指标盲扫所有维度,而是针对问题因子精准下钻。
举例:GMV 下降 10%。如果直接做维度归因,你可能发现"Retail 渠道贡献了 70% 的下降",但还是不知道 Retail 是流量少了还是转化差了。如果先做因子拆解,发现"转化率下降是主因",再对转化率做维度归因,直接就定位到"Retail 渠道的转化率环比降了 18%"。每一步都在收窄范围,效率高得多。
当然,如果指标没有明确的业务公式可以拆解(Step 2 不适用),直接跳到 Step 3 做维度归因即可。
---
## 0. 接口信息(复用 Gateway API)
本 Skill 复用 metric-query 的 Gateway API 体系。所有 API 调用规则与 metric-query 完全一致。
### Gateway 搜索 API(检索指标和维度)
**搜索指标**: GET `https://gateway.can.aloudata.com/api/metrics/search?keyword={关键词,可逗号分隔}&pageSize={数量}`
**单指标维度**: GET `https://gateway.can.aloudata.com/api/metrics/{metricName}/dimensions?keyword={可选过滤词,支持逗号分隔多关键词}`
**批量指标维度**: GET `https://gateway.can.aloudata.com/api/metrics/dimensions?metricNames={指标1,指标2}&keyword={可选过滤词,支持逗号分隔多关键词}`
**认证方式**:所有请求必须携带 API Key,通过请求头 `X-API-Key` 传递(也可通过 `?apikey=` 查询参数传递)。未携带或无效 Key 将返回 401。
**调用铁律**:
1. **所有请求必须加 API Key 认证头 `-H "X-API-Key: $CAN_API_KEY"`**,`$CAN_API_KEY` 从环境变量读取(用户需在 `~/.openclaw/.env` 中配置 `CAN_API_KEY=cgk-xxxxxxxx`)
2. URL 中文参数必须 URL 编码,使用 `--data-urlencode` + `-G`
> 示例:
> ```bash
> curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/search?pageSize=5" --data-urlencode "keyword=销售额" -G
> curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/retail_amt/dimensions"
> # 维度多关键词过滤(逗号分隔,匹配任一即返回,匹配范围包括维度名/展示名/描述/维度值样本)
> curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/retail_amt/dimensions" --data-urlencode "keyword=渠道,地区,品牌" -G
> ```
### 指标查询 API(执行数据查询)
**接口**: POST `https://gateway.can.aloudata.com/api/metrics/query`
用 heredoc 传 JSON body(因 timeConstraint 含单引号,禁止用 `-d '...'`):
```bash
curl -X POST "https://gateway.can.aloudata.com/api/metrics/query" \
-H "X-API-Key: $CAN_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<'EOF'
{JSON请求体}
EOF
```
**请求体格式与 metric-query 完全一致**,遵守 metric-query Skill 的全部 9 条铁律和构建规范(包括 NOW() 使用、metricDefinitions 注册、占比/排名陷阱、heredoc 传参等)。
---
## Step 1:确认波动事实
归因的起点是搞清楚"到底变了多少"和"跟什么比"。基准选错,后面全白做。
### 1.1 确定对比基准
| 用户说 | 对比基准 | 实现方式 |
|-------|---------|---------|
| "环比下降了""跟上月比" | 上一周期 | `__sameperiod__mom__` 系列 |
| "同比下降了""跟去年比" | 去年同期 | `__sameperiod__yoy__` 系列 |
| "跟目标差多少""没达标" | 目标值 | 需用户提供目标值,或从系统获取 |
| "为什么降了"(未说基准) | **默认环比** | 推断后与用户确认;若涉及季节性行业,建议同比 |
**当用户未明确基准时**:不要直接假设,先向用户确认。例如:"您说的下降是跟上个月比(环比),还是跟去年同期比(同比)?如果这个行业有明显的季节性,建议用同比来排除季节因素。"
### 1.2 查询总体变化量
通过 Gateway 检索指标后,先查整体变化:
```bash
# 搜索指标
curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/search?pageSize=5" --data-urlencode "keyword=销售额" -G
# 查整体环比变化
curl -X POST "https://gateway.can.aloudata.com/api/metrics/query" \
-H "X-API-Key: $CAN_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<'EOF'
{
"metrics": ["retail_amt", "retail_amt__sameperiod__mom__value", "retail_amt__sameperiod__mom__growthvalue", "retail_amt__sameperiod__mom__growth"],
"timeConstraint": "DateTrunc(['metric_time'], \"MONTH\") = DATEADD(DateTrunc(NOW(), \"MONTH\"), -1, \"MONTH\")"
}
EOF
```
产出:**明确的数字事实**——指标从 X 变到了 Y,变化了 Z(变化率 W%)。后续分析都基于此展开。
### 1.3 观察时间趋势(可选但推荐)
查近几个月趋势,判断是异常波动还是持续趋势:
```json
{
"metrics": ["retail_amt"],
"dimensions": ["metric_time__month"],
"timeConstraint": "DateTrunc(['metric_time'], \"MONTH\") >= DATEADD(DateTrunc(NOW(), \"MONTH\"), -6, \"MONTH\") AND DateTrunc(['metric_time'], \"MONTH\") < DateTrunc(NOW(), \"MONTH\")",
"orders": [{"metric_time__month": "asc"}]
}
```
---
## Step 2:因子拆解(定性——哪个业务环节出了问题)
先弄清楚"是哪个环节坏了",后续的维度归因才有靶子。
### 2.1 判断是否适用
因子拆解的前提是指标有明确的业务公式。**如果有公式,必须先做这一步**;如果没有,直接跳到 Step 3。
**常见拆解公式**:
| 复合指标 | 拆解公式 | 因子含义 |
|---------|---------|---------|
| GMV / 销售额 | UV × 转化率 × 客单价 | 流量 × 转化 × 价格 |
| 销售额 | 购买人数 × 客单价 | 客数 × 价格 |
| 销售额 | 订单数 × 件单价 × 连带率 | 订单量 × 价格 × 购买深度 |
| 利润 | 收入 - 成本 | 收入端 vs 成本端 |
如果用户没有明确给出公式,根据业务常识推断并与用户确认。例如用户问"GMV 为什么降了",可以主动提议:"我来按 UV × 转化率 × 客单价 拆解看看是哪个环节的问题?"
### 2.2 获取因子数据
通过 Gateway 搜索各因子对应的指标,然后查询当期和基准期的值:
```bash
# 搜索相关因子指标
curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/search?pageSize=10" --data-urlencode "keyword=UV,转化率,客单价,购买人数" -G
```
```json
{
"metrics": ["visitor_cnt", "buyer_cnt", "AOV",
"visitor_cnt__sameperiod__mom__value",
"buyer_cnt__sameperiod__mom__value",
"AOV__sameperiod__mom__value"],
"timeConstraint": "DateTrunc(['metric_time'], \"MONTH\") = DATEADD(DateTrunc(NOW(), \"MONTH\"), -1, \"MONTH\")"
}
```
如果某些因子没有直接对应的指标,用 metricDefinitions + expr 计算:
```json
"metricDefinitions": {
"cvr": { "expr": "[buyer_cnt]/[visitor_cnt]" }
}
```
### 2.3 计算因子贡献
**乘法公式 Y = A × B × C**:
当各因子变化率较小(均 < 20%)时,可用近似法:
```
ΔY% ≈ ΔA% + ΔB% + ΔC% + 交叉项
A 对 Y 的贡献 ≈ ΔA% / ΔY%
```
当变化率较大时,使用 **Shapley 值分解**确保精确性:
```python
import itertools, math
def shapley_decomposition(factors_base, factors_current):
"""
factors_base: dict, 如 {"UV": 10000, "CVR": 0.05, "AOV": 200}
factors_current: dict, 如 {"UV": 12000, "CVR": 0.045, "AOV": 210}
返回各因子对总变化量的 Shapley 贡献
"""
factor_names = list(factors_base.keys())
n = len(factor_names)
contributions = {}
for name in factor_names:
shapley_val = 0
others = [fn for fn in factor_names if fn != name]
for subset_size in range(n):
for subset in itertools.combinations(others, subset_size):
subset_set = set(subset)
val_with, val_without = 1, 1
for fn in factor_names:
if fn == name:
val_with *= factors_current[fn]
val_without *= factors_base[fn]
elif fn in subset_set:
val_with *= factors_current[fn]
val_without *= factors_current[fn]
else:
val_with *= factors_base[fn]
val_without *= factors_base[fn]
weight = math.factorial(subset_size) * math.factorial(n - subset_size - 1) / math.factorial(n)
shapley_val += weight * (val_with - val_without)
contributions[name] = shapley_val
return contributions
```
**加法公式 Y = A + B + C**:直接看各项的变化量即可,无需复杂分解。
**加法 + 乘法混合**:先按加法拆,再对乘法项分别做 Shapley。
### 2.4 瀑布图可视化
因子拆解的结果用**瀑布图(Waterfall Chart)**呈现最为直观——起点是基准值,终点是当期值,中间每一段代表一个因子的贡献量,正向贡献向上(绿色),负向贡献向下(红色),一眼就能看出哪个环节拖了后腿、哪个环节在撑场。
使用 Python + matplotlib 生成瀑布图:
```python
import matplotlib.pyplot as plt
import matplotlib
matplotlib.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
matplotlib.rcParams['axes.unicode_minus'] = False
def waterfall_chart(factors, contributions, base_value, current_value, title, save_path):
"""
factors: list, 因子名称列表,如 ["UV", "转化率", "客单价", "交叉项"]
contributions: list, 各因子的贡