Files
mindfulness/设计说明文档/個性化推薦算法規則.md
2026-02-02 11:22:35 +08:00

353 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 正念 APP三種分發場景推薦算法方案Feed / Push / Widget · V1
> **目標**
> 針對三種分發方式Feed、App Push、Widget 每日一句)制定一套一致但可調參的推薦流程。
>
> **共用基礎**
>
> * 用戶畫像Umom_stage one-hotemotion/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命中=1unknown對非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可設定 05 次)— 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.40.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 05 次推送的排程策略
* 使用者設定次數 N
* 第 1 條need 命中 + 安全
* 第 2 條emotion 修復
* 第 3 條self-worth / rest_balance視 need 而定)
* 第 45 條:通用句補位,避免疲勞
---
# 六、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.40.8**tired→calm
* 避免太低(沉重)
* 避免太高(過嗨)
---
## 七、場景差異總結(快速對照)
| 場景 | 目標 | 候選池 | 風險容忍 | 權重重點 | 序列策略 |
| ------ | ----- | --- | ---- | ------------------- | ------ |
| Feed | 探索+共鳴 | 大 | 中 | context↑、diversity↑ | MMR 序列 |
| Push | 準+安全 | 小 | 低 | need↑、emotion↑ | 頻控+冷卻 |
| Widget | 穩+代表性 | 中小 | 低 | stage↑、emotion中性 | 跨日多樣性 |
---
## 八、(後段解釋預告)提及的算法/概念
* Candidate Generation混合召回命中 + 通用 + 探索)
* Hard Filter規則引擎
* Linear Weighted Scoring加權線性模型
* MMRMaximal 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 可直接上線的預設參數
* FeedTop1 命中 + MMR 序列 30 條
* Push每次 Top1冷卻 7 天不重複作者14 天不重複同句
* Widgetemotion_score 限制 0.40.87 日不重複作者/模板
V1.1 補充(工程預設):
* FeedMMR `λ=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ᵢ 打分,按場景調候選池、權重與重排約束。**