Skip to content

第三章 需求定义与 SOW ​

3.4 指标口径公式与语义注册 ​

承前:上一节 SOW 模板里埋了一个钩子——附录 A"指标口径公式"。这是 FDE 圈子里心照不宣的一条铁律:需求文档里最容易被跳过、交付时最常炸雷的部分,恰恰是指标口径。青禾优选三个部门报出三个会员数(80 万、120 万、76 万),问题不在数据存储,在口径。这一节我们用"90 天会员复购率"一个指标,把口径定义拆到分子分母级,落到 SQL,再讲怎么把它注册进 Agent 底座的指标语义扩展接口,让 Agent 的每一句话都长在同一个口径上。


3.4.1 口径是怎么变成连环雷的 ​

先看青禾的三个会员数是怎么来的:

  • 营销部门报 120 万:统计口径是"历史累计注册手机号",包括从未到店消费的、一人多号的、门店扫码送礼拉来的;
  • 会员系统报 80 万:口径是"当前有效会员卡",但包含了大量员工测试卡和已注销未清除的卡;
  • 财务报 76 万:口径是"本年度有付费行为且完成实名"。

三个数都对——在各自的口径下都对。灾难在于没有人把口径写下来,每个汇报的人都默认"会员数"这个词只有一个含义。

这类问题的杀伤力在 Agent 项目里会放大十倍:Agent 要基于"沉睡会员"发短信,如果"沉睡"的口径没定,工程按"180 天未消费"实现,运营按"90 天未消费"预期,上线第一天就会爆发"你们把活跃会员当沉睡会员打扰了"的事故。数字时代这类问题早已被数据团队系统研究过——dbt 语义层等工具的核心理念就是"指标定义一次、处处复用",但工具解决不了人没想清楚的问题。口径必须先由 FDE 主持定义,再交给工具固化。

3.4.2 一个完整口径的五要素 ​

一个能进 SOW 附录的指标口径,必须写满五要素:

一、分子分母的业务定义。 复购率的朴素说法是"老客户又来买的比例",但要写成可执行的定义:

指标:90 天会员复购率(试点门店群)

分母 = 观察期开始前 90 天内,在试点门店群
       有 ≥1 次有效消费的会员数
分子 = 上述分母中的会员,在观察期内
       (连续 90 天)又有 ≥1 次有效消费的会员数

有效消费 = 单笔实付金额 > 0,剔除:退货冲销单、
           员工测试订单、内部调拨单

二、时间窗。 "90 天"是滚动窗还是固定观察期?起算点是上次消费日还是月初?每个选择都会改变数值 1-2 个百分点,而第一期承诺的提升目标可能就 1.5 个百分点——时间窗没定,等于验收标准没定。

三、剔除规则。 上面"有效消费"括号里的三条就是剔除规则。再加几条常见的:储值卡消费算不算?用券后 0 元订单算不算?同一手机号多卡怎么去重?这些是口径会议的主要弹药消耗点。

四、数据来源。 分子分母各从哪张表算:订单明细来自 POS 同步库 order_detail,会员主档来自会员系统 member_master,映射关系依赖第 4 章要诊断的"新旧双轨会员 ID 映射表"。

五、刷新频率与责任方。 每日 T+1 计算还是实时?由谁的计算任务产出?数值打架时以哪份为准?给指标指定一个"唯一数据源",是止住"三个部门三个数"的制度性解药。

3.4.3 从口径到 SQL ​

五要素齐了,SQL 才有得写。青禾的复购率参考实现(伪 SQL,表名按沙盘设定):

sql
-- 口径:90天会员复购率(试点门店群,滚动观察期)
WITH valid_orders AS (
    SELECT o.member_id, o.paid_amount, o.order_ts
    FROM pos_sync.order_detail o
    JOIN member.member_master m
      ON o.member_id = m.member_id          -- 依赖双轨ID映射(W4诊断)
    WHERE o.store_id IN (SELECT store_id
                         FROM project.pilot_stores)   -- 试点边界
      AND o.paid_amount > 0
      AND o.order_type NOT IN ('RETURN', 'STAFF_TEST', 'TRANSFER')
      AND o.member_id NOT IN (
          SELECT blacklisted_member_id
          FROM project.metric_exclusions)    -- 剔除规则集中管理
),
denominator AS (
    SELECT COUNT(DISTINCT member_id) AS members
    FROM valid_orders
    WHERE order_ts BETWEEN :base_window_start AND :base_window_end
),
numerator AS (
    SELECT COUNT(DISTINCT v2.member_id) AS members
    FROM valid_orders v2
    WHERE v2.order_ts BETWEEN :obs_window_start AND :obs_window_end
      AND v2.member_id IN (
          SELECT DISTINCT member_id FROM valid_orders
          WHERE order_ts BETWEEN :base_window_start AND :base_window_end)
)
SELECT n.members::FLOAT / d.members AS repurchase_rate_90d,
       d.members AS base_members, n.members AS repeat_members
FROM denominator d CROSS JOIN numerator n;

三个工程细节值得点破:

  • 剔除规则进配置表而不是散在代码里(metric_exclusions)。每加一条剔除规则开一次会、改一行配置、留一条审计日志,而不是改五处 SQL。
  • 双轨 ID 映射显式出现在 JOIN 里。这是把已知的数据风险"钉在明面上":口径文档里要注明"本指标可信度受 ID 映射覆盖率影响,覆盖率为 87%(W4 诊断结论)"。指标带误差条,才是诚实的指标。
  • SQL 本身是交付物。它进 SOW 的附录 A,客户 BI 团队复核口径就是在复核这段 SQL。能被复核的指标定义,才配叫口径。

