# 10 · 任务与触达回收（白盒 NBA 模型）

> 前 9 册解决"怎么算"，这一册解决**"算完之后怎么变成动作、动作做完怎么算账"**——从分层结果到导购手里的任务，再到触达后的转化回收，即市面 MA / SCRM 产品所说的 NBA（Next Best Action）引擎。本册以本仓库样板间的任务池实现为蓝本（`dwd_会员经营任务` 21 列 + `ads_会员经营任务池` 32 列），抽出可移植的字段模型、生成规则与回收口径。
>
> **来源标记补充**：🏠 = 本仓库样板间实现（模拟数据，结构与口径可引用，数值不可当基准）。其余 🅰️🅱️⚪ 含义见 [README](README.md)。

## 任务池字段模型：NBA 四段 🏠

一张任务表 21 列，正好切成 MA 系统的四段。搭自己的任务池时按段检查，缺哪段补哪段：

| 段 | 字段 | 作用 |
|---|---|---|
| **① 输入**（圈谁） | 任务ID / 会员ID / 归属门店ID / 任务来源 / 任务优先级 / 任务类型 / 人群标签 | 圈选结果 + 任务元信息。`任务来源` 三值：**规则生成 / 模型生成 / 人工指派**——留好这个字段，规则跑不过模型时可以灰度切换，店长临时插单也有处安放 |
| **② 决策**（做什么） | **推荐动作 / 推荐权益 / 推荐原因 / 预计价值** | NBA 的核心四件套。`推荐原因` 给导购看（"60 天未消费"），执行的人知道为什么做才会认真做；`预计价值` 给排序用（同优先级内按预计价值倒序派发） |
| **③ 执行**（谁去做） | 员工导购ID / 任务生成时间 / 任务截止时间 / 任务失效时间 / 触达状态 / 触达时间 / 触达方式 | 截止时间 ≠ 失效时间：**截止**是考核线（逾期算导购未完成），**失效**是业务线（过了这天再触达已无意义，如券已过期）。两条线分开，考核和业务才不打架 |
| **④ 回收**（算账） | 触达后下单 / 触达后下单金额 / 任务结果 | 任务结果三态：已完成-有转化 / 已完成-无转化 / 已失效。**"已完成-无转化"必须单独留着**——它是校准圈选规则和权益力度的原料，合并进"失败"就再也分不清是没做还是做了没用 |

ADS 层（`ads_会员经营任务池`）在此基础上 JOIN 会员/门店/员工三张维表补 11 列展示字段，并算出两个派生状态（见"执行状态与转化阶段"节）。

## 九类任务：类型 × 优先级 × 圈选依据 × 动作映射 🏠

样板间预置的九类任务，每类的圈选条件都能在前 9 册和样板间数据集里找到出处——这张表就是"分层 → 动作"的翻译对照：

