---
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` 这条链路。
