# Personalized Reco｜Overview（大规范总览）

> 目的：保留大规范的背景/总览，并作为各子模块规范的索引入口。
>
> 依据：
>
> - `设计说明文档/個性化推薦算法規則.md`
> - `设计说明文档/句子文案打分規則.md`（risk_flags 命名与语义的唯一准绳，必须严格对齐）
> - `spec_kit/User Profile Scoring/spec.md`（客户端问卷画像输出契约，V1.2）

---

## 1. 背景

需要在后端实现一套可复用、可调参、可观测、可回退的推荐流程，覆盖 Feed / Push / Widget 三种分发场景。推荐模块必须与 API/任务解耦，避免逻辑散落；并在 Push 等高风险场景自动“降个性化/降风险”。

当前约束与确认点（来自需求澄清）：

- **数据库现状**：数据库尚未设计，当前为空（需要新增 DB 设计与迁移子模块）。
- **规则口径**：risk_flags 等内容画像语义必须严格对齐 `句子文案打分规则`。
- **调用方式**：推荐请求时由客户端传入 `user_profile` 与历史集合（已推荐 ID、已触达/浏览 ID）。
- **Widget 情绪区间**：0.4~0.8 采用**软降权**（非硬过滤）。
- **频控**：Push/Widget 需要冷却与频控（确认要做）。
- **集成形态**：既需要 FastAPI API 接口，也需要 Celery 任务调用（两者都要）。

---

## 2. 大需求输入/输出（对外契约摘要）

- **输入**：
  - `scene`: `feed | push | widget`
  - `user_profile`: 客户端问卷画像（V1.2，支持字段缺失/跳过）
  - `already_recommended_ids`: 已推荐过的文案 ID（本次请求需去重）
  - `touched_or_viewed_ids`: 已触达/浏览的文案 ID（本次请求需去重/疲劳）
  - `k`：返回条数（feed 默认 30；push/widget 默认 1）
- **输出**：
  - 推荐句子列表（`content_id` + `text` + `final_score` 等）
  - `meta`：候选规模、过滤/频控后规模、回退层级、empty_reason 等（用于打点）

---

## 3. 子模块拆分（modules/）

> 原则：每个子模块都可独立实现、测试、验收；子模块之间通过明确接口关联。

目录结构：

```text
spec_kit/Personalized Reco/
├ overview.md
├ spec.md
└ modules/
   ├ db-design/
   │  └ spec.md
   ├ content-repository/
   │  └ spec.md
   ├ reco-engine/
   │  └ spec.md
   ├ scoring/
   │  └ spec.md
   ├ rerank-freqcap/
   │  └ spec.md
   ├ observability/
   │  └ spec.md
   └ integration-api-worker/
      └ spec.md
```

模块关系（逻辑依赖）：

- `integration-api-worker` → 调用 `reco-engine`
- `reco-engine` → 依赖 `content-repository` 拉取候选
- `reco-engine` → 依赖 `hard filter / scoring / rerank-freqcap`（此处拆为独立模块：`scoring`、`rerank-freqcap`）
- `content-repository` → 依赖 `db-design` 提供表结构与字段契约
- `observability` → 被 `reco-engine` 与 `integration-api-worker` 共同使用

---

## 4. 主规范与子规范的职责划分

- `spec.md`：大需求的高层契约与总体约束（面向集成与验收）。
- `modules/*/spec.md`：每块可落地实现的子模块规范（面向工程实现与单测）。

---

## 5. 模块实现顺序（建议）

> 原则：先把“数据可查”打通，再实现“可排序”，最后做“可对外提供（API/任务）”与“可观测”。

1. **`modules/db-design/`（数据库设计与迁移）**已实施
   - 交付：表结构 + Alembic 迁移可跑通；能插入/读取最小 `ContentProfile` 字段。
2. **`modules/content-repository/`（数据访问层）**已实施
   - 交付：按场景/回退层级拉候选、按 ID（`content_id` 自增 `int`）批量查；risk_flags 旧→新映射与默认值兜底。
   - 语言：`text` 按客户端 `locale` 输出（当前仅 EN/TC），且不允许语言回退（缺语言内容直接过滤）。
   - 口径：suitability 读取层统一输出稳定结构；缺失时补齐“全 0.5”，key 集合固定为：
     - context：`family/work/relationship/friends/health`
     - need：`emotional_support/parenting_pressure/self_worth/anxiety_relief/rest_balance`
3. **`modules/scoring/`（打分）** 已实施
   - 交付：`final_score` 与缺失字段保守策略（V1.2）实现；Push 的 `P_uncertainty`；Widget 情绪区间软降权。
4. **`modules/rerank-freqcap/`（去重/重排/频控）** 已实施
   - 交付：基于传入历史集合的去重；Feed 的 MMR；Push/Widget 冷却窗口规则（先保证“同句不重复”）。
5. **`modules/observability/`（可观测）** 已实施
   - 交付：统一 `meta` 结构与字段；能准确定位候选在何阶段被清空/回退。
6. **`modules/reco-engine/`（引擎编排）** 已实施
   - 交付：新增后端 `reco_engine`（编排器 + Hard Filter）；串起候选→过滤→打分→重排→回退；输出 items+meta；默认开启轻量 explanations；在画像缺失/候选不足时仍稳定返回。
7. **`modules/integration-api-worker/`（API + Celery 集成）** 已实施
   - 交付：新增 `/v1/reco/{feed|push|widget}` 三个推荐接口（含 `Accept-Language→en/tc` 与 `X-Now` 注入）；新增按 IP 限流 10/min；新增 Celery 任务 `tasks.reco.generate` 与 `tasks.reco.push_once`，均调用同一 `Reco Engine`。

---

## 6. 变更记录

- 2026-02-02：完成 `modules/scoring/` 的 `plan.md` 与 `tasks.md`，并新增后端打分模块 `server/app/features/personalized_reco/scoring/` 与单元测试 `server/tests/test_scoring.py`。
- 2026-02-02：完成 `modules/rerank-freqcap/` 的 `plan.md` 与 `tasks.md`，并新增后端重排/频控模块 `server/app/features/personalized_reco/rerank_freqcap/` 与单元测试 `server/tests/test_rerank_freqcap.py`。
- 2026-02-02：完成 `modules/observability/` 的 `plan.md` 与 `tasks.md`，并新增后端可观测模块 `server/app/features/personalized_reco/observability/` 与单元测试 `server/tests/test_observability.py`。
- 2026-02-02：完成 `modules/reco-engine/` 的 `plan.md` 与 `tasks.md`，并新增后端引擎编排模块 `server/app/features/personalized_reco/reco_engine/`（含 Hard Filter + Orchestrator）与单元测试 `server/tests/test_reco_engine.py`。
- 2026-02-02：完成 `modules/integration-api-worker/` 的 `plan.md` 与 `tasks.md`，并新增后端集成：
  - FastAPI：`server/app/api/v1/reco.py`、`server/app/api/limits.py`、`server/app/main.py`
  - Celery：`server/app/tasks/reco.py`
  - 测试：`server/tests/test_integration_api_worker.py`
  - 依赖：`server/requirements.txt`（新增 `httpx` 用于 API 测试）

