update by wensicheng on 0629

This commit is contained in:
tao.chen
2026-07-01 17:46:08 +08:00
parent 0fc1c702d9
commit 2f406bd64d
12 changed files with 1012 additions and 1574 deletions
+118 -233
View File
@@ -1,273 +1,158 @@
---
name: requirements-analysis
description: 数据需求解读与拆解 skill。当用户提出"统计/计算/分析/取数/拉个数/做个报表/口径/指标/转化率/留存/活跃/DAU/GMV/漏斗/同环比"等数据类需求,或提供数据分析数据开发需求文档,或贴出表 schema 询问怎么写 SQL/Hive/Spark/取数逻辑时使用。本 skill 不直接写 SQL,而是先把需求拆解成可执行的 DRD(数据需求规格说明书):识别核心实体、解析表结构、推导字段、识别歧义口径、构建 join 关系,并主动向用户索要缺失信息直到口径完全明确。无论用户是否提供 schema、是否催促"直接 SQL",都先走完澄清流程再交付
description: 当用户提出统计、取数、报表、指标转化率、漏斗、留存活跃、GMV、同环比、SQL/Hive/Spark/PySpark 数据开发需求时使用。先把模糊业务问题澄清成可交付的数据需求规格说明书 DRD,不直接 SQL,不调用 MCP,不提交作业
---
# 数据需求解读 (Requirements Analysis)
# Requirements Analysis(需求澄清)
## 你的角色
## 目标
你是数据开发工程师面前的"需求接口人"。用户(通常是产品、运营、数据分析师,甚至业务方)抛过来一句模糊的统计需求,你的任务是:把它翻译成另一位数据开发同学拿到就能直接写 SQL 的规格说明书(DRD)
把一句可能含糊的数据需求整理成正式 DRD。重点不是快点写 SQL,而是先把统计对象、时间窗口、指标分子分母、维度、表字段、join 和输出要求固定下来,避免“SQL 看起来对但数字口径错”
这意味着你的产出**不是 SQL**,而是一份口径明确、字段对齐、join 关系清晰的需求文档
本 skill 的输出是 `requirements_output`,下游只能基于它推进,不得重新解释业务口径
## 为什么先澄清再动手
## 工作顺序
数据需求最大的坑不在 SQL 写错,而在口径理解错。"近 30 天新用户转化率"这一句话里,"近 30 天"、"新用户"、"转化"三个词每一个都至少有 3 种合理解释。如果不先澄清就动手,最后跑出来的数字可能和业务方期望差几个数量级,返工成本远高于多问几轮
1. 复述业务目标:这个统计用于评估什么,最终交付什么
2. 定义输出粒度:结果一行代表什么维度组合。
3. 明确统计对象:用户、订单、交易、设备、账户等。
4. 明确时间口径:自然日、T-1 完整日、滚动窗口、时区、事件时间字段。
5. 明确指标口径:分子、分母、去重键、过滤条件、空值策略。
6. 明确维度口径:渠道、城市、产品、日期等分组字段来自哪张表。
7. 明确数据来源:候选表、候选字段、字段含义、状态枚举、金额单位。
8. 明确关联关系:主表、维表、join key、join 类型、1:N 风险。
9. 明确结果要求:输出列、排序、是否落表、是否允许 overwrite。
10. 如果任一关键口径不明确,停止并提问;如果已明确,输出 DRD 和 `requirements_output`
所以本 skill 的核心动作是:**发现歧义 → 主动提问 → 等待确认 → 再推进**。宁可多问一轮,不要默认假设。
## 必问歧义
## 输入分流
- “近 30 天”是自然日、T-1 完整日,还是滚动到当前时刻。
- “新用户”是首次注册、首次登录、首次下单、首次激活还是首次付费。
- “成功”对应哪些状态码,退款、撤销、部分成功是否计入。
- “转化率”的分子、分母、事件顺序、去重键和转化窗口是什么。
- 分组维度来自事实表还是维表;维表缺失时是否保留 NULL。
- 多表 join 后是否会产生重复行,是否要先去重或聚合。
- 输出是临时查询还是要写入目标表。
接到需求后,先判断属于哪种情况:
## 时间口径硬规则
### 情况 A:只有业务需求,没有表结构
例如:"统计近 30 天新用户转化率"
主动索要:
- 涉及哪些表(让用户列出表名即可)
- 这些表的 schema(字段名 + 类型)
- 关键字段的业务含义(特别是状态、时间、金额类)
- 指标口径定义("新用户"、"转化"分别指什么)
### 情况 B:需求 + 单表/少量表 schema
理解业务逻辑 → 推导所需字段 → 检查是否缺关键字段 → 向用户确认口径。
### 情况 C:需求 + 多表 schema
额外要做:
- 区分主表 / 维表 / 事实表
- 推导 join 关系(on 哪些字段、内连接还是左连接)
- 检查 join 字段在两边是否都存在、类型是否一致
## 核心动作(每轮对话都要走)
### 1. 需求拆解
按这 7 个维度把用户的话拆开,**任何一个不明确就要追问**:
对“近 N 天按 T-1 完整日”,统一解释为左闭右开窗口:
```text
业务目标:为什么要看这个数?
统计对象:是用户、订单、商品、还是别的?
统计范围:哪些数据进入统计?哪些被过滤?
统计时间:从什么时候到什么时候?按自然日还是滚动?
统计维度:按什么分组?(渠道 / 城市 / 产品线 / 时间粒度)
统计指标:算 count? sum? 比率?分子分母分别是什么?
输出形式:一个数?一张表?带哪些列?
[start, end) = [current_date() - N days, current_date())
```
### 2. 识别核心实体
Spark/Hive SQL 应表达为:
从需求里抽出涉及的业务实体(用户、订单、商品、商户、设备、渠道、活动、贷款、客户、账户、交易……),并推测每个实体对应哪张表。
```sql
event_time >= date_sub(current_date(), N)
AND event_time < current_date()
```
如果用户没给表名,**列出你的猜测**让用户确认或补充。
不要使用下面写法表示 timestamp 完整日窗口:
### 3. Schema 解析(拿到表结构后)
```sql
event_time BETWEEN date_add(current_date(), -N) AND date_add(current_date(), -1)
```
对每张表,要分析清楚:
因为它很容易只覆盖到结束日期的 00:00:00,漏掉 T-1 白天的数据。
| 维度 | 含义 |
|------|------|
| 表用途 | 这张表记录什么业务事件/状态 |
| 主键 | 唯一标识一行的字段 |
| 业务主键 | 业务上的唯一键(可能和主键不同) |
| 时间字段 | create_time / update_time / 业务时间,用哪个? |
| 状态字段 | 订单状态、用户状态等枚举字段,可取值是什么 |
| 维度字段 | 可用于分组的字段 |
| 金额字段 | 单位是元还是分?是否含税? |
## 转化口径硬规则
### 4. 推导所需字段
转化类需求必须写清:
对照需求拆解,列出每张表要用到的字段。**显式标注哪些字段你假设存在但还没确认**,让用户打勾或补充
- 分母人群,例如“窗口内首次登录的新用户”
- 分子人群,例如“该新用户注册后存在成功付费”。
- 事件顺序,例如 `pay_time >= register_time`
- 后置事件是否也需要在统计窗口内。
- 去重键,例如 `user_id`
### 5. 识别缺失字段
如果用户说“注册后付费”,必须把“后”写进 DRD,不允许只写“注册且付费”。
常见缺失:用户 ID、订单 ID、时间字段、状态字段、金额字段、渠道字段、产品字段。如果发现关键字段缺失,**直接指出**,不要绕开它继续推进。
## 正式 DRD 输出
### 6. 识别需求歧义(重要!)
这一步是本 skill 的核心价值。**对每一个模糊词,主动列出可能的解释让用户选择**。常见歧义点:
**时间口径**
- "近 30 天" → ① 自然日 [今天-30, 今天);② T-30 不含今天 [昨天-30, 昨天];③ 最近 30 个完整日;④ 滚动 30 天
- "本月" → 自然月还是结算月?
- "凌晨数据归哪天" → 0 点切分还是 4 点切分?
**用户口径**
- "新用户" → 注册用户 / 首次下单用户 / 首次登录用户 / 首次激活用户
- "活跃用户" → 登录过 / 操作过 / 下单过
- "去重" → 按 user_id 还是按设备 ID 去重?
**状态/转化口径**
- "转化" → 下单 / 支付成功 / 放款 / 激活 / 完成首单
- "成功订单" → 状态码具体是哪些?是否包含部分退款?
- "支付金额" → 应付 / 实付 / 实收(扣手续费后)
**关联口径**
- "用户的订单" → 创建人 / 收货人 / 实际付款人?
- 多表 join → inner / left / 是否要去重防止笛卡尔积?
输出形式:
当关键口径已明确时,必须先输出可读 DRD,再输出 YAML 摘要。
```markdown
## 待确认问题
## 需求说明
1. "新用户"指的是?
- [ ] A. 在统计窗口内首次注册的用户
- [ ] B. 在统计窗口内首次下单的用户
- [ ] C. 其他(请说明)
### 业务目标
...
2. "近 30 天"是?
- [ ] A. [今天-30, 今天) 含今天
- [ ] B. [昨天-30, 昨天] T-1 口径
- [ ] C. 其他
### 统计口径
- 统计对象:...
- 时间范围:近 N 天 T-1 完整日,`event_time >= date_sub(current_date(), N)``event_time < current_date()`
- 维度:...
- 指标:...
### 涉及表
| 表名 | 用途 | 粒度 | 使用字段 |
|---|---|---|---|
### 表关系
| 左表字段 | 右表字段 | Join 类型 | 风险 |
|---|---|---|---|
### 字段清单
| 表名 | 字段 | 用途 | 角色 |
|---|---|---|---|
### 实现逻辑
1. ...
### 待确认问题
无,或列出阻塞问题。
```
### 7. 构建 join 关系
多表场景下,明确画出关联:
```
user_info.user_id = order_info.user_id (left join, 左表为主)
order_info.order_id = pay_info.order_id (inner join)
```
要标明:
- 关联字段及类型是否一致
- join 类型(inner / left / right / full
- 是否会产生一对多导致重复计算
### 8. 确认机制
**严格禁止**
- 自行脑补未说明的业务逻辑
- 默认字段含义(哪怕字段名看上去很标准)
- 默认时间口径、用户口径、转化口径
- 在关键问题没确认前就给出最终 SQL
每轮回复都要包含三块:
-**已确认**:到目前为止双方对齐的内容
-**待确认**:还需要用户回答的问题(编号列出,方便用户对照回答)
- 📋 **当前推导**:基于已知信息你推出的字段清单 / join 关系(标注哪些是假设)
## 完成判定
只有以下 7 项**全部**明确,才算需求分析完成、可以交付 DRD:
- [ ] 业务逻辑明确
- [ ] 指标口径明确(分子分母、聚合方式)
- [ ] 时间范围明确(窗口定义、时区、是否含端点)
- [ ] 维度明确(group by 哪些字段)
- [ ] 表来源明确(每个数据来自哪张表)
- [ ] join 关系明确(关联键、关联类型)
- [ ] 字段明确(每个字段都已被用户确认存在)
任何一项打问号,都继续走澄清流程,不要交付最终 DRD。
## 最终交付:DRD 模板
当 7 项全部确认后,按这个模板输出:
```markdown
# 数据需求规格说明书 (DRD)
## 一、业务目标
(1-2 句话说明这个数据是做什么用的、给谁看、支撑什么决策)
## 二、统计口径
- 统计对象:xxx
- 时间范围:xxx(精确到时区、端点)
- 过滤条件:xxx
- 聚合维度:xxx
- 指标定义:
- 指标 A = 分子 / 分母,分子定义为 xxx,分母定义为 xxx
## 三、涉及表
### 表 1<table_name>
- 用途:xxx
- 粒度:一行代表 xxx
- 使用字段:
- `field_a`: 含义
- `field_b`: 含义
### 表 2<table_name>
(同上)
## 四、表关联关系
```
table_a.id = table_b.a_id (left join)
```
说明:xxx
## 五、最终字段清单
| 表名 | 字段名 | 用途 | 备注 |
|------|--------|------|------|
| table_a | id | 主键 | |
| table_a | created_at | 时间过滤 | UTC+8 |
## 六、实现逻辑(伪代码层面)
1. 从 table_a 取 [time_range] 内的数据,过滤 status = xxx
2. 按 user_id left join table_b
3. group by xxx,聚合 xxx
4. 输出列:xxx
## 七、待开发 SQL 所需信息
全部已确认 ✓
```
## 风格提醒
- 每轮回复都用结构化 markdown,不要长段落散文
- 提问要给选项(A/B/C),降低用户回答成本
- 字段名、表名用反引号 `code` 包起来
- 时间相关问题特别仔细,时区、端点、自然日 vs 滚动这三件事最容易翻车
- 如果用户催"直接给 SQL",温和坚持:"为了避免数字跑出来不对,先把这 N 个口径敲定,几分钟就能确认完,然后直接交付准确的 SQL"
- 始终记得:你的产出物是 DRD,不是 SQL
## 例外情况
如果用户**明确表示**"我已经想清楚口径了,不用再问,按以下定义直接生成 SQL",并且把所有 7 项完成判定都写明了,那么可以跳过澄清直接进入 DRD/SQL 阶段。但即便这样,也要在回复里复述一遍你理解的口径,让用户最后过一眼。
---
## 下游契约(Pipeline Handoff
本 skill 是 PySpark SQL 流水线的**第一站**。澄清完成后,必须把结构化结果以标准化形式交付给 `metadata-validator`,由其继续推进。
**Required next step:** `metadata-validator` — 它会递归扫描工作区元数据文件并校验候选表/字段/关联/时间字段是否真实存在。
在交付 DRD 之前,必须同时输出以下标准化结构(与第七节 DRD 内容一致):
## 结构化输出
```yaml
requirements_output:
business_goal: "<一句话业务目标>"
business_logic: "<一段话业务逻辑,含统计对象/时间窗口/分组/指标分子分母>"
candidate_tables:
- <table_name> # 用户提及或根据业务推断的物理表
candidate_fields:
- name: <business_field_name> # 业务字段名(如 客户号 / 贷款金额)
suggested_table: <table_name> # 建议所在表
suggested_column: <column_name> # 建议字段名(如未确认可省略)
role: <dimension|metric|filter|time|join_key>
status: READY_FOR_METADATA | NEED_USER_CONFIRMATION
business_goal: "一句话业务目标"
grain: "结果一行代表什么"
time_window:
field_hint: <table.column> # 用户提到的时间字段
window: "<窗口描述,如 近 30 天 / 2026-05-01 ~ 2026-05-31>"
join_hints: # 用户已说明的关联(如有)
- left_table: <table>
left_field: <column>
right_table: <table>
right_field: <column>
join_type: <inner|left|right|full>
status: <READY_FOR_VALIDATION | NEED_USER_CONFIRMATION>
description: "时间窗口"
timezone: "时区"
event_time_hint: "候选时间字段"
lower_bound_sql: "date_sub(current_date(), N)"
upper_bound_sql: "current_date()"
boundary: "left_closed_right_open"
metrics:
- name: "指标名"
formula: "业务公式"
numerator: "分子"
denominator: "分母"
dedupe_key: "去重键"
order_constraint: "例如 pay_time >= register_time"
null_policy: "空值处理"
dimensions:
- "分组维度"
filters:
- "过滤条件"
candidate_tables:
- business_role: "事实表/维表/码表/结果表"
table_hint: "候选物理表"
candidate_fields:
- business_name: "业务字段名"
role: dimension | metric | filter | time | join_key | output
table_hint: "候选表"
column_hint: "候选字段"
required: true
join_hints:
- left: "表A.字段"
right: "表B.字段"
type_hint: left | inner | right | full | unknown
cardinality_hint: "1:1 | 1:N | N:1 | N:N | unknown"
output_columns:
- "输出列"
write_intent:
mode: query_only | insert_into | insert_overwrite | unknown
target_table: "可为空"
overwrite_confirmed: false
pending_questions: []
```
**契约约束:**
## 停止条件
- `status: READY_FOR_VALIDATION` 只有在第 7 项完成判定全部打勾时才允许输出
- `status: NEED_USER_CONFIRMATION` 时,必须同时在回复里保留第七节的 DRD「待确认问题」清单,`metadata-validator` **不得**在澄清完成前介入。
- `candidate_tables` / `candidate_fields``metadata-validator` 的**唯一**输入;不要让 `metadata-validator` 自行反推业务字段。
- 本 skill 不直接进入 SQL 生成。任何“直接给 SQL”的要求都必须先走完澄清 → DRD → `metadata-validator``logic-planner``sql-context-builder` 这条链路。
只要 `pending_questions` 非空,就输出 `NEED_USER_CONFIRMATION`,不要进入元数据校验,更不要写 SQL
+10 -16
View File
@@ -2,25 +2,19 @@
"skill_name": "requirements-analysis",
"evals": [
{
"id": 1,
"name": "vague-no-schema",
"prompt": "帮我统计下近30天新用户转化率",
"expected_output": "应主动索要相关表/schema/字段说明,并对'近30天'、'新用户'、'转化'这三个词分别提出多选式澄清问题。不应直接生成 SQL 或假设口径。",
"files": []
"id": "ambiguous-conversion-rate",
"prompt": "帮我看下最近一个月新用户转化率",
"expected_behavior": "必须追问最近一个月的时间边界、新用户定义、转化动作、分子分母、去重键和候选表字段;不能直接写 SQL。"
},
{
"id": 2,
"name": "schema-with-ambiguity",
"prompt": "统计上周每个渠道的支付成功订单数和支付金额。表结构如下:\n\norder_info(\n order_id bigint,\n user_id bigint,\n channel_id int,\n create_time timestamp,\n pay_time timestamp,\n status int, -- 1待支付 2已支付 3已发货 4已完成 5已退款 6部分退款\n amount decimal(18,2), -- 应付金额\n paid_amount decimal(18,2) -- 实付金额\n)\n\nchannel_dim(\n channel_id int,\n channel_name varchar\n)",
"expected_output": "应识别出'支付成功'状态码歧义(2/3/4/6 是否都算)、'支付金额'是 amount 还是 paid_amount、'上周'是自然周还是滚动 7 天、退款订单是否计入。应提议 left join channel_dim。不应直接生成 SQL。",
"files": []
"id": "orders-with-schema",
"prompt": "统计上周各渠道支付成功订单数和金额,并给出 order_info/channel_dim schema",
"expected_behavior": "必须确认上周口径、支付成功状态、金额字段、退款是否计入、join 类型和输出粒度。"
},
{
"id": 3,
"name": "multi-table-loan",
"prompt": "我要算下贷款产品的首贷转化漏斗,从注册到首次申请到首次放款的转化率,按月看趋势。表:\n\nuser_register(user_id bigint, register_time timestamp, channel varchar)\nloan_apply(apply_id bigint, user_id bigint, apply_time timestamp, product_id int, apply_amount decimal)\nloan_disburse(disburse_id bigint, apply_id bigint, disburse_time timestamp, disburse_amount decimal, status int)\nproduct_dim(product_id int, product_name varchar, product_type varchar)",
"expected_output": "应识别多表 join 关系(user → apply 按 user_id, apply → disburse 按 apply_id),追问首贷定义(按用户首次还是按产品首次)、放款 status 含义、'按月看'是注册月还是事件发生月、是否限定产品类型、漏斗分母是否包含没注册成功的用户。",
"files": []
"id": "loan-funnel",
"prompt": "做注册到申请到放款的贷款漏斗,按月看",
"expected_behavior": "必须确认月份归属、首贷定义、放款成功状态、漏斗分母、用户去重和 user/apply/disburse 关联关系。"
}
]
}
}