Skip to content

Latest commit

 

History

History
405 lines (308 loc) · 16.9 KB

File metadata and controls

405 lines (308 loc) · 16.9 KB

打分算法说明

本文档说明「未来专业人格卡」的打分算法。实现见 src/lib/score.ts, 对应测试见 src/lib/score.test.ts,依据 PRD v1.1 §8 / §9 / §10。

当前实现的推荐链路是:

18 道双选题 → RIASEC 六维分 → 人格卡 → 人格卡候选专业池排序 → 结果页推荐
                              ↘ 全量 99 大类排序 → 完整专业报告

题目选项绑定的专业大类只提供「提示分」,用于微调排序;完整专业覆盖由 31 张人格卡的 persona.majors 候选池共同承担。

算法对外只有一个入口:

scoreAll(answers: Answer[]): ScoreResult

answers 是用户对 18 道题的作答,每题一条:

interface Answer {
  qIndex: number;        // 题目下标 0–17
  first:  Letter | null; // 「最想做」选项的 RIASEC 字母
  second: Letter | null; // 「第二想做」选项的 RIASEC 字母
}

Letter 为 RIASEC 六维之一:R 现实型 / I 研究型 / A 艺术型 / S 社会型 / E 企业型 / C 常规型。


总览:两层计分

PRD §8.1 的核心思路是「先判人格,再推专业」:

算什么 用途
第一层 RIASEC 兴趣分 决定人格卡(稳定、易分享)
第二层 专业大类提示分 专业推荐贴近学生的具体作答(可细化)

两层结果再加权成「专业推荐分」,对专业大类排序。

数据口径

数据层位于 src/data/quiz.ts,核心有三组:

数据 数量 用途
QUIZ_BANK 18 题 产生 RIASEC 兴趣分和专业提示分
PERSONAS 31 张 承接 30 个有序双维人格 + 1 个「未来多面手」
MAJORS 99 个 专业大类元数据,顺序来自 major_data/major_categories.md

MAJORS.rankmajor_data/major_categories.md 的序号一致,也作为同分时的稳定排序依据。 新增大类没有富详情时,详情页仍走现有「暂无解析」占位;这不影响推荐排序。

PERSONAS[].majors 是当前人格卡的完整专业候选池。31 张卡合起来覆盖 99 个大类; 单张卡通常保留约 9–11 个候选,结果页再从当前卡里切出「优先探索」和「继续了解」。

QUIZ_BANK.options[].majors 不是 99 大类全集,只是该题选项的提示标签。它可以让用户的具体作答 影响同一人格卡内部的排序,但不负责完整覆盖。

