fix:更新算法

This commit is contained in:
吕新雨
2026-02-02 11:22:35 +08:00
parent 814b96edb6
commit 58d17fc39f
27 changed files with 3286 additions and 62 deletions

View File

@@ -0,0 +1,102 @@
# 子模块Content Repository候选查询与数据访问层Spec
## 1. 目标描述
提供推荐算法可注入的、与 ORM/SQL 解耦的数据访问接口:
- 按场景与用户画像拉取候选内容画像Cᵢ
-`content_id` 批量获取内容画像(去重/重排/补字段)。
- 对 risk_flags、suitability JSON 等“存储形态”做统一解析与兼容(对上提供稳定结构)。
> 规则口径risk_flags 命名与语义严格按 `句子文案打分规则`;若历史数据存在旧 flag需在读取层做一次映射避免语义漂移
>
> 存储形态对齐 `modules/db-design/plan.md`:读取层需要将 `contents` + `content_profiles` + `content_risk_flags` 组装为上层稳定的 `ContentProfile` 结构。
---
## 2. 输入 / 输出定义
### 2.1 输入
- `scene`: `feed | push | widget`
- `user_profile`: 客户端问卷画像V1.2;字段允许缺失)
- `fallback_level`: `0|1|2|3`
- `limit`: 候选条数上限(由引擎配置)
- (可选)排除集合:`exclude_content_ids`(用于 DB 层先排一部分,减少传输;类型为 `List[int]`,与 MySQL 自增 `content_id` 对齐)
- 数据库会话/连接(实现层使用 `AsyncSession` 注入)
### 2.2 输出
- `List[ContentProfile]`(稳定字段契约):
- `content_id``int`MySQL 自增主键)
- `text`:文案文本
- `stage``general | expecting | parenting | unknown`
- `emotion_score``float | None`(约定:`None` 表示 general
- `context_suitability``Dict[str, float]`(见 4.1 的 key 集合;值为 `0/0.5/1`
- `need_suitability``Dict[str, float]`(见 4.1 的 key 集合;值为 `0/0.5/1`
- `personalization_power``float`(对上稳定口径为 `0/0.5/1`;若 DB 存 `0/5/10`,读取层需映射)
- `risk_flags``List[str]`(已做旧→新映射、去重;命名只允许 `unsafe_for_* / block_* / soft_*`
- 可选:`author_id``template_id``review_confidence`
### 2.3 数据存储形态(对齐 DB 设计)
> 对齐:`spec_kit/Personalized Reco/modules/db-design/plan.md`
- `contents`:提供 `content_id``text`、(可选)`author_id``template_id`
- `content_profiles`:提供 `stage``emotion_score``context_suitability_json``need_suitability_json``personalization_power`(推荐存 `0/5/10`)、(可选)`review_confidence`
- `content_risk_flags`:通过关联表提供风险标记集合(同一 content 下按 `uniq_content_flag(content_id, flag)` 去重)
---
## 3. 接口(建议)
推荐模块对该子模块只依赖抽象接口Python Protocol/ABC 均可):
- `fetch_candidates(scene, user_profile, fallback_level, limit, exclude_content_ids=None) -> List[ContentProfile]`
- `fetch_contents_by_ids(content_ids: List[int]) -> List[ContentProfile]`
---
## 4. 关键规则与实现约束
### 4.1 字段缺失与默认值
-`review_confidence` 缺失:输出时默认按 `0.7`(对齐 `句子文案打分规则` V1.2 约定)。
- `context_suitability/need_suitability` 若缺失:**读取层必须补齐为“全 0.5 的通用可推”结构**(稳定输出,避免上层分支判断)。
- `context_suitability` 必须包含 5 个 key`family/work/relationship/friends/health`
- `need_suitability` 必须包含 5 个 key`emotional_support/parenting_pressure/self_worth/anxiety_relief/rest_balance`
- 补齐时上述 key 的默认值均为 `0.5`
- `personalization_power`:若 DB 采用 `0/5/10` 存储,读取层必须映射为 `0.0/0.5/1.0` 对上输出。
### 4.2 risk_flags 兼容映射(若存在历史旧数据)
对齐 `句子文案打分规则` 的旧→新映射:
- `block_stage_unknown``unsafe_for_stage_unknown`
- `block_stage_parenting``unsafe_for_stage_parenting`
- `block_emotion_low``unsafe_for_emotion_low`
- `block_health_sensitive``block_health_medical`(读取层默认采用更保守的硬拦截映射;除非未来引入可判定的细分字段再放宽为 `soft_health_sensitive`
输出约束:
- 输出的 flags 必须已去重,且不得包含任何旧命名。
### 4.3 性能约束
- 不得产生 N+1 查询:候选与字段必须一次或少量批量查询获取。
- `fetch_candidates` 必须支持 limit并在 DB 层尽量过滤(减少应用层扫描)。
- `fetch_contents_by_ids` / `fetch_candidates` 推荐查询形态:
- `contents` JOIN `content_profiles`,再 LEFT JOIN `content_risk_flags`(或先批量取 profiles再批量取 flags 并在应用层聚合),避免按 `content_id` 循环查 flags。
---
## 5. 验收标准(可验证)
- `fetch_contents_by_ids`
- 输入任意 `content_id` 列表,返回包含完整字段的 `ContentProfile` 列表(无重复、可缺省字段按约定兜底)。
- `fetch_candidates`
- 在不同 `scene``fallback_level` 下能返回候选(即便画像缺失也不报错)。
- risk_flags 映射正确:输出的 flag 名称集合只包含新命名(`unsafe_for_* / block_* / soft_*`)。
- 性能:
- 单次调用不出现按 content_id 循环查库的行为(可通过日志/测试断言查询次数)。