3.4.4 注册到指标语义扩展接口 ​

口径定了、SQL 能跑了,最后一步是把它注册进 Agent 底座的指标语义层,让 Agent 在生成分析、回答问题、生成报告时引用的是同一份定义。

产品底座(沙盘设定:模型调用、会话、工具注册、日志、trace、评估接口已有)通常提供一个语义扩展接口,形如:

json
{
  "metric_name": "repurchase_rate_90d",
  "display_name": "90天会员复购率(试点门店群)",
  "definition": "基线窗内有效消费会员,在观察窗内再次有效消费的比例",
  "numerator": "观察窗内复购的基线会员数",
  "denominator": "基线窗内有效消费会员数",
  "time_window": "滚动90天基线窗 + 90天观察窗",
  "exclusions": ["退货冲销单", "员工测试订单", "内部调拨单", "黑名单会员"],
  "data_sources": ["pos_sync.order_detail", "member.member_master"],
  "owner": "青禾BI团队-张工(复核方)/ 本项目(定义方)",
  "refresh": "每日 T+1",
  "implementation_ref": "sql/repurchase_rate_90d.sql",
  "known_caveats": "受双轨会员ID映射覆盖率影响,当前覆盖87%"
}

注册之后,语义层给 Agent 的分析工具挂上这把"标尺":Agent 回答"试点门店复购率"时,查询走注册的 SQL,表述用注册的 display_name,遇到口径争议时能引用 definition 和 known_caveats。这正是 dbt 语义层这类产品在数据工程界做的事——"define once, use everywhere"——在 Agent 交付里的翻版:口径一旦写进语义层,BI 看板、Agent 分析、验收报告三个出口的数字就再也打不了架。

注册还有一层管理意义:口径本身要有版本和变更流程。第二期如果把"有效消费"的定义改了(比如包含储值卡消费),旧指标必须归档标记 v1,新口径标 v2,回测历史时注明版本。指标口径是项目资产,像代码一样需要版本管理。

3.4.5 沙盘:口径定义会的实况 ​

青禾的口径会开了三场才收敛,冲突点值得记录:

第一场炸在"沉睡会员"定义:工程团队默认 180 天(好实现),运营坚持 90 天(行业惯例),最后数据说话——按两个口径各拉了一遍分布,180 天口径的"沉睡会员"有 41% 其实 90-180 天内有过小额消费,召回价值密度太低。定 90 天,但分两档:90-180 天为"半沉睡"(低强度触达),180 天以上为"深度沉睡"。

第二场炸在储值卡:财务坚持储值卡消费算复购(钱早收了,消费是履约),营销坚持不算(触达动作对储值用户无效)。解法是把口径拆成两个指标:履约复购率(含储值)和现金复购率(不含),召回用例锚定后者。

第三场炸在"谁说了算":三个部门都认为自己是口径权威。最终解法是制度性的——口径注册表指定唯一 owner 和复核方,任何口径变更走书面评审。这已经不是技术决策,是数据治理决策,FDE 要有意识地推动它落到制度层面。

3.4.6 口径定义的沟通技术:让数字说话 ​

口径会议本质是利益谈判,但谈判的武器最好是数据而不是立场。三个实战技巧:

技巧一:双口径并行展示。 当双方各执一词(储值卡算不算复购),别急着裁决,把两个口径的数值都算出来放在同一张表里:含储值 31.2%、不含储值 27.4%。多数口径争议在看到具体数字的差距后自己就消解了——差距 0.3 个百分点的争议不值得再开一场会,差距 4 个百分点的争议说明这真的是两个不同的业务问题,拆成两个指标是正解。

技巧二:用分布图杀"拍脑袋"。 沉睡会员定义之争(90 天 vs 180 天)的解法是拉"距上次消费天数的会员分布图":图上清楚看到 90-180 天区段有 41% 的人有小额消费——这批人叫"沉睡"太冤,叫"活跃"太假。分布一摆,讨论从"我认为"变成"图上显示",收敛速度提升一个量级。

技巧三:给口径争议设"冷却成本"。 每场口径会开完还没收敛的,把议题和"不定口径的代价"写进纪要:"此项每延迟一周,M1 里程碑的指标基线产出延迟一周,SOW 里程碑 M2 相应顺延。"口径争议的参与者在知道争议有价格之后,态度会务实得多。

最后回到一个更高的视角:口径工作的复利在项目之外。 青禾做完复购率口径之后,客户把同样的五要素模板用到了客单价、毛利率的定义上——口径治理从你的项目资产变成了客户的组织资产。这是 FDE 交付能留下的最持久的痕迹之一:模型会换代,系统会重构,但一个把口径写下来的习惯,会留在客户的会议文化里。

3.4.7 要点总结 ​

  • 指标口径五要素:分子分母业务定义、时间窗、剔除规则、数据来源、刷新频率与责任方;缺一个要素,验收时就多一个扯皮点。
  • 口径必须落到可复核的 SQL,剔除规则进配置表,已知数据风险(如双轨 ID 覆盖率)作为 caveats 附在指标上。
  • 注册到指标语义扩展接口 = "define once, use everywhere":Agent 分析、BI 看板、验收报告共享同一份定义,数字不再打架。
  • 口径是资产:要有版本、有 owner、有变更流程;口径会议的冲突最终都要上升到数据治理制度才能闭环。
  • 三个部门三个数的病根不是数据是口径;写下来的口径,胜过任何先进的计算引擎。

参考资料 ​