题库问题与候选答案(18 题)

  1. 第 1 题(场景题·大学专业开放日):你最想先去哪类展台?
    A. 机器人 / 无人机现场演示
    B. AI / 数据 / 生命科学讲座
    C. 设计 / 影像 / 建筑模型
    D. 心理 / 教育 / 公益项目
    E. 创业路演 / 金融模拟 / 法学辩论
    F. 培养方案 / 录取规则 / 课程表

  2. 第 2 题(项目题·第一学期项目制课程):你最想负责什么?
    A. 做实物原型 / 装置
    B. 查资料 / 实验 / 数据验证
    C. 设计页面 / 海报 / 视觉
    D. 用户访谈 / 同伴辅导
    E. 路演 / 合作沟通 / 资源争取
    F. 预算 / 排期 / 风险管理

  3. 第 3 题(场景题·AI 应用比赛):你更想做哪件事?
    A. 把 AI 接到硬件 / 机器人
    B. 训练或评估 AI 模型
    C. 设计 AI 产品界面 / 脚本
    D. AI 助学 / 心理 / 医疗
    E. 规划 AI 产品商业模式
    F. 整理需求 / 测试 / 数据规范

  4. 第 4 题(选择题·大学实验室 / 实践基地):你想进入哪一个?
    A. 智能制造 / 车辆 / 无人机
    B. 算法 / 生命科学 / 材料
    C. 数字媒体 / 影视 / 建筑设计
    D. 教育实践 / 心理 / 临床
    E. 创业孵化 / 投资 / 模拟法庭
    F. 数据治理 / 供应链 / 政务

  5. 第 5 题(主题题·新能源与双碳):你更想参与什么?
    A. 电池 / 储能 / 能源设备
    B. 碳排放数据 / 政策建模
    C. 低碳传播 / 海报 / 展览
    D. 社区节能 / 公众教育
    E. 新能源商业 / 融资 / 推广
    F. 碳核算 / 项目流程 / 合规

  6. 第 6 题(主题题·医学与健康):你更想做什么?
    A. 康复设备 / 医学影像
    B. 研究疾病 / 药物 / 流行病
    C. 健康科普短视频 / 图文
    D. 陪伴患者 / 心理支持 / 护理
    E. 医疗服务产品 / 医院运营
    F. 病历 / 检验 / 药品合规

  7. 第 7 题(项目题·校园创业项目):你最想负责什么?
    A. 产品样机 / 线下服务流程
    B. 用户数据 / 竞品 / 成本分析
    C. 品牌 / 宣传片 / 短视频
    D. 用户关系 / 客服 / 社群
    E. 定价 / 销售 / 融资路演
    F. 订单 / 库存 / 财务合同

  8. 第 8 题(主题题·未来城市项目):你更想做哪部分?
    A. 交通 / 能源 / 基础设施模型
    B. 人口 / 地理 / 交通数据
    C. 城市公共空间 / 文旅体验
    D. 居民访谈 / 社区治理
    E. 城市招商 / 产业规划
    F. 审批 / 预算 / 风险管理

  9. 第 9 题(项目题·大学生新闻 / 传播项目):你更想负责什么?
    A. 现场拍摄 / 搭直播设备
    B. 核查资料 / 数据 / 证据
    C. 写稿 / 剪片 / 视觉包装
    D. 采访不同群体 / 理解立场
    E. 传播节奏 / 品牌 / 增长
    F. 素材库 / 审核 / 版权流程

  10. 第 10 题(问题题·面对学生学习焦虑):你更想怎么做?
    A. 做一个学习工具 / 教具
    B. 研究学习数据 / 心理机制
    C. 课程动画 / 讲解视频 / 图文
    D. 辅导 / 倾听 / 班级活动
    E. 推广学习产品 / 训练营
    F. 学习计划 / 测评 / 反馈流程

  11. 第 11 题(场景题·一个数据项目):你更想处理哪类数据?
    A. 设备 / 交通 / 能源 / 传感器
    B. 算法 / 金融 / 医学 / 调查
    C. 点击 / 传播 / 体验 / 视觉
    D. 学习 / 心理 / 健康 / 公共服务
    E. 销售 / 消费 / 投资 / 经营
    F. 预算 / 流程 / 供应链 / 档案

  12. 第 12 题(项目题·机器人 / 智能装备项目):你更想做什么?
    A. 结构 / 控制 / 设备调试
    B. 识别算法 / 路径规划
    C. 外观 / 交互 / 展示视频
    D. 服务老人 / 学生 / 社区
    E. 行业应用 / 商业模式
    F. 安全规范 / 测试 / 采购

  13. 第 13 题(主题题·法律和社会议题):你更想做什么?
    A. 走访现场 / 记录证据
    B. 研究法条 / 案例 / 政策
    C. 写评论 / 普法短视频
    D. 为弱势群体咨询 / 调解
    E. 辩论 / 谈判 / 公共倡议
    F. 合同 / 合规 / 档案 / 风控

  14. 第 14 题(场景题·国际交流 / 跨境项目):你更想负责什么?
    A. 跨境物流 / 设备 / 技术对接
    B. 国际市场 / 政策 / 汇率
    C. 翻译 / 写作 / 国际传播
    D. 接待交流学生 / 文化沟通
    E. 商务拓展 / 跨境电商
    F. 合同 / 报关 / 税务 / 合规

  15. 第 15 题(主题题·数字文旅 / 城市文化项目):你更想做什么?
    A. 展陈设备 / 空间动线 / 互动装置
    B. 历史资料 / 游客数据 / 文脉
    C. 短剧 / 展览 / 游戏化体验
    D. 导览服务 / 志愿者培训
    E. 文旅产品 / 商业合作 / 营销
    F. 票务 / 预算 / 版权 / 运营

  16. 第 16 题(展望题·毕业设计):你希望最后呈现什么成果?
    A. 能运行的装置 / 系统 / 工程
    B. 数据 / 实验 / 模型支撑的研究
    C. 作品集 / 短片 / 展览 / 剧本
    D. 帮助人的课程 / 咨询 / 公共服务
    E. 商业计划 / 品牌 / 创业方案
    F. 流程 / 预算 / 标准 / 管理手册

  17. 第 17 题(角色题·大学团队):你最自然会承担哪种角色?
    A. 动手解决设备 / 现场问题
    B. 找资料 / 分析 / 验证判断
    C. 表达 / 审美 / 内容包装
    D. 照顾团队关系 / 支持他人
    E. 争取资源 / 对外推动决策
    F. 管理任务 / 进度 / 资料 / 风控

  18. 第 18 题(终极题·真正选专业时):哪类大学生活最让你愿意投入四年?
    A. 实验室 / 车间 / 现场做实物
    B. 研究问题 / 写代码 / 读论文
    C. 创作作品 / 设计体验 / 讲故事
    D. 帮助人成长 / 变好 / 解决困难
    E. 商业 / 法律 / 谈判 / 公共表达
    F. 规则 / 数据 / 流程 / 系统运行