| 任务类型 | 优先级 | 圈选依据（出处） | 推荐动作 | 推荐权益示例 |
|---|---|---|---|---|
| 流失预警 | **P0** | 消费间隔接近流失阈值（`param_会员生命周期阈值` + [02 册 R 阈值四档](02-customer-and-membership.md#r-阈值多档分级按业务场景调)） | 电话回访 + 召回券 | 沉睡唤醒 9 折 |
| 负评修复 | **P0** | `dwd_评价` 低分/负评标签（见本册"差评客户挽回"节） | 服务补救 + 客服回访 | 免费小食券 |
| 沉睡召回 | P1 | 60 天未消费（`dws_会员生命周期` 沉睡段） | 强召回权益 + 低频触达 | 拉新返券 |
| 新会员首单 | P1 | 注册未消费 / 新客-未首单（生命周期状态机） | 发首单券 + 邀约入群 | 新人首单特价 |
| 首单后二单 | P1 | 新客-已首单且在二单窗口内（[02 册 90 天复购分桶](02-customer-and-membership.md#90-天复购分桶-)定窗口） | 发二单券 + 推荐爆款 | 满 30 减 10 |
| 外卖转到店 | P2 | `dws_渠道迁移分析`：纯外卖 / 堂食→外卖迁移 | 到店专享 + 堂食套餐 | 下午茶套餐 |
| 堂食老客召回 | P2 | 渠道迁移：纯堂食且 R 走低 | 新品邀请 + 同行福利 | 新品体验 5 折 |
| 高价值维护 | P2 | RFM 重要价值客户（[02 册 RFM 8 类](02-customer-and-membership.md#rfm-顾客分类8-类)） | 专属权益 + 会员日邀约 | 高等级专享折扣 |
| 领券未核销 | P2 | `dwd_券事件`：已发放、未核销、临近失效（[05 册核销率](05-coupon-and-discount.md)） | 核销提醒 | 原券 + 到期提示 |

**优先级设计的逻辑**：P0 = 不做马上有损失（流失、负评发酵）；P1 = 窗口期内做才有效（新客转化黄金期、沉睡未到流失）；P2 = 做了更好（提频、交叉、维护）。**优先级挂在任务类型上而不是逐单算分**，导购一看类型就知道轻重，规则也好维护。

## 任务生成 SQL 模式（规则生成）🏠⚪

规则生成 = 每条规则一段 SELECT 圈人 + 拼上决策字段，UNION ALL 汇总。可移植模板（Spark 3.4，两条规则示例，其余同构）：

```sql
WITH r1_沉睡召回 AS (
  SELECT
    `会员ID`, `注册门店ID` AS `归属门店ID`,
    '规则生成' AS `任务来源`, 'P1' AS `任务优先级`,
    '沉睡召回' AS `任务类型`, `生命周期阶段` AS `人群标签`,
    '强召回权益+低频触达' AS `推荐动作`,
    '拉新返券' AS `推荐权益`,
    CONCAT(`距末单天数`, ' 天未消费') AS `推荐原因`,
    ROUND(`总消费金额` / NULLIF(`总订单数`, 0), 2) AS `预计价值`   -- 用历史客单价近似
  FROM `dws_会员生命周期`
  WHERE `生命周期阶段` = '沉睡'
),
r2_外卖转到店 AS (
  SELECT
    `会员ID`, NULL AS `归属门店ID`,   -- 迁移分析无门店归属时留空，下游按注册门店回填
    '规则生成', 'P2', '外卖转到店', `迁移类型`,
    '到店专享+堂食套餐', '下午茶套餐',
    CONCAT('近30天外卖 ', `近30天外卖`, ' 单，堂食 ', `近30天堂食`, ' 单'),
    NULL
  FROM `dws_渠道迁移分析`
  WHERE `迁移类型` IN ('纯外卖', '堂食→外卖迁移')
)
SELECT * FROM r1_沉睡召回
UNION ALL
SELECT * FROM r2_外卖转到店;
```

**口径要点**：
- `推荐原因` 一定要在生成时就写成人话并带具体数字——事后补不回来，导购端展示全靠它。
- `预计价值` 最简单的近似 = 该会员历史客单价 ×（该任务类型的历史转化率）。冷启动时先用客单价，跑一个月后用真实转化率回填。

### 防打扰与优先级仲裁 ⚪

多条规则同时命中一个会员是常态（沉睡的人往往也在"领券未核销"里）。两步收敛：

```sql
-- 步骤 1：排除近 N 天已触达的会员（防打扰）
SELECT t.* FROM `任务候选` t
LEFT ANTI JOIN (
  SELECT DISTINCT `会员ID` FROM `dwd_会员触达`
  WHERE `触达日期` >= date_sub(CURRENT_DATE, 7)    -- 打扰间隔按业务定，7~14 天常见
) d ON t.`会员ID` = d.`会员ID`;

-- 步骤 2：同一会员只留最高优先级一条（优先级仲裁）
SELECT * FROM (
  SELECT *,
    ROW_NUMBER() OVER (
      PARTITION BY `会员ID`
      ORDER BY `任务优先级` ASC, `预计价值` DESC    -- P0 < P1 < P2 字典序正好可用
    ) AS rn
  FROM `任务候选_已防打扰`
) WHERE rn = 1;
```

**坑**：
- 防打扰要查的是**触达事实表**（`dwd_会员触达`），不是任务表——人工指派的触达也算打扰。
- 两步顺序（先防打扰、后仲裁）不影响正确性——防打扰拦的是整个人，不是某条任务——但**先拦人再仲裁省计算**：窗口函数只在可触达的人上跑。

## 执行状态与转化阶段（ADS 层派生口径）🏠

样板间 `ads_会员经营任务池` 的两个派生字段，原样可抄：

```sql
CASE
  WHEN `任务结果` LIKE '已完成%' THEN '已完结'
  WHEN `任务失效时间` < CURRENT_TIMESTAMP() THEN '已过期'
  ELSE '进行中'
END AS `执行状态`,

CASE
  WHEN `触达后下单` = 1 THEN '有转化'
  WHEN `触达状态` = '已触达' THEN '已触达未转化'
  ELSE '未触达'
END AS `转化阶段`
```

**口径解读**：`执行状态`管流程（做没做），`转化阶段`管效果（做了有没有用），**两个维度必须分开建字段**——只有一个"状态"字段的任务系统，月底一定算不清"完成率 90% 但转化率 8%"到底是执行问题还是规则问题。

## 回收口径：任务漏斗四率 🏠⚪

```sql
SELECT
  `任务类型`,
  COUNT(*)                                                        AS `生成任务数`,
  COUNT(IF(`触达状态` = '已触达', 1, NULL))                        AS `触达数`,
  COUNT(IF(`触达后下单` = 1, 1, NULL))                             AS `转化数`,
  SUM(IF(`触达后下单` = 1, `触达后下单金额`, 0))                    AS `触达后下单金额`,
  COUNT(IF(`触达状态` = '已触达', 1, NULL)) * 1.0 / COUNT(*)        AS `触达率`,      -- 执行力
  COUNT(IF(`触达后下单` = 1, 1, NULL)) * 1.0
    / NULLIF(COUNT(IF(`触达状态` = '已触达', 1, NULL)), 0)          AS `触达转化率`,  -- 规则+权益的质量
  SUM(IF(`触达后下单` = 1, `触达后下单金额`, 0))
    / NULLIF(SUM(`预计价值`), 0)                                   AS `价值兑现率`   -- 预估校准
FROM `ads_会员经营任务池`
GROUP BY `任务类型`;
```

**三个必须提醒业务方的坑**：

1. **归因窗口要有限**。"触达后下单"必须限定"触达后 N 天内"（7 天常见），无限窗口会把自然回流全记成任务功劳，转化率虚高到没法用。
2. **没有对照组，转化率≠增量**。沉睡客即使不触达也有自然回流率；严谨做法是每期留 5%~10% 圈中但不触达的对照组（holdout），**增量 = 触达组转化率 − 对照组转化率**。样板间未内置对照组字段，落地时在任务表加一列 `是否对照组` 即可。
3. **按"任务类型 × 权益"双维度看转化**，只按类型看会掩盖"动作对了、券力度不对"的情况——同是沉睡召回，9 折券和 6 折券可能差三倍转化。

**员工侧回收**：同一张表按 `员工导购ID` 分组即得导购效能排行（任务数 / 触达率 / 触达后下单金额），样板间实现见 `etl_dws_员工导购效能`。考核用**触达率**（执行力，导购可控），不要用转化率（受圈选规则质量影响，导购不可控）。

## 差评客户挽回 🏠⚪

九类任务里唯一入口不在交易数据的——圈选源是评价表。这也是最容易被会员运营漏掉的动作：差评客大概率同时是"高流失风险 + 会传播负口碑"的双重风险体。

### 圈选（从 dwd_评价 生成 P0 任务）

```sql
SELECT
  e.`会员ID`,
  e.`门店ID` AS `归属门店ID`,
  '规则生成' AS `任务来源`, 'P0' AS `任务优先级`,
  '负评修复' AS `任务类型`,
  COALESCE(NULLIF(e.`负评标签`, ''), '低分') AS `人群标签`,
  '服务补救+客服回访' AS `推荐动作`,
  '免费小食券' AS `推荐权益`,
  CONCAT(e.`评价平台`, ' ', e.`评分`, ' 分',
         IF(e.`负评标签` <> '', CONCAT('：', e.`负评标签`), '')) AS `推荐原因`
FROM `dwd_评价` e
WHERE (e.`评分` <= 2 OR (e.`负评标签` IS NOT NULL AND e.`负评标签` <> ''))
  AND e.`回复状态` <> '已回复'
  AND e.`会员ID` IS NOT NULL AND e.`会员ID` <> ''      -- 非会员差评走门店客服流程，进不了会员任务池
  AND e.`评价日期` >= date_sub(CURRENT_DATE, 3);        -- 只圈近 3 天：差评修复拼时效
```

**口径要点**：
- 差评任务**不参加防打扰排除**——服务补救性质的触达不算营销打扰，反而越快越好（24~48 小时黄金窗口）。但要参加优先级仲裁（P0 天然赢）。
- `评分 <= 2 OR 负评标签非空`：有些平台 3 分也带负评标签（"口味不好"），只卡分数会漏。

### 挽回效果口径

```sql
-- 挽回成功率：负评修复任务触达后 90 天内该会员是否再消费
COUNT(DISTINCT IF(t.`触达状态` = '已触达' AND o.`会员ID` IS NOT NULL, t.`会员ID`, NULL)) * 1.0
/ NULLIF(COUNT(DISTINCT IF(t.`触达状态` = '已触达', t.`会员ID`, NULL)), 0) AS `挽回成功率`
-- o = 触达时间后 90 天内的已完成订单，JOIN 条件按会员ID + 时间窗
```

**配套监控**：门店级负评趋势看 `dws_体验口碑汇总`；负评标签的分布变化（"卫生差"突增）比单条差评更值得升级成门店整改任务——那已经不是会员运营问题，切 [04 册多渠道评价 pipeline](04-channel-and-store.md) 的门店视角。

## 与前 9 册的接线图

```
02 册（分层：RFM/生命周期/复购）──┐
04 册（渠道迁移）                 ├─→ 本册（生成任务 → 分派 → 触达 → 回收）─→ 03 册（回收金额进营收口径）
05 册（券与核销）                 │
dwd_评价（差评圈选）─────────────┘
```

分层是弹药，本册是扳机与弹着点报告。**只做分层不做任务池，分层报表三个月后就没人看了**——因为它不欠任何人一个动作。
