--- name: requirements-analysis description: 当用户提出统计、取数、报表、指标、转化率、漏斗、留存、活跃、GMV、同环比、SQL/Hive/Spark/PySpark 数据开发需求时使用。先把模糊业务问题澄清成可交付的数据需求规格说明书 DRD,不直接写 SQL,不调用 MCP,不提交作业。 --- # Requirements Analysis(需求澄清) ## 目标 把一句可能含糊的数据需求整理成正式 DRD。重点不是快点写 SQL,而是先把统计对象、时间窗口、指标分子分母、维度、表字段、join 和输出要求固定下来,避免“SQL 看起来对但数字口径错”。 本 skill 的输出是 `requirements_output`,下游只能基于它推进,不得重新解释业务口径。 ## 工作顺序 1. 复述业务目标:这个统计用于评估什么,最终交付什么。 2. 定义输出粒度:结果一行代表什么维度组合。 3. 明确统计对象:用户、订单、交易、设备、账户等。 4. 明确时间口径:自然日、T-1 完整日、滚动窗口、时区、事件时间字段。 5. 明确指标口径:分子、分母、去重键、过滤条件、空值策略。 6. 明确维度口径:渠道、城市、产品、日期等分组字段来自哪张表。 7. 明确数据来源:候选表、候选字段、字段含义、状态枚举、金额单位。 8. 明确关联关系:主表、维表、join key、join 类型、1:N 风险。 9. 明确结果要求:输出列、排序、是否落表、是否允许 overwrite。 10. 如果任一关键口径不明确,停止并提问;如果已明确,输出 DRD 和 `requirements_output`。 ## 必问歧义 - “近 30 天”是自然日、T-1 完整日,还是滚动到当前时刻。 - “新用户”是首次注册、首次登录、首次下单、首次激活还是首次付费。 - “成功”对应哪些状态码,退款、撤销、部分成功是否计入。 - “转化率”的分子、分母、事件顺序、去重键和转化窗口是什么。 - 分组维度来自事实表还是维表;维表缺失时是否保留 NULL。 - 多表 join 后是否会产生重复行,是否要先去重或聚合。 - 输出是临时查询还是要写入目标表。 ## 时间口径硬规则 对“近 N 天按 T-1 完整日”,统一解释为左闭右开窗口: ```text [start, end) = [current_date() - N days, current_date()) ``` Spark/Hive SQL 应表达为: ```sql event_time >= date_sub(current_date(), N) AND event_time < current_date() ``` 不要使用下面写法表示 timestamp 完整日窗口: ```sql event_time BETWEEN date_add(current_date(), -N) AND date_add(current_date(), -1) ``` 因为它很容易只覆盖到结束日期的 00:00:00,漏掉 T-1 白天的数据。 ## 转化口径硬规则 转化类需求必须写清: - 分母人群,例如“窗口内首次登录的新用户”。 - 分子人群,例如“该新用户注册后存在成功付费”。 - 事件顺序,例如 `pay_time >= register_time`。 - 后置事件是否也需要在统计窗口内。 - 去重键,例如 `user_id`。 如果用户说“注册后付费”,必须把“后”写进 DRD,不允许只写“注册且付费”。 ## 正式 DRD 输出 当关键口径已明确时,必须先输出可读 DRD,再输出 YAML 摘要。 ```markdown ## 需求说明 ### 业务目标 ... ### 统计口径 - 统计对象:... - 时间范围:近 N 天 T-1 完整日,`event_time >= date_sub(current_date(), N)` 且 `event_time < current_date()` - 维度:... - 指标:... ### 涉及表 | 表名 | 用途 | 粒度 | 使用字段 | |---|---|---|---| ### 表关系 | 左表字段 | 右表字段 | Join 类型 | 风险 | |---|---|---|---| ### 字段清单 | 表名 | 字段 | 用途 | 角色 | |---|---|---|---| ### 实现逻辑 1. ... ### 待确认问题 无,或列出阻塞问题。 ``` ## 结构化输出 ```yaml requirements_output: status: READY_FOR_METADATA | NEED_USER_CONFIRMATION business_goal: "一句话业务目标" grain: "结果一行代表什么" time_window: 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: [] ``` ## 停止条件 只要 `pending_questions` 非空,就输出 `NEED_USER_CONFIRMATION`,不要进入元数据校验,更不要写 SQL。