第一层 · RIASEC 兴趣分

每道题用户选两次,按 PRD §8.1 计分:

最想做(first) → 对应维度 +2
第二想做(second) → 对应维度 +1

完整有效作答时,18 题、每题 2 + 1 = 3 分,六维总分恒为 54(单元测试有断言)。 scoreAll 对空答案、缺少第二选择或越界题号做容错处理,这些边缘输入不会强行补分。

六维累计后降序排序;同分时按 RIASEC 规范序 R < I < A < S < E < C 固定先后, 保证同一组答案每次得到完全一致的结果(确定性)。

排序后的前两维拼成人格代码,按得分主次序书写(主导维在前), 因此「C 排第 1、I 排第 2」得到代码 C-I,而「I 排第 1、C 排第 2」得到 I-C,二者是不同的人格卡, 命中 30 个有序双维人格之一;满足「多面手」条件时则取「未来多面手」(见下文)。 完全平分时由上面的规范序兜底确定谁是主导维,仍保持确定性。


第二层 · 专业大类提示分

每个选项除了一个 RIASEC 字母,还绑定若干「专业大类标签」(见 quiz.ts 中每个 option 的 majors)。 用户选中该选项时,对这些专业大类累加提示分(PRD §8.1):

最想做选项绑定的每个专业大类 → +1.0
第二想做选项绑定的每个专业大类 → +0.5

累计结果记为 hintScore[专业大类]

如果某个专业大类从未出现在用户选中的题目选项里,它的 hintScore 默认为 0,仍会参与 RIASEC 匹配排序。


专业推荐分

对每个专业大类,按 PRD §8.1 的公式算综合推荐分:

推荐分 = 0.65 × RIASEC匹配分 + 0.35 × 题目专业提示分 + 主导维对齐微调

其中 RIASEC 匹配分 r 按学生维度排名命中专业的 RIASEC 标签计:

专业的 RIASEC 标签命中学生第 1 维度 → r += 5
                       第 2 维度 → r += 3
                       第 3 维度 → r += 1

「命中」指专业的标签集合包含该维度,与标签在集合中的位置无关。 题目专业提示分 即上一节的 hintScore[该专业大类]

主导维对齐微调:若专业自身首要标签riasec[0])等于学生第 1 维,则 +0.05。 它小于最小的提示分步长(0.5×0.35=0.175),只在 r 与提示分都打平时拆平局,不会打乱已分高下的排名。 作用是让有序双维卡的正/反两张(如 R-II-R)在专业排序上分出先后—— 那些「骨子里更偏主导维」的专业(如兵器类标签 [R,I,C],首位 R)会对 R 主导用户上浮、对 C 主导用户不上浮。 注:当某专业被用户作答的提示分明显顶高时,提示分优先级高于此微调(这是有意的:实际作答 > 结构性拆平局)。

同分时统一按 rank 升序排序,保证同一组答案每次返回一致结果。


输出专业列表

scoreAll 会生成三类专业列表,取值范围不同:

字段 候选范围 数量 用途
personaMajors 当前 persona.majors 当前人格卡完整候选池 结果页和完整专业报告展示本卡全部候选
priorityMajors 当前 persona.majors 3 本卡候选池前 3 个,高优先级推荐
continueMajors 当前 persona.majors 3 本卡候选池第 4–6 个,继续了解方向
deepReport 全量 99 个 MAJORS 10 完整专业报告

排序都使用同一个「专业推荐分」公式。差别只在候选范围:

  • 结果页推荐只从当前人格卡候选池里取,并展示完整的 personaMajors 顺序
  • priorityMajorscontinueMajors 是为了局部强调,不代表人格卡候选池只有 3 个或 6 个
  • 完整专业报告从 99 个大类全量排序,给用户看到更宽的探索面
  • 多面手结果额外生成 multiTracks,见下文

置信度(PRD §8.2)

PRD §8.2 给出 5 条相互独立、可同时成立的展示规则。算法返回一组布尔标记, 而不是单一枚举,结果页据此可叠加展示多条文案:

