Files
mindfulness/spec_kit/Personalized Reco/spec.md
2026-02-02 11:22:35 +08:00

12 KiB
Raw Blame History

Personalized Reco后端个性化推荐算法模块解耦版Spec索引版

阶段高层规范spec

目标:把「个性化推荐算法」做成后端独立模块,输入用户画像与曝光历史,模块内部从数据库拉取文案候选并排序,输出推荐句子(支持 Feed / Push / Widget 三种场景的可调参策略)。

依据:

  • 设计说明文档/個性化推薦算法規則.md
  • 设计说明文档/句子文案打分規則.mdrisk_flags 命名与语义必须严格对齐)
  • spec_kit/User Profile Scoring/spec.md用户画像输入契约V1.2

1. 背景与动机(摘要)

需要在后端实现一套跨场景一致、可调参、可观测、可回退的推荐流程并将其做成独立模块以便复用API / Celery 均可调用),降低 Push 等高风险场景的翻车概率。

已确认约束:

  • 数据库当前未设计且为空:本需求内新增 DB 设计与迁移子模块。
  • risk_flags 等内容画像语义:严格按 句子文案打分规则 执行。
  • 推荐请求:由客户端在请求时传入 user_profile 与历史集合。
  • Widget 情绪区间0.4~0.8):采用软降权。
  • Push/Widget需要频控与冷却且 API 与 Celery 两种调用方式都需要。

2. 目标Goals

  • 模块解耦:推荐逻辑以独立包/子模块方式存在,暴露稳定接口,不与 FastAPI 路由/ Celery 任务强绑定。
  • 统一 PipelineHard Filter → Soft Scoring → Rerank多样性/新鲜度/疲劳并支持候选不足的回退梯度L0~L3
  • 输入明确:输入用户画像(允许字段缺失)、已推荐的文案 ID、已触达/浏览的文案 ID用于去重/疲劳/频控)。
  • 从 DB 取候选:模块内部负责根据画像与场景召回候选,并从数据库读取文案画像/风险标记/元信息。
  • 输出可直接下发:输出推荐句子(含 content_id、文本、排序分与必要的解释字段用于打点/调参)。
  • 可观测:对候选规模、过滤原因、回退层级、 served_k 等关键指标提供统一事件结构,便于落点与报表。

3. 非目标Non-goals

  • 不在本阶段定义内容生产生成句子、人工审核工作流、embedding/向量检索V2 扩展)。
  • 不绑定具体表结构:仅规定“必须能读到的字段契约”,具体表名/索引/迁移由后续 plan 细化。
  • 不负责推送/Widget 排程:模块只负责“给定场景与约束,返回推荐结果”,调度由上层系统决定。

4. 术语与数据对象Definitions摘要

4.1 场景Scene

  • feed探索优先Exploration-first返回序列 TopK例如 30 条)。
  • push精确与安全优先Precision-first通常返回 Top1或 TopN 供上层挑选)。
  • widget稳定与品牌一致性优先Consistency-first返回 Top1每日一句

4.2 用户画像 UUserProfile

用户画像结构以客户端问卷输出为准V1.2),详见:

  • spec_kit/User Profile Scoring/spec.md(字段与缺失约定)
  • modules/reco-engine/spec.md(本模块如何消费画像与缺失判定)

4.3 文案画像 CContentProfile

