Files
mindfulness/spec_kit/User Profile Scoring/spec.md
2026-02-02 11:22:35 +08:00

477 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# User Profile Scoring高层规范
## 1. 背景与目标
本模块用于将 Onboarding 问卷答案转换为标准化、可计算、可版本化的**用户画像User Profile**,供其他模块(个性化推荐 / Push 推送排序 / 内容过滤)统一调用。
### 1.1 问卷信息V1.2,供外部 UI 实现;支持可跳过)
本模块**不接入 UI**,仅定义“问卷答案 → 用户画像”的规则。外部 UI或服务端只需在用户完成 Onboarding 问卷后,按以下题目将答案编码为枚举值并调用本模块。
V1.2 题目集合(每题**可跳过**;作答时为单选;**中英对齐**
#### Q1 母职阶段(`mom_stage`
- 中文:你处于哪个母职阶段?
- English: Which stage of motherhood are you in?
| UI 展示(中文) | UI 展示English | 枚举值(提交给本模块) |
| --- | --- | --- |
| 备孕 / 怀孕 / 准备迎接宝宝 | Pregnant / Preparing | `expecting` |
| 已经在育儿阶段 | Parenting | `parenting` |
| 不想说 / 不希望被母职身份定义 | Prefer not to say | `unknown` |
#### Q2 当下情绪(`emotion`
- 中文:你现在感觉如何?
- English: How are you feeling right now?
| UI 展示(中文) | UI 展示English | 枚举值(提交给本模块) |
| --- | --- | --- |
| 低落 | Low | `low` |
| 过载 / 不堪重负 | Overwhelmed | `overwhelmed` |
| 疲惫 | Tired | `tired` |
| 还好 / 一般 | Okay | `neutral` |
| 平静 | Calm | `calm` |
| 愉悦 | Joyful | `joyful` |
#### Q3 主要触发场景(`context`
- 中文:这些感受主要受到什么影响?
- English: Whats been influencing how you feel?
| UI 展示(中文) | UI 展示English | 枚举值(提交给本模块) |
| --- | --- | --- |
| 家庭 | Family | `family` |
| 工作或学习 | Work or study | `work` |
| 亲密关系 | Relationship | `relationship` |
| 朋友 | Friends | `friends` |
| 健康 | Health | `health` |
#### Q4 最需要的支持(`need`
- 中文:你现在最需要哪一种支持?
- English: What kind of support do you need most right now?
| UI 展示(中文) | UI 展示English | 枚举值(提交给本模块) |
| --- | --- | --- |
| 情绪支持 | Emotional support | `emotional_support` |
| 育儿压力 | Parenting pressure | `parenting_pressure` |
| 自我价值 | Self-worth | `self_worth` |
| 缓解焦虑 | Anxiety relief | `anxiety_relief` |
| 休息与平衡 | Rest & balance | `rest_balance` |
说明:
- 外部 UI 可自由决定视觉样式,但建议文案**中英成对出现**并与上表一致;无论文案如何变化,**答案编码必须与上述枚举一致**,以保证跨端一致性与可回归测试。
- 每一题允许用户**跳过不答**;当题目被跳过时,外部调用可选择“不传该字段”或传 `null`(以具体接口约定为准),本模块将按第 6.1.1 节输出 `profile_answered` 并生成保守画像。
- 后续若扩展为多选(例如 `context/need` 多选),应遵循第 8 节兼容策略,保持 V1 输出结构可向后兼容。
该模块的设计原则:
- **不做心理诊断**:只描述「此刻允许被如何对待」
- 区分 **身份(离散)****状态(连续)**
- 允许「通用」与「高个性化」内容并存,并通过置信度控制“个性化力度”
来源规则文档:`设计说明文档/客戶端問卷打分規則.md`V1 / V1.1 / V1.2
## 2. 模块定位与边界
### 2.1 负责In Scope
- 定义**统一画像结构**(字段、类型、取值范围)
- 定义从问卷答案到画像的**映射规则**V1
- 生成画像的**元信息**V1.1:版本、来源、生成时间、置信度)
- 提供最小可复用的“硬规则”输出(用于下游模块做禁推/降风险)
### 2.2 不负责Out of Scope
- 不负责具体推荐算法实现(相似度计算、排序、探索/利用策略等)
- 不负责内容标签的生成与管理(内容画像 Cᵢ 的维护属于内容/推荐模块)
- 不负责长期行为信号融合(行为修正可在后续版本扩展)
## 3. 关键概念
- **用户画像 U**:由问卷生成,描述用户阶段、状态与当下需求
- **内容画像 Cᵢ**:内容侧标签/强度(由内容模块维护)
- **置信度 conf_U**:画像可靠程度(用于推送等高风险场景的降个性化/降风险)
## 4. 输入与输出(对外接口)
### 4.1 输入(问卷答案)
V1.2:每题**可跳过**;作答时为**单选**
- `mom_stage?``expecting | parenting | unknown`
- `emotion?``low | overwhelmed | tired | neutral | calm | joyful`
- `context?``family | work | relationship | friends | health`
- `need?``emotional_support | parenting_pressure | self_worth | anxiety_relief | rest_balance`
> 说明:
>
> - 带 `?` 表示该字段允许缺失(题目跳过)。
> - 多选 `context/need` 可在后续版本扩展,但 V1 输出结构需保持可兼容升级。
### 4.2 输出(用户画像)
输出为一个 JSON 对象(或等价的 TypeScript 类型),包含:
- **元信息V1.2**
- `profile_version`: string`"v1.2"`
- `profile_source`: `"questionnaire"`(后续可扩展 `"behavior"` / `"mixed"`
- `profile_generated_at`: stringISO8601 时间戳)
- `profile_confidence`: number01
- `profile_answered`: object标记各题是否作答
- **四个维度V1V1.2 允许缺失/跳过)**
- `stage`: one-hot若题目跳过按安全策略输出 `unknown=1`
- `emotion_score`: number01`null`(题目跳过)
- `context`: one-hot 或空对象 `{}`(题目跳过)
- `need`: one-hot 或空对象 `{}`(题目跳过)
推荐的最小输出示例(结构示意):
```json
{
"profile_version": "v1.2",
"profile_source": "questionnaire",
"profile_generated_at": "2026-01-30T00:00:00Z",
"profile_confidence": 1.0,
"profile_answered": { "stage": true, "emotion": true, "context": true, "need": true },
"stage": { "expecting": 0, "parenting": 1, "unknown": 0 },
"emotion_score": 0.4,
"context": { "work": 1 },
"need": { "rest_balance": 1 }
}
```
题目跳过时的最小输出示例V1.2
```json
{
"profile_version": "v1.2",
"profile_source": "questionnaire",
"profile_generated_at": "2026-01-30T00:00:00Z",
"profile_confidence": 0.5,
"profile_answered": { "stage": false, "emotion": false, "context": false, "need": false },
"stage": { "unknown": 1 },
"emotion_score": null,
"context": {},
"need": {}
}
```
## 5. 画像字段定义V1
### 5.1 mom_stage母职阶段离散
映射one-hot
- Pregnant / Preparing → `stage.expecting = 1`
- Parenting → `stage.parenting = 1`
- Prefer not to say → `stage.unknown = 1`
语义约束:
- `unknown` 的语义是:**不希望被母职身份定义**(不是“没有孩子”)
- 若题目被跳过:按安全策略输出 `stage.unknown = 1`,同时 `profile_answered.stage=false`
### 5.2 emotion当下情绪连续 01
该分数不是“快乐程度”,而是**可承受刺激与吸收内容的能力**。分数越低越需要减压、陪伴、允许停下;分数越高才适合庆祝、提醒珍惜等高能量调性内容。
映射(固定离散值):
| 选项 | tag | emotion_score |
| --- | --- | --- |
| Low | emotion: low | 0.0 |
| Overwhelmed | emotion: overwhelmed | 0.2 |
| Tired | emotion: tired | 0.4 |
| Okay | emotion: neutral | 0.6 |
| Calm | emotion: calm | 0.8 |
| Joyful | emotion: joyful | 1.0 |
输出:`emotion_score ∈ [0,1]`;若题目被跳过则输出 `null`(或不输出该字段),并通过 `profile_answered.emotion=false` 表示“未作答”
### 5.3 context影响来源离散
映射one-hot
- Family → `context.family = 1`
- Work or study → `context.work = 1`
- Relationship → `context.relationship = 1`
- Friends → `context.friends = 1`
- Health → `context.health = 1`
若题目被跳过:
- 输出 `context = {}`
- `profile_answered.context = false`
语义说明:
- `context` 不是情绪,而是情绪的“触发场景”
- 用于提升内容共感(语境命中),而非硬性过滤
### 5.4 need最需要的支持离散推荐权重最高
映射one-hot
- Emotional support → `need.emotional_support = 1`
- Parenting pressure → `need.parenting_pressure = 1`
- Self-worth → `need.self_worth = 1`
- Anxiety relief → `need.anxiety_relief = 1`
- Rest & balance → `need.rest_balance = 1`
若题目被跳过:
- 输出 `need = {}`
- `profile_answered.need = false`
语义说明:
- `need` 是**推荐权重最高的维度**
- 表示“她现在最缺的是哪一种心理资源”
## 6. 元信息与置信度V1.2
### 6.1 profile_version / source / generated_at
- `profile_version`:用于规则升级与兼容(建议从 `"v1.2"` 起步;本规范与规则文档已对齐 V1.2
- `profile_source`:固定为 `"questionnaire"`(后续可扩展)
- `profile_generated_at`:画像生成时间(用于推送降风险)
### 6.1.1 profile_answered支持题目可跳过V1.2
> 目的:区分“明确选择 unknown”与“题目被跳过导致 unknown/缺失”,并让下游在不确定时自动降个性化/降风险。
- `profile_answered`:记录每一题是否作答
- `stage/emotion/context/need``true/false`
输出约定与设计说明文档保持一致V1.2
- `mom_stage` 被跳过:按安全策略输出 `stage.unknown = 1`,同时 `profile_answered.stage=false`
- `emotion` 被跳过:`emotion_score` 输出 `null`(或不输出该字段),同时 `profile_answered.emotion=false`
- `context` 被跳过:`context` 输出为空对象 `{}`,同时 `profile_answered.context=false`
- `need` 被跳过:`need` 输出为空对象 `{}`,同时 `profile_answered.need=false`
### 6.2 profile_confidenceconf_U
默认规则(可配置参数):
- 问卷刚完成:`conf_U = 1.0`
- 随时间衰减(避免用过期状态强个性化推送):
- 07 天:`conf_U = 1.0`
- 730 天:线性衰减到 `0.7`
- 30 天以上:`conf_U = 0.5`(除非用户重新做问卷或有行为信号更新)
V1.2 补充:叠加“作答完整度”(题目可跳过场景):
-`answered_count = Σ I[profile_answered.* = true]`,总题数 `total_questions = 4`
- `completion = answered_count / total_questions`
- `completion_factor = 0.5 + 0.5 * completion`
- `conf_U = clamp(conf_time * completion_factor, 0.2, 1.0)`(其中 `conf_time` 按时间衰减得到)
下游使用建议:
- Push 推送等高风险场景:当 `conf_U` 低时,应启用不确定性惩罚(例如 `P_uncertainty`)并限制个性化力度上限。
## 7. 跨维度硬规则Hard Rules输出
本模块应向下游暴露“可直接执行”的硬规则结果(例如 `forbidden_tags``content_tone_blacklist`),以保证在任何排序之前先做安全过滤。
V1.2 核心禁推规则:
1. **`stage.unknown = 1`**
- 禁推:强指向育儿压力且高个性化的内容(用于避免“把她当妈妈/正在育儿”的对话)
- 条件(由下游在内容侧判定):`need: parenting_pressure``personalization_power = 1`
2. **`stage.parenting = 1`**
- 禁推:明确怀孕 / 孕期 / 胎动等内容
3. **`emotion_score ≤ 0.2`low / overwhelmed**
- 禁推高能量庆祝型joyful 调性)内容
原则说明:
- 这些不是“答案不准”,而是“会造成反感或退出”的高风险匹配,应始终优先执行。
## 8. 兼容性与演进策略
- **向后兼容**:新版本字段可新增,但不得破坏 V1 的四维度结构与含义
- **多选扩展**:后续允许 `context/need` 多选时,输出仍可保持 one-hot但可允许多个 key=1并提供归一化规则
- **行为融合**:后续可引入 `profile_source=mixed`,将行为信号用于修正 `emotion_score` 或补全缺失维度,但必须保留 `questionnaire` 原始画像以便可观测与回溯
## 9. 验收标准(模块级)
- Onboarding 填写完成后,能够生成符合本规范的用户画像对象
- 输出包含元信息(版本、来源、时间、置信度)与四维度字段
- 硬规则输出可被推荐/推送模块直接用于过滤(先过滤、后打分)
## 10. 测试(输入题目答案 → 输出用户画像)
> 本模块作为**独立模块**暂不接入 UI外部 UI 只需按本规范提供枚举答案,本模块输出标准化用户画像对象。以下用例用于外部 UI / 服务端编写自动化测试,验证“输入答案 → 输出画像”稳定且可版本化。
### 10.1 测试约定(为可重复性而设)
- `profile_version`:固定为 `"v1.2"`
- `profile_source`:固定为 `"questionnaire"`
- `profile_generated_at`:测试用例中使用固定时间戳(避免随系统时间波动)
- `profile_confidence`
- 若“刚完成问卷”,测试时可令 `now == profile_generated_at`,期望 `profile_confidence = 1.0`
- 若测试时间衰减,则固定 `profile_generated_at``now`,按第 6.2 节规则计算期望值
### 10.2 字段映射用例(基础正确性)
#### 用例 A完整映射parenting + tired + work + rest_balance
输入(题目答案):
```json
{
"mom_stage": "parenting",
"emotion": "tired",
"context": "work",
"need": "rest_balance"
}
```
期望输出(用户画像;示例中 `profile_generated_at` 由测试固定注入):
```json
{
"profile_version": "v1.2",
"profile_source": "questionnaire",
"profile_generated_at": "2026-01-30T00:00:00Z",
"profile_confidence": 1.0,
"profile_answered": { "stage": true, "emotion": true, "context": true, "need": true },
"stage": { "expecting": 0, "parenting": 1, "unknown": 0 },
"emotion_score": 0.4,
"context": { "work": 1 },
"need": { "rest_balance": 1 }
}
```
#### 用例 Bunknown 语义(不希望被母职身份定义)
输入:
```json
{
"mom_stage": "unknown",
"emotion": "neutral",
"context": "relationship",
"need": "emotional_support"
}
```
期望输出(关键点:`stage.unknown = 1`
```json
{
"profile_version": "v1.2",
"profile_source": "questionnaire",
"profile_generated_at": "2026-01-30T00:00:00Z",
"profile_confidence": 1.0,
"profile_answered": { "stage": true, "emotion": true, "context": true, "need": true },
"stage": { "expecting": 0, "parenting": 0, "unknown": 1 },
"emotion_score": 0.6,
"context": { "relationship": 1 },
"need": { "emotional_support": 1 }
}
```
#### 用例 A2全部跳过V1.2 最小可计算画像)
输入(所有题都跳过;用“不传字段”的方式表示):
```json
{}
```
期望输出(关键点:`profile_answered` 全 false`stage.unknown=1``emotion_score=null``context/need={}`
```json
{
"profile_version": "v1.2",
"profile_source": "questionnaire",
"profile_generated_at": "2026-01-30T00:00:00Z",
"profile_confidence": 0.5,
"profile_answered": { "stage": false, "emotion": false, "context": false, "need": false },
"stage": { "unknown": 1 },
"emotion_score": null,
"context": {},
"need": {}
}
```
### 10.3 置信度衰减用例(时间维度)
> 本组用例只验证 `profile_confidence` 计算是否符合第 6.2 节;其余字段可沿用任意合法输入。
#### 用例 C07 天(不衰减)
- `profile_generated_at = 2026-01-01T00:00:00Z`
- `now = 2026-01-05T00:00:00Z`
期望:`profile_confidence = 1.0`
#### 用例 D730 天(线性衰减到 0.7
- `profile_generated_at = 2026-01-01T00:00:00Z`
- `now = 2026-01-11T00:00:00Z`(第 10 天)
期望:`profile_confidence ≈ 1.0 - 0.3 * (10 - 7) / (30 - 7) ≈ 0.9609`
> 测试建议:用浮点容差断言(例如 `abs(actual - expected) <= 1e-3`)。
#### 用例 E30 天以上(固定为 0.5
- `profile_generated_at = 2026-01-01T00:00:00Z`
- `now = 2026-02-15T00:00:00Z`
期望:`profile_confidence = 0.5`
### 10.4 硬规则触发用例(可选,但建议覆盖)
> 本节只验证“规则是否被触发”。由于第 7 节目前只规定了规则语义,未强约束硬规则输出字段结构,测试可用两种方式之一:
>
> - 方式 1若实现提供 `hard_rules`(或同义字段),则断言其包含对应禁推项
> - 方式 2实现不提供结构化 `hard_rules` 时,至少应提供可观测的 `rule_hits`(字符串数组)用于下游与回归测试
#### 用例 Femotion_score ≤ 0.2 禁推 joyful 调性
输入:
```json
{
"mom_stage": "expecting",
"emotion": "overwhelmed",
"context": "health",
"need": "anxiety_relief"
}
```
期望:
- `emotion_score = 0.2`
- 规则命中:`emotion_score ≤ 0.2` → 禁推高能量庆祝型joyful 调性)内容
#### 用例 Gstage.unknown 禁推“育儿压力 + 高个性化”内容
输入:
```json
{
"mom_stage": "unknown",
"emotion": "calm",
"context": "family",
"need": "parenting_pressure"
}
```
期望:
- `stage.unknown = 1`
- 规则命中:`stage.unknown = 1` → 下游禁推满足以下条件的内容:
- `need: parenting_pressure`
- `personalization_power = 1`