Files
mindfulness/spec_kit/Personalized Reco/modules/observability/plan.md
2026-02-02 16:47:37 +08:00

7.1 KiB
Raw Blame History

Observability可观测性与打点载荷Plan

对应规范:spec_kit/Personalized Reco/modules/observability/spec.md

规则来源(必须对齐):

  • 设计说明文档/個性化推薦算法規則.mdcandidate_pool_size_*、fallback_level_final、empty_reason 等必打点字段)
  • spec_kit/Personalized Reco/overview.md(模块边界:本模块被 reco-engineintegration-api-worker 共同使用)

1. 目标与交付物

1.1 目标

  • 定义推荐模块统一的 RecoMetameta/event 载荷),随推荐结果一起返回,由调用方负责上报/落库/打点。
  • 确保每次推荐调用都能产出可用于监控与排障的关键字段:
    • 覆盖率、回退率、候选规模分布、过滤原因分布
    • served_k=0 时必须给出准确的 empty_reason(定位清空阶段)
  • 与现有子模块接口对齐:
    • 候选生成content-repository
    • Hard Filter引擎阶段
    • Soft Scoringscoring
    • Rerank/Freqcaprerank-freqcap

1.2 交付物

  • modules/observability/plan.md:本技术计划(本文件)。
  • 代码实现(后续 tasks 阶段落地)建议位置:
    • server/app/features/personalized_reco/observability/
    • 包含:
      • types.pyRecoMetaPydantic BaseModel
      • builder.pyRecoMetaBuilder(在 pipeline 中逐步填充)
      • utils.pyempty_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_Umissing_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_filterHard Filter 过滤后的候选数
    • candidate_pool_size_after_dedup:去重(基于历史集合)后的候选数
    • candidate_pool_size_after_freqcap:频控/冷却后的候选数(包含作者/模板维度若执行)
    • served_k:最终输出 items 的长度(≤ k

4.2 empty_reasonserved_k=0 时必填)

枚举建议(对齐 spec

  • hard_filter_all
  • freqcap_all
  • pool_empty
  • unknown

判定逻辑V1 推荐写死,保证阶段一致):

  • candidate_pool_size_raw == 0pool_empty
  • 否则若 candidate_pool_size_after_hard_filter == 0hard_filter_all
  • 否则若 candidate_pool_size_after_freqcap == 0freqcap_all
  • 否则 → unknown

说明dedup 导致清空通常也会表现为 after_freqcap==0(若 dedup 发生在 freqcap 前V1 先统一归入 freqcap_all,并建议在可选字段中输出更细分的 empty_stage(例如 dedup),后续迭代细化。

4.3 conf_Umissing_fields 口径

  • conf_U:直接取 user_profile.profile_confidence
  • missing_fields
    • need: user_profile.need 为空对象 {} 或不存在
    • context: user_profile.context 为空对象 {} 或不存在
    • emotion: user_profile.emotion_scorenull/不存在

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
    • metaRecoMeta
  • 是否对客户端透出所有 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=0empty_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_countsrisk_filtered_count_by_flag 的统一结构与上报策略,便于报表按维度聚合。