模块需能从 DB 读到(或通过视图/派生字段得到):

  • content_id(稳定主键)
  • text(句子文本)
  • stage(或可推导的 stage 标签)
  • emotion_score0~1 或标记为 general
  • need_suitability / context_suitability(离散适配表/JSON
  • personalization_power0 / 0.5 / 1
  • risk_flags(集合/数组/位图均可,语义一致即可)
  • (可选)author_id / template_id / review_confidence

5. 模块边界与接口API Contract

5.1 入口函数(推荐引擎接口)

推荐模块对外暴露一个主入口,建议形式(不限定语言结构,但需表达同等信息):

  • 输入
    • scene: "feed" | "push" | "widget"
    • user_profile: UserProfile
    • already_recommended_ids: list[int|str]
    • touched_or_viewed_ids: list[int|str](触达/浏览/点击等均归一为“已曝光”集合)
    • k: intfeed 默认 30push/widget 默认 1
    • now: 时间戳(用于时间衰减/冷却窗口)
    • constraints(可选):如黑名单 author/template、最大风险等级、频控窗口天数等
  • 输出
    • items: 推荐结果数组(长度 ≤ k
    • meta: 本次推荐的统计与解释字段(用于打点/调参)

5.2 输出结果项RecommendedItem

每条推荐至少包含:

  • content_id
  • text
  • final_score
  • fallback_level_final
  • explanations(轻量可选):如命中 need/context/stage、是否 general、被降个性化的原因缺失/低置信度/回退)

5.3 数据访问抽象Repository / Gateway

为实现解耦,推荐模块不得直接依赖 FastAPI 的 Depends;应通过注入的 ContentRepository 读取数据:

  • fetch_candidates(scene, user_profile, limit, fallback_level) -> list[ContentProfile]
  • fetch_contents_by_ids(ids) -> list[ContentProfile](用于补全曝光历史的画像信息时可用)

实现层可使用 AsyncSessionSQLAlchemy完成具体查询但算法层不感知 ORM/SQL。


6. 推荐流程(统一 Pipeline

本节是工程必须遵守的“骨架”,参数可按场景配置。

6.1 Candidate Generation候选集生成

核心要求:

  • 依据 U 召回一个候选池:匹配 need/context/stage 的内容 + 一部分通用内容general
  • 若问卷允许跳过导致字段缺失need/context/emotion_score 缺失),候选池需自动提高通用安全内容占比,并视为至少进入 L1(限制 personalization_power ≤ 0.5)。

6.2 Hard Filter硬性过滤

基于 risk_flags 与产品规则做剔除(说明文档 3.x

  • block_health_medical:全场景硬过滤。
  • 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
  • 跨维度规则:U.stage.unknown=1need_suitability[parenting_pressure]=1personalization_power=1 → 禁推。

Hard Filter 后需输出 candidate_pool_size_after_hard_filter 以及若清空的 empty_reason

6.3 Soft Scoring软性打分

采用说明文档的线性加权结构:

最终分:

[ final_score(U,C_i)=\mathbb{I}[pass]\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} ]

缺失字段的保守计算(说明文档 V1.2,必须实现):

  • U.need 缺失 → S_need = 0.5
  • U.context 缺失 → S_context = 0.5
  • U.emotion_score 缺失 → S_emotion = 0.8general 仍为 0.8

个性化加成(必须受回退梯度约束):

[ S_{personal}=\alpha \cdot personalization_power \cdot \max(S_{need}, S_{context}) ]

不确定性惩罚Push 建议默认开启,模块需支持开关):

[ P_{uncertainty}=\beta \cdot (1-conf_U)\cdot(1-conf_{C_i})\cdot personalization_power ]

6.4 Rerank重排多样性/新鲜度/疲劳)

最小要求:

  • 去重:排除 already_recommended_idstouched_or_viewed_ids(同一句不重复)。
  • 多样性:作者/模板/标签多样性Feed 场景建议使用 MMR说明文档 4.5)。
  • 频控与冷却Push/Widget 必做):同句/同作者/同模板在窗口 X 天内不重复(具体 X 由 plan 定参数)。

7. 回退策略Fallback Ladder

候选不足或过滤/频控导致 served_k 过少时,必须按梯度回退,并输出最终 fallback_level_final

  • L0正常:按场景默认召回配比。
  • L1放宽匹配need/context 命中阈值放宽;personalization_power ≤ 0.5
  • L2回退通用池:增加 general 低风险句;personalization_power = 0
  • L3兜底安全池:仅从通用安全句库/白名单池抽取。

