新功能:个性化推荐算法
This commit is contained in:
190
spec_kit/Personalized Reco/modules/observability/plan.md
Normal file
190
spec_kit/Personalized Reco/modules/observability/plan.md
Normal file
@@ -0,0 +1,190 @@
|
||||
# Observability(可观测性与打点载荷)|Plan
|
||||
|
||||
> 对应规范:`spec_kit/Personalized Reco/modules/observability/spec.md`
|
||||
>
|
||||
> 规则来源(必须对齐):
|
||||
>
|
||||
> - `设计说明文档/個性化推薦算法規則.md`(candidate_pool_size_*、fallback_level_final、empty_reason 等必打点字段)
|
||||
> - `spec_kit/Personalized Reco/overview.md`(模块边界:本模块被 `reco-engine` 与 `integration-api-worker` 共同使用)
|
||||
|
||||
---
|
||||
|
||||
## 1. 目标与交付物
|
||||
|
||||
### 1.1 目标
|
||||
|
||||
- 定义推荐模块统一的 `RecoMeta`(meta/event 载荷),**随推荐结果一起返回**,由调用方负责上报/落库/打点。
|
||||
- 确保每次推荐调用都能产出可用于监控与排障的关键字段:
|
||||
- 覆盖率、回退率、候选规模分布、过滤原因分布
|
||||
- `served_k=0` 时必须给出准确的 `empty_reason`(定位清空阶段)
|
||||
- 与现有子模块接口对齐:
|
||||
- 候选生成(content-repository)
|
||||
- Hard Filter(引擎阶段)
|
||||
- Soft Scoring(scoring)
|
||||
- Rerank/Freqcap(rerank-freqcap)
|
||||
|
||||
### 1.2 交付物
|
||||
|
||||
- `modules/observability/plan.md`:本技术计划(本文件)。
|
||||
- 代码实现(后续 tasks 阶段落地)建议位置:
|
||||
- `server/app/features/personalized_reco/observability/`
|
||||
- 包含:
|
||||
- `types.py`:`RecoMeta`(Pydantic BaseModel)
|
||||
- `builder.py`:`RecoMetaBuilder`(在 pipeline 中逐步填充)
|
||||
- `utils.py`:`empty_reason` 判定工具函数
|
||||
- 单元测试(后续 tasks 阶段落地):
|
||||
- `served_k=0` 时 empty_reason 必填且阶段一致
|
||||
- 计数口径一致性(after_* 的单调性与非负)
|
||||
|
||||
---
|
||||
|
||||
## 2. 模块职责边界(V1 约定)
|
||||
|
||||
### 2.1 本模块负责
|
||||
|
||||
- 提供统一的数据结构 `RecoMeta`(返回给调用方)与构建方式(builder)。
|
||||
- 在推荐 pipeline 中收集各阶段统计,避免“散落日志/散落字段”:
|
||||
- 候选生成规模(raw)
|
||||
- Hard Filter 后规模
|
||||
- Dedup 后规模
|
||||
- Freqcap 后规模
|
||||
- 回退层级与触发原因(由引擎提供)
|
||||
- served_k 与 empty_reason
|
||||
- `conf_U` 与 `missing_fields`
|
||||
- (可选)risk flag 命中统计
|
||||
|
||||
### 2.2 不在本模块实现
|
||||
|
||||
- 不负责真正的上报实现(埋点 SDK / 日志落库 / 指标上报)。
|
||||
- 不负责决定回退策略与过滤规则,只负责“把发生了什么”记录成统一载荷。
|
||||
|
||||
---
|
||||
|
||||
## 3. `RecoMeta` 字段定义(V1)
|
||||
|
||||
> 以 `modules/observability/spec.md` 为准,本 plan 补充“口径/生成时机/默认值”。
|
||||
|
||||
### 3.1 必须字段(每次推荐都要产出)
|
||||
|
||||
- `scene: "feed" | "push" | "widget"`
|
||||
- `candidate_pool_size_raw: int`
|
||||
- `candidate_pool_size_after_hard_filter: int`
|
||||
- `candidate_pool_size_after_dedup: int`
|
||||
- `candidate_pool_size_after_freqcap: int`
|
||||
- `fallback_level_final: int`
|
||||
- `served_k: int`
|
||||
- `empty_reason: str | None`
|
||||
- `served_k=0` 时必填
|
||||
- `served_k>0` 时可为 `None`(或输出 `"unknown"`,但建议为 None 更干净)
|
||||
- `conf_U: float`
|
||||
- `missing_fields: { need: boolean; context: boolean; emotion: boolean }`
|
||||
|
||||
### 3.2 可选字段(建议支持,便于排障/调参)
|
||||
|
||||
- `risk_filtered_count_by_flag: { flag: count }`
|
||||
- 其他调参辅助字段(V1 可先不返回给客户端,仅在内部日志/事件中使用):
|
||||
- `config_snapshot`(权重、alpha/beta、mmr_lambda、cooldown 等)
|
||||
- `fallback_trigger_reason`(例如 pool_empty/hard_filter_all/freqcap_all)
|
||||
|
||||
---
|
||||
|
||||
## 4. 口径与生成时机(V1 必须写死)
|
||||
|
||||
### 4.1 数量统计口径(强约束)
|
||||
|
||||
- 计数必须满足:
|
||||
- 全部为非负整数
|
||||
- 单调不增:
|
||||
- `raw >= after_hard_filter >= after_dedup >= after_freqcap >= served_k`
|
||||
- 每个阶段计数的来源:
|
||||
- `candidate_pool_size_raw`:候选生成阶段拿到的候选数(从 `content-repository` 返回的候选列表长度)
|
||||
- `candidate_pool_size_after_hard_filter`:Hard Filter 过滤后的候选数
|
||||
- `candidate_pool_size_after_dedup`:去重(基于历史集合)后的候选数
|
||||
- `candidate_pool_size_after_freqcap`:频控/冷却后的候选数(包含作者/模板维度若执行)
|
||||
- `served_k`:最终输出 items 的长度(≤ k)
|
||||
|
||||
### 4.2 empty_reason(served_k=0 时必填)
|
||||
|
||||
枚举建议(对齐 spec):
|
||||
|
||||
- `hard_filter_all`
|
||||
- `freqcap_all`
|
||||
- `pool_empty`
|
||||
- `unknown`
|
||||
|
||||
判定逻辑(V1 推荐写死,保证阶段一致):
|
||||
|
||||
- 若 `candidate_pool_size_raw == 0` → `pool_empty`
|
||||
- 否则若 `candidate_pool_size_after_hard_filter == 0` → `hard_filter_all`
|
||||
- 否则若 `candidate_pool_size_after_freqcap == 0` → `freqcap_all`
|
||||
- 否则 → `unknown`
|
||||
|
||||
> 说明:dedup 导致清空通常也会表现为 `after_freqcap==0`(若 dedup 发生在 freqcap 前),V1 先统一归入 `freqcap_all`,并建议在可选字段中输出更细分的 `empty_stage`(例如 `dedup`),后续迭代细化。
|
||||
|
||||
### 4.3 `conf_U` 与 `missing_fields` 口径
|
||||
|
||||
- `conf_U`:直接取 `user_profile.profile_confidence`
|
||||
- `missing_fields`:
|
||||
- `need`: `user_profile.need` 为空对象 `{}` 或不存在
|
||||
- `context`: `user_profile.context` 为空对象 `{}` 或不存在
|
||||
- `emotion`: `user_profile.emotion_score` 为 `null`/不存在
|
||||
|
||||
---
|
||||
|
||||
## 5. 工程落地方式(V1)
|
||||
|
||||
### 5.1 Builder 模式(避免散落)
|
||||
|
||||
推荐在 `reco-engine` 内使用 `RecoMetaBuilder`:
|
||||
|
||||
- 初始化:`builder = RecoMetaBuilder(scene, user_profile, k, now)`
|
||||
- 各阶段更新:
|
||||
- `builder.set_candidate_pool_size_raw(n)`
|
||||
- `builder.set_after_hard_filter(n, risk_filtered_count_by_flag=...)`
|
||||
- `builder.set_after_dedup(n)`
|
||||
- `builder.set_after_freqcap(n, freqcap_filtered_counts=...)`
|
||||
- `builder.set_fallback_level_final(level, reason=...)`
|
||||
- `builder.set_served_k(len(items))`
|
||||
- 最终:`meta = builder.build()`(内部负责 empty_reason 判定与默认值填充)
|
||||
|
||||
### 5.2 API/Celery 的返回策略(边界清晰)
|
||||
|
||||
- `integration-api-worker` 对外返回:
|
||||
- `items`
|
||||
- `meta`(RecoMeta)
|
||||
- 是否对客户端透出所有 meta 字段:
|
||||
- V1 建议:对客户端返回最小必要字段;但服务端事件中保留完整 meta(含可选字段)
|
||||
- 具体裁剪由 API 层决定,Observability 模块只负责提供完整结构
|
||||
|
||||
---
|
||||
|
||||
## 6. 测试计划(V1)
|
||||
|
||||
### 6.1 单元测试(pure)
|
||||
|
||||
- `empty_reason` 判定:
|
||||
- raw=0 → pool_empty
|
||||
- raw>0 且 after_hard_filter=0 → hard_filter_all
|
||||
- after_freqcap=0 → freqcap_all
|
||||
- 单调性断言(若输入不满足单调性,builder 应做防御式 clamp 或记录告警,V1 可选择“以最后写入为准”并在测试中覆盖)
|
||||
|
||||
### 6.2 最小集成验证(与 reco-engine 串联)
|
||||
|
||||
- 构造一次推荐调用:
|
||||
- items 长度与 `served_k` 一致
|
||||
- `candidate_pool_size_*` 与实际阶段产物一致
|
||||
- `served_k=0` 时 `empty_reason` 与清空阶段一致
|
||||
|
||||
---
|
||||
|
||||
## 7. 风险与后续演进
|
||||
|
||||
### 7.1 已知风险
|
||||
|
||||
- V1 可能缺少细分 empty_stage(例如 dedup_all 与 freqcap_all 的区分),导致排障粒度不足。
|
||||
|
||||
### 7.2 演进方向
|
||||
|
||||
- 增加 `empty_stage: "candidate" | "hard_filter" | "dedup" | "freqcap" | "unknown"`,保持与 `empty_reason` 并存。
|
||||
- 增加 `freqcap_filtered_counts`、`risk_filtered_count_by_flag` 的统一结构与上报策略,便于报表按维度聚合。
|
||||
|
||||
130
spec_kit/Personalized Reco/modules/observability/tasks.md
Normal file
130
spec_kit/Personalized Reco/modules/observability/tasks.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# Observability(可观测性与打点载荷)|Tasks
|
||||
|
||||
> 对应计划:`spec_kit/Personalized Reco/modules/observability/plan.md`
|
||||
>
|
||||
> 本清单执行原则:
|
||||
>
|
||||
> - Observability 只负责**统一 meta 结构与构建**,不负责埋点 SDK/落库/上报实现。
|
||||
> - `RecoMeta` 必须可被 `reco-engine` 与 `integration-api-worker` 共同使用(同一结构、同一口径)。
|
||||
|
||||
---
|
||||
|
||||
## 0. 任务标记规则
|
||||
|
||||
- 用勾选框标记执行状态:
|
||||
- `[ ]` 未开始
|
||||
- `[x]` 已完成
|
||||
- 每个任务都要求可独立验收(有明确产出/可运行的检查方式)。
|
||||
|
||||
---
|
||||
|
||||
## 1. 文档对齐(先把口径写死,避免实现漂移)
|
||||
|
||||
- [x] 1.1 校对 `modules/observability/spec.md` 与 `modules/observability/plan.md` 一致性
|
||||
- **检查点**:
|
||||
- `RecoMeta` 必须字段集合一致(scene、candidate_pool_size_*、fallback_level_final、served_k、empty_reason、conf_U、missing_fields)
|
||||
- `empty_reason` 枚举与判定逻辑一致
|
||||
- **验收**:两份文档无冲突;V1 的默认值/缺失策略写清楚。
|
||||
|
||||
---
|
||||
|
||||
## 2. 目录与骨架(与推荐子模块同级)
|
||||
|
||||
- [x] 2.1 新建目录 `server/app/features/personalized_reco/observability/`
|
||||
- **包含**:
|
||||
- `__init__.py`
|
||||
- `types.py`(`RecoMeta`、`MissingFields` 等 Pydantic 模型)
|
||||
- `utils.py`(`compute_empty_reason` 等纯函数)
|
||||
- `builder.py`(`RecoMetaBuilder`:逐阶段填充并 build)
|
||||
- **验收**:可通过 `app.features.personalized_reco.observability.*` 正常 import。
|
||||
|
||||
---
|
||||
|
||||
## 3. 类型定义(稳定契约)
|
||||
|
||||
- [x] 3.1 定义 `MissingFields`(布尔结构)
|
||||
- **字段**:`need/context/emotion`
|
||||
- **验收**:字段名与 `spec.md` 一致;序列化输出稳定。
|
||||
|
||||
- [x] 3.2 定义 `RecoMeta`(统一 meta 载荷)
|
||||
- **必须字段**:
|
||||
- `scene`
|
||||
- `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 必填;served_k>0 可为 None)
|
||||
- `conf_U`
|
||||
- `missing_fields`(`MissingFields`)
|
||||
- **可选字段**:
|
||||
- `risk_filtered_count_by_flag`
|
||||
- `freqcap_filtered_counts`
|
||||
- `config_snapshot`(V1 可先不实现,仅预留字段)
|
||||
- **验收**:字段集合固定;可被 API/Celery 直接返回。
|
||||
|
||||
---
|
||||
|
||||
## 4. 纯函数与判定逻辑(V1 写死)
|
||||
|
||||
- [x] 4.1 实现 `compute_missing_fields(user_profile) -> MissingFields`
|
||||
- **规则**:
|
||||
- need:`user_profile.need` 为空对象 `{}` 或不存在
|
||||
- context:`user_profile.context` 为空对象 `{}` 或不存在
|
||||
- emotion:`user_profile.emotion_score` 为 `null`/不存在
|
||||
- **验收**:单测覆盖三种缺失情况与全不缺失情况。
|
||||
|
||||
- [x] 4.2 实现 `compute_empty_reason(...) -> str | None`
|
||||
- **规则**(对齐 plan):
|
||||
- served_k>0 → None
|
||||
- raw==0 → `pool_empty`
|
||||
- raw>0 且 after_hard_filter==0 → `hard_filter_all`
|
||||
- after_freqcap==0 → `freqcap_all`
|
||||
- 其他 → `unknown`
|
||||
- **验收**:单测覆盖所有分支。
|
||||
|
||||
---
|
||||
|
||||
## 5. Builder(在 pipeline 中逐阶段填充)
|
||||
|
||||
- [x] 5.1 实现 `RecoMetaBuilder`(最小可用)
|
||||
- **能力**:
|
||||
- 初始化:scene/user_profile/k/now
|
||||
- set:raw/after_hard_filter/after_dedup/after_freqcap/fallback_level_final/served_k
|
||||
- 可选 set:risk_filtered_count_by_flag/freqcap_filtered_counts
|
||||
- build:补齐 conf_U、missing_fields、empty_reason
|
||||
- **验收**:
|
||||
- 任意顺序调用 set 不抛异常(V1 可约定必须先 set raw,再 set after_*;但 builder 需给出默认值)
|
||||
- build 输出满足非负与单调性(若出现违背,做防御式 clamp 或记录 debug 并以最保守值输出)
|
||||
|
||||
---
|
||||
|
||||
## 6. 单元测试(pytest)
|
||||
|
||||
- [x] 6.1 新建测试文件 `server/tests/test_observability.py`
|
||||
- **用例覆盖**:
|
||||
- empty_reason 判定所有分支
|
||||
- missing_fields 判定
|
||||
- builder build 输出字段集合稳定
|
||||
- 单调性约束:输入异常时 builder 的防御策略生效(不输出负数)
|
||||
- **验收**:`pytest -q tests/test_observability.py` 通过。
|
||||
|
||||
---
|
||||
|
||||
## 7. 最终自检清单(合入前)
|
||||
|
||||
- [x] 7.1 文档一致性检查
|
||||
- **验收**:`spec.md` / `plan.md` / `RecoMeta` 类型字段一致。
|
||||
|
||||
- [x] 7.2 全量测试通过
|
||||
- **命令**(在 `server/`):
|
||||
- `pytest -q`
|
||||
- **验收**:所有用例通过。
|
||||
|
||||
- [x] 7.3 全部完成后更新大规范 `overview.md`
|
||||
- **变更点**:
|
||||
- 将 `modules/observability/` 标记为“已实施”
|
||||
- 增加一条变更记录(日期 + 交付物:plan/tasks/代码/测试)
|
||||
- **验收**:`spec_kit/Personalized Reco/overview.md` 中模块状态与交付记录准确。
|
||||
|
||||
Reference in New Issue
Block a user