353 lines
13 KiB
Markdown
353 lines
13 KiB
Markdown
# 正念 APP|三種分發場景推薦算法方案(Feed / Push / Widget · V1)
|
||
|
||
> **目標**:
|
||
> 針對三種分發方式(Feed、App Push、Widget 每日一句)制定一套一致但可調參的推薦流程。
|
||
>
|
||
> **共用基礎**:
|
||
>
|
||
> * 用戶畫像:U(mom_stage one-hot;emotion/context/need 允许缺失/跳过;含 `profile_confidence/profile_answered`)
|
||
> * 文案畫像:Cᵢ(stage、emotion_score、context/need suitability、personalization_power、risk_flags;建議含 content_id/author_id/template_id/review_confidence)
|
||
> * 推薦骨架:Hard Filter → Soft Scoring → Rerank(多樣性/新鮮度/疲勞)
|
||
|
||
---
|
||
|
||
## 一、先說整體流程與思路(適用三種場景)
|
||
|
||
### 1) 核心理念:同一個用戶同一天需要「不同強度」的個性化
|
||
|
||
* **Push**:最容易翻車 → **高精準 + 低風險**(Precision-first)
|
||
* **Widget**:每天唯一一句 → **穩定、代表性、可長期持續**(Consistency-first)
|
||
* **Feed**:可上下滑探索 → **可試探、可擴展、多樣性**(Exploration-first)
|
||
|
||
### 2) 共用三段式 Pipeline
|
||
|
||
1. **Candidate Generation(候選集生成)**
|
||
|
||
* 依 U 取一個「候選池」:匹配 need/context/stage 的內容 + 一部分通用內容
|
||
* V1.2:若問卷允許跳過導致 `U.need/U.context/U.emotion_score` 缺失,候選池需自動提高通用安全內容占比,并视为至少进入 L1(限制 `personalization_power≤0.5`)
|
||
2. **Hard Filter(硬性過濾)**
|
||
|
||
* 依 risk_flags 與產品規則剔除高風險內容
|
||
3. **Soft Scoring(軟性打分)**
|
||
|
||
* 用加權模型計算核心匹配分
|
||
4. **Rerank(重排)**
|
||
|
||
* 去重、作者/模板多樣性、頻控、時間衰減
|
||
5. **Serve(分發)**
|
||
|
||
* 依場景不同策略選 TopK 或組成序列
|
||
|
||
### 3) 工程必備:候選不足回退策略 + 可觀測指標(V1.1)
|
||
|
||
#### 3.1 候選不足回退(Fallback Ladder)
|
||
|
||
> 目的:避免「過濾/頻控後候選為空」導致體驗斷崖;同時在回退時**自動降個性化與降風險**(尤其 Push)。
|
||
|
||
共用定義:
|
||
|
||
* `fallback_level`:從 0 開始遞增(0=不回退)
|
||
* 回退原則:**先放寬匹配,再放寬探索,再回退到通用安全池**;同時限制 `personalization_power` 上限
|
||
|
||
建議梯度(可按場景調整):
|
||
|
||
* **L0(正常)**:按原候選配比取候選
|
||
* **L1(放寬匹配)**:`need/context` 由 `1 → ≥0.5`;`personalization_power` 上限降為 `≤0.5`
|
||
* **L2(回退通用池)**:加入更多 `general`/低風險句;`personalization_power` 上限降為 `0`
|
||
* **L3(兜底)**:僅從「通用安全句庫」抽取(需單獨維護白名單/安全池)
|
||
|
||
每次請求需輸出最終使用的 `fallback_level`(用於分析覆蓋率與風險)。
|
||
|
||
#### 3.2 可觀測指標(必打點)
|
||
|
||
每次生成推薦(Feed Session / 每次 Push / 每日 Widget)至少打點:
|
||
|
||
* `candidate_pool_size_raw`:初始候選池大小
|
||
* `candidate_pool_size_after_hard_filter`
|
||
* `candidate_pool_size_after_dedup`
|
||
* `candidate_pool_size_after_freqcap`
|
||
* `fallback_level_final`
|
||
* `served_k`:實際下發條數
|
||
* `empty_reason`:若 served_k=0,記錄原因(如 hard_filter_all / freqcap_all / pool_empty / unknown)
|
||
|
||
核心監控衍生指標(報表層計算):
|
||
|
||
* **覆蓋率**:`served_k > 0` 的比例(按場景分開)
|
||
* **回退率**:`fallback_level_final > 0` 的比例
|
||
* **頻控後候選數分布**:`candidate_pool_size_after_freqcap` 的 P50/P90/P99
|
||
|
||
---
|
||
|
||
## 二、總分結構(Score Decomposition)
|
||
|
||
對任意文案 Cᵢ:
|
||
|
||
[
|
||
\textbf{final_score}(U,Cᵢ) = \mathbb{I}[\text{pass filters}] \times \Big(
|
||
S_{core} + S_{personal} + S_{fresh} - P_{fatigue} - P_{repeat} - P_{risk} - P_{uncertainty}
|
||
\Big)
|
||
]
|
||
|
||
其中
|
||
|
||
[
|
||
S_{core} = w_{need}S_{need} + w_{emotion}S_{emotion} + w_{stage}S_{stage} + w_{context}S_{context}
|
||
]
|
||
|
||
* `S_need = Cᵢ.need_suitability[U.need]`(若 U.need 缺失,见 V1.2)
|
||
* `S_context = Cᵢ.context_suitability[U.context]`(若 U.context 缺失,见 V1.2)
|
||
* `S_stage`:general=1;命中=1;unknown對非unknown=0.7;其餘=0
|
||
* `S_emotion`:若文案 general→0.8;否則 `1-|U.emotion_score-Cᵢ.emotion_score|`(若 U.emotion_score 缺失,见 V1.2)
|
||
|
||
### V1.2:当问卷允许跳过题目时的打分约定(工程必读)
|
||
|
||
> 目标:用户画像字段不全时仍能产出排序;并在不确定时自动降个性化/降风险。
|
||
|
||
判定缺失:
|
||
|
||
* `U.need` 为空对象 `{}` 或不存在 → 视为缺失
|
||
* `U.context` 为空对象 `{}` 或不存在 → 视为缺失
|
||
* `U.emotion_score` 为 `null`/不存在 → 视为缺失
|
||
|
||
缺失时的保守计算:
|
||
|
||
* `S_need`:
|
||
* 若 `U.need` 缺失 → `S_need = 0.5`
|
||
* 否则 → `S_need = Cᵢ.need_suitability[U.need]`
|
||
* `S_context`:
|
||
* 若 `U.context` 缺失 → `S_context = 0.5`
|
||
* 否则 → `S_context = Cᵢ.context_suitability[U.context]`
|
||
* `S_emotion`:
|
||
* 若 `U.emotion_score` 缺失 → `S_emotion = 0.8`
|
||
* 否则按原定义计算(文案 general 仍为 0.8)
|
||
|
||
额外约束(与回退梯度一致,6A):
|
||
|
||
* 若 `conf_U` 偏低或字段缺失明显:必须启用 `P_uncertainty`
|
||
* 若进入回退梯度(`fallback_level_final>0`):按 L1/L2/L3 限制 `personalization_power` 上限(见 3.1)
|
||
|
||
個性化加成:
|
||
[
|
||
S_{personal} = \alpha \cdot Cᵢ.personalization_power \cdot \max(S_{need}, S_{context})
|
||
]
|
||
|
||
不確定性懲罰(Push 建議啟用):
|
||
[
|
||
P_{uncertainty} = \beta \cdot (1-\text{conf}_U) \cdot (1-\text{conf}_{Cᵢ}) \cdot Cᵢ.personalization\_power
|
||
]
|
||
|
||
> 說明:
|
||
>
|
||
> * `conf_U`:用戶畫像置信度(建議由問卷生成後隨時間衰減;見「用戶畫像」文件 V1.1)
|
||
> * `conf_{Cᵢ}`:內容標註置信度(`Cᵢ.review_confidence`;缺省可給 0.7)
|
||
> * `P_{uncertainty}` 可併入 `P_risk`(工程上更簡單),但需保留獨立打點便於調參
|
||
|
||
---
|
||
|
||
## 三、Hard Filter(共用禁推規則)
|
||
|
||
### 3.1 risk_flags(內容自帶)
|
||
|
||
> V1.1 起,risk_flags 命名/語義以「句子文案打分規則」為準(`unsafe_for_*` / `block_*` / `soft_*`)。
|
||
|
||
* `U.stage.unknown=1` → 禁推 `unsafe_for_stage_unknown`
|
||
* `U.stage.parenting=1` → 禁推 `unsafe_for_stage_parenting`
|
||
* `U.emotion_score≤0.2` → 禁推 `unsafe_for_emotion_low`
|
||
* `Cᵢ.risk_flags` 含 `block_health_medical` → **全场景禁推(Hard Filter)**(仅挡「医疗/诊断/严重暗示」)
|
||
|
||
> `soft_health_sensitive` 不做 Hard Filter,改由 Soft Penalty(見 Push 的 P_risk)
|
||
|
||
### 3.2 產品規則(跨維度)
|
||
|
||
* `U.stage.unknown=1` 且 `Cᵢ.need_suitability[parenting_pressure]=1` 且 `Cᵢ.personalization_power=1` → 禁推
|
||
|
||
---
|
||
|
||
# 四、Feed 模式(App 內上下滑)— Exploration-first
|
||
|
||
## 4.1 目標
|
||
|
||
* 讓用戶快速感到「被理解」
|
||
* 同時探索更多題材,避免內容疲乏
|
||
* 允許一定程度的試探(比 Push 寬鬆)
|
||
|
||
## 4.2 流程(Feed Session)
|
||
|
||
1. **建候選池**(大)
|
||
|
||
* 60%:匹配 need/context 的內容(含 personalization_power=0.5/1)
|
||
* 30%:通用內容(general)
|
||
* 10%:探索內容(與 context/need 邊緣相關)
|
||
2. Hard Filter(仍嚴格)
|
||
3. Soft Scoring(偏多樣性)
|
||
4. Rerank:用 MMR 做序列
|
||
|
||
## 4.3 Feed 打分權重(建議)
|
||
|
||
* `w_need=0.35, w_emotion=0.20, w_stage=0.15, w_context=0.30`
|
||
|
||
> Feed 更重視「語境共鳴」與內容多樣性,所以 context 權重上調。
|
||
|
||
## 4.4 Feed 序列重排(MMR)
|
||
|
||
* Top1:最高分(確保第一眼命中)
|
||
* 後續:在高分候選中,最大化與已選內容的差異(作者/模板/need/context)
|
||
|
||
### 4.5 Feed 的 MMR 定義(工程側定義,V1.1)
|
||
|
||
選擇第 t 個內容:
|
||
|
||
[
|
||
\text{MMR}(c)=\lambda \cdot \text{Rel}(c) - (1-\lambda)\cdot \max_{s \in S_{t-1}} \text{Sim}(c,s)
|
||
]
|
||
|
||
建議預設:`λ = 0.7`(更偏相關性,仍保留多樣性)
|
||
|
||
* `Rel(c)`:使用 `final_score(U,c)`(或 Soft Scoring 後的分數)
|
||
* `Sim(c,s)`:相似度定義(無 embedding 也可落地)
|
||
|
||
相似度(離散特徵版,推薦 V1 上線):
|
||
|
||
* 若 `content_id` 相同 → `Sim=1`
|
||
* 若 `template_id` 相同且非空 → `Sim += 0.6`
|
||
* 若 `author_id` 相同且非空 → `Sim += 0.3`
|
||
* `need/context/stage` 標籤重合(Jaccard)→ `Sim += 0.1 * Jaccard(tags_c, tags_s)`
|
||
* 最終 `Sim` clamp 到 `[0,1]`
|
||
|
||
字段依賴與回退:
|
||
|
||
* 缺 `template_id/author_id` 時,只用 tags 相似度(Sim 仍可算)
|
||
* 若後續引入文本 embedding,可將 embedding cosine 加權合併(V2)
|
||
|
||
---
|
||
|
||
# 五、App Push(可設定 0–5 次)— Precision & Safety-first
|
||
|
||
## 5.1 目標
|
||
|
||
* Push 是「打擾」:錯一次就掉留存
|
||
* 追求「準、溫柔、少翻車」
|
||
|
||
## 5.2 流程(每次 Push)
|
||
|
||
1. **候選池**(小而精)
|
||
|
||
* 70%:need 命中(S_need=1)的內容
|
||
* 20%:emotion 命中(距離小)的內容
|
||
* 10%:通用安全句(general + 低風險)
|
||
2. Hard Filter(最嚴格)
|
||
3. Soft Scoring(偏 need + emotion)
|
||
4. 冷卻與頻控(必做)
|
||
|
||
* 同一句/同作者/同模板至少 X 天不重複
|
||
5. 發送
|
||
|
||
> Push 追加規則(V1.1):若 `fallback_level_final > 0` 或 `conf_U` 偏低,需自動「降個性化」:
|
||
>
|
||
> * `personalization_power` 上限降為 `≤0.5`(L1)或 `0`(L2/L3)
|
||
> * 若候選不足,優先回退到「通用安全句庫」,而不是擴大高個性化內容
|
||
>
|
||
> V1.2(支持问卷跳过)补充:
|
||
>
|
||
> * 若 `profile_answered.need=false` 或 `U.need` 缺失:不得按“need 强命中”召回,候选池应提高通用安全句占比,并至少按 L1 降个性化
|
||
> * 若 `profile_answered.emotion=false` 或 `U.emotion_score` 缺失:Push 应偏向 `Cᵢ.emotion_score` 为 `general` 或 0.4–0.8 的稳定内容,并启用 `P_uncertainty`
|
||
|
||
## 5.3 Push 打分權重(建議)
|
||
|
||
* `w_need=0.45, w_emotion=0.35, w_stage=0.15, w_context=0.05`
|
||
|
||
> Push 更在乎「此刻需要」與「語氣安全」。context 權重降低。
|
||
|
||
## 5.4 Push 風險懲罰(P_risk)
|
||
|
||
* 若 `Cᵢ.personalization_power=1` 且 `S_need<1` 且 `S_context<1` → 額外扣分
|
||
* 若 content 涉及健康敏感(`soft_health_sensitive`)→ 扣分(Soft Penalty,不做禁推)
|
||
* 不確定性懲罰:`P_uncertainty`(或併入 `P_risk`),用於在 `conf_U/conf_C` 偏低時自動降權高個性化內容
|
||
|
||
## 5.5 0–5 次推送的排程策略
|
||
|
||
* 使用者設定次數 N:
|
||
|
||
* 第 1 條:need 命中 + 安全
|
||
* 第 2 條:emotion 修復
|
||
* 第 3 條:self-worth / rest_balance(視 need 而定)
|
||
* 第 4–5 條:通用句補位,避免疲勞
|
||
|
||
---
|
||
|
||
# 六、Widget(每日一句)— Consistency & Brand-first
|
||
|
||
## 6.1 目標
|
||
|
||
* Widget 是「代表你這個 App 的一句話」
|
||
* 需要:穩定、可持續、低風險、避免太私密
|
||
|
||
## 6.2 流程(每日生成)
|
||
|
||
1. 候選池:以 **general + personalization_power≤0.5** 為主
|
||
2. Hard Filter(嚴格)
|
||
3. Soft Scoring:偏 stage 安全 + emotion 中性/平靜
|
||
4. 跨日多樣性:7 日內不重複作者/模板/同一句
|
||
|
||
> 若候選不足:同樣走回退梯度(優先增加 general 安全句;不提高個性化力度)。
|
||
|
||
## 6.3 Widget 打分權重(建議)
|
||
|
||
* `w_need=0.25, w_emotion=0.25, w_stage=0.30, w_context=0.20`
|
||
|
||
> Widget 需要「身份語境安全」與「普適」,stage 權重更高。
|
||
|
||
## 6.4 Widget 的情緒區間約束
|
||
|
||
* 建議限制 `Cᵢ.emotion_score` 在 **0.4–0.8**(tired→calm)
|
||
|
||
* 避免太低(沉重)
|
||
* 避免太高(過嗨)
|
||
|
||
---
|
||
|
||
## 七、場景差異總結(快速對照)
|
||
|
||
| 場景 | 目標 | 候選池 | 風險容忍 | 權重重點 | 序列策略 |
|
||
| ------ | ----- | --- | ---- | ------------------- | ------ |
|
||
| Feed | 探索+共鳴 | 大 | 中 | context↑、diversity↑ | MMR 序列 |
|
||
| Push | 準+安全 | 小 | 低 | need↑、emotion↑ | 頻控+冷卻 |
|
||
| Widget | 穩+代表性 | 中小 | 低 | stage↑、emotion中性 | 跨日多樣性 |
|
||
|
||
---
|
||
|
||
## 八、(後段解釋預告)提及的算法/概念
|
||
|
||
* Candidate Generation(混合召回:命中 + 通用 + 探索)
|
||
* Hard Filter(規則引擎)
|
||
* Linear Weighted Scoring(加權線性模型)
|
||
* MMR(Maximal Marginal Relevance,多樣性重排)
|
||
* Time Decay(時間衰減)
|
||
* Frequency Capping(頻控)
|
||
* Cooldown Keys(去重鍵:句子/作者/模板)
|
||
|
||
> 工程側去重鍵定義(V1.1):
|
||
>
|
||
> * `sentence_key = content_id`(若無 content_id,需生成 stable hash,但建議補 content_id)
|
||
> * `author_key = author_id`(可空)
|
||
> * `template_key = template_id`(可空)
|
||
>
|
||
> 冷卻/頻控同時支持三層 key,避免只靠單一 key 造成過度重複或過度稀釋。
|
||
|
||
---
|
||
|
||
## 九、V1 可直接上線的預設參數
|
||
|
||
* Feed:Top1 命中 + MMR 序列 30 條
|
||
* Push:每次 Top1;冷卻 7 天不重複作者,14 天不重複同句
|
||
* Widget:emotion_score 限制 0.4–0.8;7 日不重複作者/模板
|
||
|
||
V1.1 補充(工程預設):
|
||
|
||
* Feed:MMR `λ=0.7`
|
||
* Push:啟用 `P_uncertainty`(或併入 `P_risk`);`fallback_level>=1` 時 `personalization_power` 上限降為 `≤0.5`
|
||
* Health:`block_health_medical` 全场景 Hard Filter;`soft_health_sensitive` 走 Soft Penalty
|
||
|
||
> 一句話:
|
||
> **同一套 U×Cᵢ 打分,按場景調候選池、權重與重排約束。**
|