interface Confidence {
  mainClear:  boolean;  // 第1名比第2名高 ≥5 分 → 主线很清晰
  dualCore:   boolean;  // 第1名与第2名差 0–4 分 → 双核心人格
  thirdColor: boolean;  // 第2名与第3名差 0–2 分 → 潜在第三色
  multi:      boolean;  // 最高与最低差 <8 分 → 未来多面手
  lowDims:    Letter[]; // 显著偏低的维度
}

判定细节:

标记 条件
mainClear 非多面手,且 gap12 = 第1名 − 第2名 ≥ 5
dualCore 非多面手,且 gap12 ≤ 4
thirdColor 非多面手,且 gap23 = 第2名 − 第3名 ≤ 2
multi spread = 最高分 − 最低分 < 8
lowDims 非多面手时,所有满足 最高分 − 该维度 ≥ 10 的维度

mainCleardualCore 互斥(gap12 要么 ≥5 要么 ≤4),但 dualCorethirdColor 可并存。 对 lowDims 里的维度,结果页用「当前吸引力较低」措辞,禁止写「不适合」(PRD §13.4)。


修订说明:三处与原型设计稿的偏差

设计稿(design-reference/)里的原型打分函数与 PRD 有三处不一致,本实现已修订。

修订 1 · 优先 / 继续了解的取值范围

原型从全量专业大类的排名里切前 3 / 第 4–6。当前数据层已有 99 个专业大类,但 PRD §10 的结果页模板明确是 人格卡专属的专业大类(§9 每张卡的「优先探索专业大类」列、§12.3 的 recommended_major_categories)。

本实现:

  • 候选集 = 当前人格卡的 persona.majors(约 9–11 项)
  • 用「专业推荐分」对候选集排序:全部 → personaMajors,前 3 → priorityMajors,第 4–6 → continueMajors
  • 题目选项绑定的专业大类只作为提示分来源,不承担完整覆盖;完整 99 大类覆盖由人格卡候选池承担
  • 全量 99 大类的推荐分排名单独保留为 deepReport(取前 10),仅供「完整专业报告页」的 深度报告区按需展开(PRD §8.3「深度报告 8–12 个」),不进结果页首屏

修订 2 · 置信度可叠加

原型把置信度做成单选枚举(multi > dual > third > clear 取一个)。 PRD §8.2 是 5 条独立规则,已改为上文的布尔标记组。

修订 3 · 未来多面手动态生成探索线

原型在「多面手」时用「未来多面手」卡的固定 majors 列表。PRD §9 多线行要求 「根据前三高维度生成组合,展示 3 条专业探索线」。

本实现:multi 为真时人格取「未来多面手」卡,但额外按前三高维度各生成一条探索线 —— 每条线 = { 该维度, 该维度下推荐分最高的 1–2 个专业大类 },三条线之间去重,存入 multiTracks


返回结构

interface ScoreResult {
  dim:    Record<Letter, number>;   // 六维原始分
  ordered: [Letter, number][];      // 六维降序(含同分确定性排序)
  top: Letter; second: Letter; third: Letter;
  persona: Persona;                 // 命中的人格卡
  confidence: Confidence;           // 置信度标记组
  personaMajors: Major[];           // 当前人格卡完整候选池,按推荐分排序
  priorityMajors: Major[];          // 修订1:人格卡范围内推荐分前 3
  continueMajors: Major[];          // 修订1:人格卡范围内推荐分第 4–6
  deepReport: Major[];              // 全量 99 排名前 10,供深度报告
  multiTracks?: MultiTrack[];       // 修订3:仅多面手时有,3 条探索线
}

DEMO_RESULT(结果页在「尚未作答」时的占位数据)也通过对一组真实答案跑 scoreAll 生成, 避免演示数据与算法逻辑漂移。


验证

src/lib/score.test.ts 覆盖:

  1. 六维总分恒为 54
  2. 人格代码落在有效 31 张之内
  3. 修订 1personaMajors 覆盖当前人格卡完整候选池,priorityMajors / continueMajors 全部 ⊆ persona.majors
  4. 修订 2:构造 gap12 ≤ 4gap23 ≤ 2 的答案,dualCorethirdColor 同时为 true
  5. 修订 3:构造 spread < 8 的答案,multi 为 true 且 multiTracks 含 3 条线

运行:npm run test

src/data/quiz.test.ts 额外守住数据口径:

  1. MAJORS 恰好 99 项
  2. 名称、顺序、门类与 major_data/major_categories.md 完全一致
  3. rank 为 1–99 且唯一
  4. 所有题目选项与人格卡引用的大类都能被 findMajor 解析
  5. 99 个大类都至少被 1 张人格卡覆盖