规则:

  • 回退时必须“降个性化与降风险”,尤其 Push。
  • 每次回退都要重新统计候选规模,并记录触发原因(如 hard_filter_all / freqcap_all / pool_empty)。

8. 场景默认参数V1 建议)

8.1 FeedExploration-first

  • 候选配比:匹配 60% + 通用 30% + 探索 10%
  • 权重建议:w_need=0.35, w_emotion=0.20, w_stage=0.15, w_context=0.30
  • 序列Top1 最高分,后续使用 MMRλ=0.7

8.2 PushPrecision & Safety-first

  • 候选配比need 强命中 70% + emotion 命中 20% + 通用安全 10%
  • 权重建议:w_need=0.45, w_emotion=0.35, w_stage=0.15, w_context=0.05
  • 默认启用 P_uncertainty;当 fallback_level_final>0 或画像缺失/低置信度时自动降个性化

8.3 WidgetConsistency & Brand-first

  • 候选池:以 general + personalization_power≤0.5 为主
  • 权重建议:w_need=0.25, w_emotion=0.25, w_stage=0.30, w_context=0.20
  • 情绪区间约束:建议 emotion_score 限制在 0.4~0.8(过低/过高降权或过滤,具体由 plan 定)

9. 数据库与存储契约DB Contract

模块需要 DB 提供以下能力(不限定表名实现方式):

  • 按标签召回:能按 need/context/stage/general、personalization_power、risk_flags 等条件筛选候选。
  • 按 ID 批量拉取:用于补全曝光历史或在 rerank 时补字段。
  • 安全池支持L3 兜底必须能拉到一批“通用安全句”(白名单/低风险集合)。

性能要求V1

  • 单次推荐k<=30应避免 N+1 查询;候选批量拉取 + 内存打分。
  • 查询需可加索引:stagegeneralpersonalization_power、(以及用于召回的标签字段)。

10. 可观测性(事件与指标)

每次推荐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_reasonserved_k=0 时必填)

建议额外输出(用于调参/排查):

  • scene
  • conf_U
  • missing_fieldsneed/context/emotion 的缺失情况)
  • risk_filtered_count_by_flag(可选聚合)

11. 安全与合规

  • 严禁返回 Hard Filter 禁推内容。
  • 对 Push 场景,默认倾向“低风险 + 低个性化强度”;当画像不确定或字段缺失时必须进一步降个性化。
  • 不在仓库写入真实数据库账号密码;连接串统一从 DATABASE_URL 环境变量读取(已由 server/app/core/config.py 支持)。

12. 验收标准Acceptance Criteria

  • 能以统一接口在三种场景运行:输入画像 + 曝光集合 → 输出 TopK 句子。
  • 画像字段缺失时仍能产出排序,并触发降个性化策略(至少 L1不会报错。
  • Hard Filter 规则生效:命中 block_health_medical 等风险标记的内容绝不出现在输出中。
  • 候选不足时会逐级回退并输出 fallback_level_final,不会出现无输出且无原因字段的情况。
  • 输出包含用于上层打点的 meta 统计字段,便于观测候选规模与回退率。

13. 子模块规范索引modules/

子模块规范用于实现拆分;本文件保留大需求高层约束与对外契约摘要。

  • modules/db-design/spec.md:数据库设计与迁移(当前库为空,本需求内补齐)
  • modules/content-repository/spec.md:数据访问层(按画像与场景拉取候选、按 ID 批量查)
  • modules/reco-engine/spec.md:推荐引擎编排(候选→过滤→打分→重排→回退)
  • modules/scoring/spec.md:打分与惩罚项(严格对齐规则文档;含缺失字段保守策略)
  • modules/rerank-freqcap/spec.md:重排/去重/频控Feed 的 MMRPush/Widget 冷却)
  • modules/observability/spec.md可观测事件结构与指标candidate_pool_size_* 等)
  • modules/integration-api-worker/spec.mdAPI 与 Celery 集成(请求入参、响应、任务封装)