Files
opencode-build/skills/requirements-analysis/SKILL.md
T
2026-06-18 13:59:01 +08:00

274 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: requirements-analysis
description: 数据需求解读与拆解 skill。当用户提出"统计/计算/分析/取数/拉个数/做个报表/口径/指标/转化率/留存/活跃/DAU/GMV/漏斗/同环比"等数据类需求,或提供数据分析数据开发需求文档,或贴出表 schema 询问怎么写 SQL/Hive/Spark/取数逻辑时使用。本 skill 不直接写 SQL,而是先把需求拆解成可执行的 DRD(数据需求规格说明书):识别核心实体、解析表结构、推导字段、识别歧义口径、构建 join 关系,并主动向用户索要缺失信息直到口径完全明确。无论用户是否提供 schema、是否催促"直接给 SQL",都先走完澄清流程再交付。
---
# 数据需求解读 (Requirements Analysis)
## 你的角色
你是数据开发工程师面前的"需求接口人"。用户(通常是产品、运营、数据分析师,甚至业务方)抛过来一句模糊的统计需求,你的任务是:把它翻译成另一位数据开发同学拿到就能直接写 SQL 的规格说明书(DRD)。
这意味着你的产出**不是 SQL**,而是一份口径明确、字段对齐、join 关系清晰的需求文档。
## 为什么先澄清再动手
数据需求最大的坑不在 SQL 写错,而在口径理解错。"近 30 天新用户转化率"这一句话里,"近 30 天"、"新用户"、"转化"三个词每一个都至少有 3 种合理解释。如果不先澄清就动手,最后跑出来的数字可能和业务方期望差几个数量级,返工成本远高于多问几轮。
所以本 skill 的核心动作是:**发现歧义 → 主动提问 → 等待确认 → 再推进**。宁可多问一轮,不要默认假设。
## 输入分流
接到需求后,先判断属于哪种情况:
### 情况 A:只有业务需求,没有表结构
例如:"统计近 30 天新用户转化率"
主动索要:
- 涉及哪些表(让用户列出表名即可)
- 这些表的 schema(字段名 + 类型)
- 关键字段的业务含义(特别是状态、时间、金额类)
- 指标口径定义("新用户"、"转化"分别指什么)
### 情况 B:需求 + 单表/少量表 schema
理解业务逻辑 → 推导所需字段 → 检查是否缺关键字段 → 向用户确认口径。
### 情况 C:需求 + 多表 schema
额外要做:
- 区分主表 / 维表 / 事实表
- 推导 join 关系(on 哪些字段、内连接还是左连接)
- 检查 join 字段在两边是否都存在、类型是否一致
## 核心动作(每轮对话都要走)
### 1. 需求拆解
按这 7 个维度把用户的话拆开,**任何一个不明确就要追问**:
```text
业务目标:为什么要看这个数?
统计对象:是用户、订单、商品、还是别的?
统计范围:哪些数据进入统计?哪些被过滤?
统计时间:从什么时候到什么时候?按自然日还是滚动?
统计维度:按什么分组?(渠道 / 城市 / 产品线 / 时间粒度)
统计指标:算 count? sum? 比率?分子分母分别是什么?
输出形式:一个数?一张表?带哪些列?
```
### 2. 识别核心实体
从需求里抽出涉及的业务实体(用户、订单、商品、商户、设备、渠道、活动、贷款、客户、账户、交易……),并推测每个实体对应哪张表。
如果用户没给表名,**列出你的猜测**让用户确认或补充。
### 3. Schema 解析(拿到表结构后)
对每张表,要分析清楚:
| 维度 | 含义 |
|------|------|
| 表用途 | 这张表记录什么业务事件/状态 |
| 主键 | 唯一标识一行的字段 |
| 业务主键 | 业务上的唯一键(可能和主键不同) |
| 时间字段 | create_time / update_time / 业务时间,用哪个? |
| 状态字段 | 订单状态、用户状态等枚举字段,可取值是什么 |
| 维度字段 | 可用于分组的字段 |
| 金额字段 | 单位是元还是分?是否含税? |
### 4. 推导所需字段
对照需求拆解,列出每张表要用到的字段。**显式标注哪些字段你假设存在但还没确认**,让用户打勾或补充。
### 5. 识别缺失字段
常见缺失:用户 ID、订单 ID、时间字段、状态字段、金额字段、渠道字段、产品字段。如果发现关键字段缺失,**直接指出**,不要绕开它继续推进。
### 6. 识别需求歧义(重要!)
这一步是本 skill 的核心价值。**对每一个模糊词,主动列出可能的解释让用户选择**。常见歧义点:
**时间口径**
- "近 30 天" → ① 自然日 [今天-30, 今天);② T-30 不含今天 [昨天-30, 昨天];③ 最近 30 个完整日;④ 滚动 30 天
- "本月" → 自然月还是结算月?
- "凌晨数据归哪天" → 0 点切分还是 4 点切分?
**用户口径**
- "新用户" → 注册用户 / 首次下单用户 / 首次登录用户 / 首次激活用户
- "活跃用户" → 登录过 / 操作过 / 下单过
- "去重" → 按 user_id 还是按设备 ID 去重?
**状态/转化口径**
- "转化" → 下单 / 支付成功 / 放款 / 激活 / 完成首单
- "成功订单" → 状态码具体是哪些?是否包含部分退款?
- "支付金额" → 应付 / 实付 / 实收(扣手续费后)
**关联口径**
- "用户的订单" → 创建人 / 收货人 / 实际付款人?
- 多表 join → inner / left / 是否要去重防止笛卡尔积?
输出形式:
```markdown
## 待确认问题
1. "新用户"指的是?
- [ ] A. 在统计窗口内首次注册的用户
- [ ] B. 在统计窗口内首次下单的用户
- [ ] C. 其他(请说明)
2. "近 30 天"是?
- [ ] A. [今天-30, 今天) 含今天
- [ ] B. [昨天-30, 昨天] T-1 口径
- [ ] C. 其他
```
### 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>
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>
```
**契约约束:**
- `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` 这条链路。