477 lines
17 KiB
Markdown
477 lines
17 KiB
Markdown
# 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: What’s 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`: string(ISO8601 时间戳)
|
||
- `profile_confidence`: number(0–1)
|
||
- `profile_answered`: object(标记各题是否作答)
|
||
- **四个维度(V1,V1.2 允许缺失/跳过)**
|
||
- `stage`: one-hot(若题目跳过,按安全策略输出 `unknown=1`)
|
||
- `emotion_score`: number(0–1)或 `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(当下情绪,连续 0–1)
|
||
|
||
该分数不是“快乐程度”,而是**可承受刺激与吸收内容的能力**。分数越低越需要减压、陪伴、允许停下;分数越高才适合庆祝、提醒珍惜等高能量调性内容。
|
||
|
||
映射(固定离散值):
|
||
|
||
| 选项 | 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_confidence(conf_U)
|
||
|
||
默认规则(可配置参数):
|
||
|
||
- 问卷刚完成:`conf_U = 1.0`
|
||
- 随时间衰减(避免用过期状态强个性化推送):
|
||
- 0–7 天:`conf_U = 1.0`
|
||
- 7–30 天:线性衰减到 `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 }
|
||
}
|
||
```
|
||
|
||
#### 用例 B:unknown 语义(不希望被母职身份定义)
|
||
|
||
输入:
|
||
|
||
```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 节;其余字段可沿用任意合法输入。
|
||
|
||
#### 用例 C:0–7 天(不衰减)
|
||
|
||
- `profile_generated_at = 2026-01-01T00:00:00Z`
|
||
- `now = 2026-01-05T00:00:00Z`
|
||
|
||
期望:`profile_confidence = 1.0`
|
||
|
||
#### 用例 D:7–30 天(线性衰减到 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`)。
|
||
|
||
#### 用例 E:30 天以上(固定为 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`(字符串数组)用于下游与回归测试
|
||
|
||
#### 用例 F:emotion_score ≤ 0.2 禁推 joyful 调性
|
||
|
||
输入:
|
||
|
||
```json
|
||
{
|
||
"mom_stage": "expecting",
|
||
"emotion": "overwhelmed",
|
||
"context": "health",
|
||
"need": "anxiety_relief"
|
||
}
|
||
```
|
||
|
||
期望:
|
||
|
||
- `emotion_score = 0.2`
|
||
- 规则命中:`emotion_score ≤ 0.2` → 禁推高能量庆祝型(joyful 调性)内容
|
||
|
||
#### 用例 G:stage.unknown 禁推“育儿压力 + 高个性化”内容
|
||
|
||
输入:
|
||
|
||
```json
|
||
{
|
||
"mom_stage": "unknown",
|
||
"emotion": "calm",
|
||
"context": "family",
|
||
"need": "parenting_pressure"
|
||
}
|
||
```
|
||
|
||
期望:
|
||
|
||
- `stage.unknown = 1`
|
||
- 规则命中:`stage.unknown = 1` → 下游禁推满足以下条件的内容:
|
||
- `need: parenting_pressure`
|
||
- `personalization_power = 1`
|
||
|