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,143 @@
# User Profile Scoring任务清单 · V1.2
> 依据:`spec_kit/User Profile Scoring/plan.md`V1.2
>
> 规则目标:在客户端实现“问卷答案(可跳过)→ 用户画像(含 profile_answered/confidence+ 硬规则输出”,供推荐/Push/Widget 复用。
## 任务状态说明
- `[ ]`:未开始
- `[~]`:进行中
- `[x]`:已完成
- `[-]`:已取消/不做
---
## A. 代码实现(客户端 TypeScript 模块)
### A1. 建立目录与导出入口
- [x]`client/src/features/` 下新增目录 `userProfileScoring/`
- **验收**:目录存在,且后续文件均放入该目录
- [x] 新建 `client/src/features/userProfileScoring/index.ts`
- **内容**:对外导出主函数与类型(避免上层直接深路径 import
- **验收**:上层可仅从 `.../userProfileScoring` 引入
### A2. 定义类型与枚举V1.2
- [x] 新建 `client/src/features/userProfileScoring/types.ts`
- **定义输入类型**`QuestionnaireAnswersV1_2`
- 字段允许 `undefined`/`null``mom_stage/emotion/context/need`
- **定义输出类型**`UserProfileV1_2`
- 固定 `profile_version: "v1.2"``profile_source: "questionnaire"`
- `profile_answered``{ stage; emotion; context; need }`
- `emotion_score: number | null`
- `context/need: Record<string, 1>`(稀疏 one-hot跳过为 `{}`
- **定义扩展输出类型**`UserProfileV1_2_Extended`
- `rule_hits: string[]`
- `hard_rules: { forbidden_risk_flags: string[]; forbidden_content_predicates: ... }`
- **验收**:类型字段与 `spec_kit/User Profile Scoring/spec.md`V1.2)一致
### A3. 实现答案归一化(非法值按跳过)
- [x] 新建 `client/src/features/userProfileScoring/scoring.ts`
- [x] 实现 `normalizeAnswers(raw): QuestionnaireAnswersV1_2`
- **规则**
- 值不在枚举内 → 归一化为 `undefined`
- `null` 保留为 `null`(表示显式跳过/无值)
- **验收**:任意输入不抛错;输出只包含合法枚举/`undefined`/`null`
### A4. 计算 profile_answeredV1.2
- [x] 实现 `computeProfileAnswered(normalized)`
- `stage = (mom_stage !== undefined && mom_stage !== null)`
- `emotion/context/need` 同理
- **验收**:与 `spec.md` 6.1.1 一致;可区分“缺失/跳过”与“明确作答”
### A5. 计算时间衰减 conf_time
- [x] 实现 `computeTimeConfidence(generatedAt, now): number`
- **规则**(与 `spec.md` 6.2 一致):
- 07 天1.0
- 730 天:线性衰减到 0.7
- 30 天以上0.5
- **验收**:给定固定时间输入,输出符合分段规则(允许浮点误差)
### A6. 计算 profile_confidenceV1.2 完整度因子 + clamp
- [x] 实现 `computeProfileConfidence(conf_time, profile_answered): number`
- **规则**(与 `设计说明文档/客戶端問卷打分規則.md` V1.2 一致):
- `answered_count = Σ I[profile_answered.* = true]`
- `completion = answered_count / 4`
- `completion_factor = 0.5 + 0.5 * completion`
- `conf = clamp(conf_time * completion_factor, 0.2, 1.0)`
- **验收**
- 全部跳过且 `conf_time=1``conf=0.5`
- 全部作答且 `conf_time=1``conf=1.0`
- 极端情况下不会低于 0.2 / 高于 1.0
### A7. 生成四维度画像字段(含跳过策略)
- [x] 实现 `buildUserProfileFromQuestionnaire(answers, options)`
- **元信息**
- `profile_version="v1.2"`
- `profile_source="questionnaire"`
- `profile_generated_at`:允许注入;默认 `new Date().toISOString()`
- **stage**
-`mom_stage` 缺失/为 `null`:按安全策略输出 `stage.unknown=1`
- 若为枚举:对应 one-hot
- **emotion_score**
- 若跳过:`null`
- 否则按映射表输出数值
- **context/need**
- 若跳过:输出 `{}`
- 否则输出稀疏 one-hot例如 `{ work: 1 }`
- **验收**:与 `spec.md` 4.2/5.x/6.x 一致
### A8. 硬规则与可观测输出rule_hits / hard_rules
- [x]`buildUserProfileFromQuestionnaire` 内生成 `rule_hits``hard_rules`
- **risk_flags 映射规则**(与 `spec.md` 7 一致):
- `stage.unknown=1``unsafe_for_stage_unknown`
- `stage.parenting=1``unsafe_for_stage_parenting`
- `emotion_score !== null && emotion_score<=0.2``unsafe_for_emotion_low`
- **跨维度规则谓词**(与 `spec.md` 7、客户端规则 V1.2 一致):
-`stage.unknown=1`:追加谓词
- `id`: 建议 `unknown_block_parenting_pressure_personalized`
- `when_user`: `{ stage_unknown: true }`
- `forbid_content`: `{ need: "parenting_pressure", personalization_power: 1 }`
- **验收**
- 输出结构稳定
- 不依赖内容侧字段(本模块只输出“可执行条件”)
---
## B. 单元测试(只测纯函数)
> 若当前工程暂不引入测试框架,可先把测试用例写成“可执行脚本/最小断言”;但建议最终落地 `vitest` 或 `jest`。
### B1. 建立测试框架(可选但建议)
- [x]`client/` 尚无测试:引入 `vitest`(或 `jest`)并添加 `test` 脚本
- **验收**:能在本机运行测试并输出结果
### B2. 覆盖 spec.md 的关键用例
- [x] 用例:完整作答映射正确(对应 `spec.md` 用例 A/B
- [x] 用例:时间衰减(对应 `spec.md` 用例 C/D/E
- [x] 用例:全部跳过 `{}`(对应 `spec.md` 用例 A2
- 断言:`profile_answered` 全 false`stage.unknown=1``emotion_score=null``context/need={}``profile_confidence=0.5`(当 conf_time=1
- [x] 用例:硬规则命中
- `emotion_score<=0.2` → 含 `unsafe_for_emotion_low`
- `stage.parenting=1` → 含 `unsafe_for_stage_parenting`
- `stage.unknown=1` → 含 `unsafe_for_stage_unknown` 且带跨维度谓词
---
## C. 接入与文档回写(后续任务)
- [ ] Onboarding 提交问卷处接入本模块(调用 `buildUserProfileFromQuestionnaire`
- **验收**:提交后能生成并持久化/上传画像对象(具体存储策略由上层决定)
- [ ] 在推荐/Push/Widget 侧消费 `hard_rules`
- **验收**Hard Filter 在打分前执行;且能使用跨维度谓词表达 unknown+育儿压力强个性化禁推