新功能:个性化推荐算法
This commit is contained in:
172
spec_kit/Personalized Reco/modules/rerank-freqcap/tasks.md
Normal file
172
spec_kit/Personalized Reco/modules/rerank-freqcap/tasks.md
Normal file
@@ -0,0 +1,172 @@
|
||||
# Rerank & Freqcap(重排 / 去重 / 频控)|Tasks
|
||||
|
||||
> 对应计划:`spec_kit/Personalized Reco/modules/rerank-freqcap/plan.md`
|
||||
>
|
||||
> 本清单执行原则:
|
||||
>
|
||||
> - 本模块只做 **Dedup / Freqcap / Feed MMR 重排**,不做 Soft Scoring 与 Hard Filter。
|
||||
> - V1 冷却窗口以“输入集合代表窗口内历史”为准(后续接入服务端历史再按天计算)。
|
||||
|
||||
---
|
||||
|
||||
## 0. 任务标记规则
|
||||
|
||||
- 用勾选框标记执行状态:
|
||||
- `[ ]` 未开始
|
||||
- `[x]` 已完成
|
||||
- 每个任务都要求可独立验收(有明确产出/可运行的检查方式)。
|
||||
|
||||
---
|
||||
|
||||
## 1. 文档对齐(先把口径写死,避免实现漂移)
|
||||
|
||||
- [x] 1.1 校对 `modules/rerank-freqcap/spec.md` 与 `modules/rerank-freqcap/plan.md` 一致性
|
||||
- **检查点**:
|
||||
- 输入:`scene/scored_candidates/history/k/config` 字段与命名一致
|
||||
- 输出:`ranked_items` 与 `meta` 字段集合一致
|
||||
- 去重键:`sentence_key=content_id`、`author_key`、`template_key` 口径一致
|
||||
- Feed:MMR λ=0.7 与 Sim 规则一致
|
||||
- **验收**:两份文档不存在冲突描述,且“V1 冷却窗口语义”写清楚(集合代表窗口内历史)。
|
||||
|
||||
- [x] 1.2 在 `plan.md` 中补充/固定“标签构造策略”与“候选截断策略”(若后续要改再更新)
|
||||
- **变更点**:
|
||||
- 明确 `tags` 的 V1 定义:`stage + need_argmax + context_argmax`
|
||||
- 明确 `top_n_for_mmr` 默认值与作用(性能兜底)
|
||||
- **验收**:实现时不会出现“标签到底取哪些 key”的二义性。
|
||||
|
||||
---
|
||||
|
||||
## 2. 目录与骨架(与推荐子模块同级)
|
||||
|
||||
- [x] 2.1 新建目录 `server/app/features/personalized_reco/rerank_freqcap/`
|
||||
- **包含**:
|
||||
- `__init__.py`
|
||||
- `types.py`(`ScoredCandidate`、`RerankConfig`、`RerankMeta`、`RerankResult`)
|
||||
- `defaults.py`(按 scene 的默认参数:λ、cooldown_*、top_n_for_mmr)
|
||||
- `utils.py`(ID 归一化、Jaccard、tag 构造等)
|
||||
- `rerank.py`(主入口 `rerank_and_freqcap`)
|
||||
- **验收**:可通过 `app.features.personalized_reco.rerank_freqcap.*` 正常 import。
|
||||
|
||||
---
|
||||
|
||||
## 3. 类型与接口(稳定契约,便于 reco-engine 调用)
|
||||
|
||||
- [x] 3.1 定义 `ScoredCandidate`(最小字段集合)
|
||||
- **必须字段**:
|
||||
- `content_id: int`
|
||||
- `final_score: float`
|
||||
- **建议字段**(用于多样性/频控):
|
||||
- `author_id: str | None`
|
||||
- `template_id: str | None`
|
||||
- `content_profile`(至少能取到 stage/need_suitability/context_suitability;缺失时需降级)
|
||||
- **验收**:能承载 MMR 相似度计算所需数据;缺失字段不会导致异常。
|
||||
|
||||
- [x] 3.2 定义 `RerankConfig`(可调参)
|
||||
- **字段**:
|
||||
- Feed:`mmr_lambda`(默认 0.7)、`top_n_for_mmr`(默认 200)
|
||||
- Push/Widget:`cooldown_sentence_days/cooldown_author_days/cooldown_template_days`(用于配置与可观测)
|
||||
- **验收**:能从 scene 推导默认 config(或由调用方传入覆盖)。
|
||||
|
||||
- [x] 3.3 定义 `RerankMeta` 与 `RerankResult`
|
||||
- **meta 必须字段**:
|
||||
- `candidate_pool_size_after_dedup`
|
||||
- `candidate_pool_size_after_freqcap`
|
||||
- `missing_history_fields`
|
||||
- **建议字段**:
|
||||
- `freqcap_filtered_counts`(sentence/author/template)
|
||||
- **验收**:字段集合固定;任何输入都能产出 meta(包括候选为空)。
|
||||
|
||||
---
|
||||
|
||||
## 4. 核心算法实现(V1 最小集合)
|
||||
|
||||
- [x] 4.1 实现历史 ID 归一化(避免 str/int 混用漏过滤)
|
||||
- **规则**:
|
||||
- `already_recommended_ids` / `touched_or_viewed_ids` 尽量转为 `int` 集合
|
||||
- 转换失败的值忽略并记录 debug
|
||||
- **验收**:单测覆盖 `["1", 2, "bad"]` 等混合输入,过滤结果正确且稳定。
|
||||
|
||||
- [x] 4.2 实现 Dedup(必做)
|
||||
- **规则**:过滤 `content_id ∈ seen_ids` 的候选
|
||||
- **产出**:`meta.candidate_pool_size_after_dedup`
|
||||
- **验收**:输出不包含历史出现过的 `content_id`。
|
||||
|
||||
- [x] 4.3 实现 Freqcap(Push/Widget 必做;Feed 可选)
|
||||
- **V1 策略**:
|
||||
- 句子维度(必做):同句硬过滤(使用 dedup 的 seen_ids 即可)
|
||||
- 作者/模板维度(增强项):
|
||||
- 若提供 `recent_author_ids`:命中则硬过滤;否则在 `missing_history_fields` 记录 `author`
|
||||
- 若提供 `recent_template_ids`:命中则硬过滤;否则在 `missing_history_fields` 记录 `template`
|
||||
- **产出**:
|
||||
- `candidate_pool_size_after_freqcap`
|
||||
- `freqcap_filtered_counts`(建议)
|
||||
- **验收**:在有/无 `recent_*_ids` 输入时行为一致且可解释。
|
||||
|
||||
- [x] 4.4 实现 Feed:tag 构造与相似度 `Sim`
|
||||
- **tag 规则(V1 写死)**:
|
||||
- `stage:<stage>`
|
||||
- `need:<argmax_key>`(从 `need_suitability` 取最大值 key;为空则跳过)
|
||||
- `context:<argmax_key>`(从 `context_suitability` 取最大值 key;为空则跳过)
|
||||
- **Jaccard**:`|A∩B|/|A∪B|`,空集合时返回 0
|
||||
- **Sim 累加规则**:
|
||||
- 同 content_id → 1
|
||||
- template_id 相同且非空 → +0.6
|
||||
- author_id 相同且非空 → +0.3
|
||||
- +0.1 * Jaccard(tags)
|
||||
- clamp 到 `[0,1]`
|
||||
- **验收**:单测覆盖缺失字段(无 author/template/tags)时仍能算出稳定 Sim。
|
||||
|
||||
- [x] 4.5 实现 Feed:MMR 选序列
|
||||
- **规则**:
|
||||
- Top1:按 `final_score` 最大
|
||||
- 后续:按 `MMR(c)=λ*Rel(c)-(1-λ)*maxSim` 选择
|
||||
- `Rel=final_score`
|
||||
- **性能兜底**:先截断候选到 `top_n_for_mmr` 再做 MMR
|
||||
- **验收**:
|
||||
- Top1 恒等于最高分
|
||||
- 候选足够时,序列不出现大量同作者/同模板紧邻重复(可用阈值断言)
|
||||
|
||||
- [x] 4.6 实现 Push/Widget:最终 TopK
|
||||
- **规则**:dedup+freqcap 后按 `final_score` 降序取前 k 条
|
||||
- **验收**:输出长度 ≤ k,且分数单调不增(允许相等)。
|
||||
|
||||
- [x] 4.7 实现主入口 `rerank_and_freqcap(...) -> RerankResult`
|
||||
- **规则**:
|
||||
- 三场景共用 dedup
|
||||
- Feed:MMR;Push/Widget:TopK
|
||||
- 必须输出 meta(即使 ranked_items 为空)
|
||||
- **验收**:任何输入(含空候选)不抛异常,并输出稳定结构。
|
||||
|
||||
---
|
||||
|
||||
## 5. 单元测试(pytest,纯函数为主)
|
||||
|
||||
- [x] 5.1 新建测试文件 `server/tests/test_rerank_freqcap.py`
|
||||
- **用例覆盖**:
|
||||
- dedup:历史集合过滤正确(含 str/int 混用)
|
||||
- freqcap:有/无 recent_author/template 的分支与 meta 缺失标记
|
||||
- feed mmr:Top1=最高分;后续避免同作者/模板紧邻(构造数据断言)
|
||||
- push/widget:TopK 输出正确
|
||||
- **验收**:`pytest -q tests/test_rerank_freqcap.py` 通过。
|
||||
|
||||
---
|
||||
|
||||
## 6. 最终自检清单(合入前)
|
||||
|
||||
- [x] 6.1 文档一致性检查
|
||||
- **验收**:`spec.md` / `plan.md` / 实现接口签名三者一致(尤其 meta 字段与默认参数)。
|
||||
|
||||
- [x] 6.2 回归检查(不影响已实施模块)
|
||||
- **验收**:不修改 `content-repository` 与 `scoring` 的既有逻辑;仅新增 `rerank-freqcap` 模块与测试。
|
||||
|
||||
- [x] 6.3 全量测试通过
|
||||
- **命令**(在 `server/`):
|
||||
- `pytest -q`
|
||||
- **验收**:所有用例通过。
|
||||
|
||||
- [x] 6.4 全部完成后更新大规范 `overview.md`
|
||||
- **变更点**:
|
||||
- 将 `modules/rerank-freqcap/` 标记为“已实施”
|
||||
- 增加一条变更记录(日期 + 交付物:plan/tasks/代码/测试)
|
||||
- **验收**:`spec_kit/Personalized Reco/overview.md` 中模块状态与交付记录准确。
|
||||
|
||||
Reference in New Issue
Block a user