17 KiB
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 | unknownemotion?:low | overwhelmed | tired | neutral | calm | joyfulcontext?:family | work | relationship | friends | healthneed?: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 或空对象{}(题目跳过)
推荐的最小输出示例(结构示意):
{
"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):
{
"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=falseemotion被跳过:emotion_score输出null(或不输出该字段),同时profile_answered.emotion=falsecontext被跳过:context输出为空对象{},同时profile_answered.context=falseneed被跳过: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(除非用户重新做问卷或有行为信号更新)
- 0–7 天:
V1.2 补充:叠加“作答完整度”(题目可跳过场景):
- 设
answered_count = Σ I[profile_answered.* = true],总题数total_questions = 4 completion = answered_count / total_questionscompletion_factor = 0.5 + 0.5 * completionconf_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 核心禁推规则:
stage.unknown = 1- 禁推:强指向育儿压力且高个性化的内容(用于避免“把她当妈妈/正在育儿”的对话)
- 条件(由下游在内容侧判定):
need: parenting_pressure且personalization_power = 1
- 条件(由下游在内容侧判定):
- 禁推:强指向育儿压力且高个性化的内容(用于避免“把她当妈妈/正在育儿”的对话)
stage.parenting = 1- 禁推:明确怀孕 / 孕期 / 胎动等内容
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)
输入(题目答案):
{
"mom_stage": "parenting",
"emotion": "tired",
"context": "work",
"need": "rest_balance"
}
期望输出(用户画像;示例中 profile_generated_at 由测试固定注入):
{
"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 语义(不希望被母职身份定义)
输入:
{
"mom_stage": "unknown",
"emotion": "neutral",
"context": "relationship",
"need": "emotional_support"
}
期望输出(关键点:stage.unknown = 1):
{
"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 最小可计算画像)
输入(所有题都跳过;用“不传字段”的方式表示):
{}
期望输出(关键点:profile_answered 全 false;stage.unknown=1;emotion_score=null;context/need={}):
{
"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:00Znow = 2026-01-05T00:00:00Z
期望:profile_confidence = 1.0
用例 D:7–30 天(线性衰减到 0.7)
profile_generated_at = 2026-01-01T00:00:00Znow = 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:00Znow = 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 调性
输入:
{
"mom_stage": "expecting",
"emotion": "overwhelmed",
"context": "health",
"need": "anxiety_relief"
}
期望:
emotion_score = 0.2- 规则命中:
emotion_score ≤ 0.2→ 禁推高能量庆祝型(joyful 调性)内容
用例 G:stage.unknown 禁推“育儿压力 + 高个性化”内容
输入:
{
"mom_stage": "unknown",
"emotion": "calm",
"context": "family",
"need": "parenting_pressure"
}
期望:
stage.unknown = 1- 规则命中:
stage.unknown = 1→ 下游禁推满足以下条件的内容:need: parenting_pressurepersonalization_power = 1