原神 MBTI 计算方式详细说明
一、总体架构
原神 MBTI 以玩家在米游社的游戏数据为基础,通过 五个"提瓦特维度" 的评分算法,将玩家人格映射为 32 种"神级代号"之一。
整体数据流如下:
米游社 API(index + 深渊 + 抽卡记录 + 旅行札记)
↓
MbtiRawData(标量数据抽平)
↓
GenshinMbtiCalculator(五维评分)
↓
GenshinMbtiCodex(代号匹配)
↓
GenshinMbtiResult(最终结果:五维分数 + 神级代号 + 评语)
核心设计原则:算法层(GenshinMbtiCalculator)只依赖标量数据(MbtiRawData),不直接依赖米游社模型,实现"逻辑/表单分离",便于单元测试与未来扩展。
二、数据来源
2.1 游戏档案 index 接口
调用米游社 game_record/app/genshin/api/index 接口,返回 GameRecordIndex,包含:
- avatars:角色列表(等级、命座、好感度、武器等)
- world_explorations:各区域世界探索度
- homes:尘歌壶数据(洞天仙力、信任等阶、摆设数量)
- stats:统计信息(活跃天数、成就总数、八类神瞳收集数)
此接口在
GameRecordService.GetGenshinIndexAsync中有 5 分钟内存缓存,避免频繁请求。
2.2 深境螺旋接口
调用 spiralAbyss?schedule_type=1 获取当期深渊数据 SpiralAbyssInfo,提取 RevealRank(出场角色排行),用于维度1 的"深渊出场角色练度"计算。
2.3 本地抽卡记录
从本地数据库的 GenshinGachaItem 表中查询已同步的抽卡记录,通过 GenshinGachaService.GetGachaTypeStats 计算出总抽数、五星数、角色池当前保底距离。
2.4 旅行札记接口
调用 TravelersDiary 接口获取当月原石收入(结果自动入库),再从数据库取最近两个月原石数据求和,用于维度4 的"原石收入信号"。
三、标量数据抽平(MbtiRawData.From)
在计算评分前,米游社的嵌套模型被"抽平"为一组标量字段。这是算法层与数据层的边界:
3.1 玩家信息
Uid:角色 UIDNickname:昵称AvatarUrl:头像 URL(取自 index.HeadIcon)RegionName:服务器名Level:冒险等阶
3.2 维度1 字段(角色练度)
AvatarCount:index 中的角色总数MaxLevelCount:等级 ≥ 90 的角色数C6Count:命座 ≥ 6(满命)的角色数Fetter10Count:好感度 ≥ 10(满好感)的角色数AvgFetter:所有角色的平均好感度AvgConstellation:所有角色的平均命座数AbyssAvatarCount:深渊出场角色数(取 index.avatars 与 abyss.revealRank 的交集)AbyssAvgLevel:深渊出场角色的平均等级AbyssAvgConstellation:深渊出场角色的平均命座数
深渊交集逻辑:从深渊
RevealRank取出出场角色的AvatarId集合,再与 index 中的角色列表取交集,确保只统计"实际在深渊中使用过"的角色。
3.3 维度2 字段(探索)
ExploreProgressAvg:所有区域探索度的平均值(0~1000,API 返回的exploration_percentage字段,值为百分比×10)OculusRate:八类神瞳收集率的均值(0~1),每类为min(1, 已收集数 / 上限)
神瞳分类:风/岩/雷/草/水/火/月/冰 共八类。其中至冬·冰神瞳上限暂填 0(7.0 版本开放后填入实际上限即生效),上限为 0 的类别自动跳过不参与均值计算。
3.4 维度3 字段(剧情)
AchievementNumber:成就总数AvgFetter:所有角色的平均好感度(复用维度1 字段,用于衡量"对角色投入的感情")
活跃天数(
ActiveDayNumber)已移除:不反映剧情参与度,每天打深渊的跳过党也可能活跃天数很高。
3.5 维度4 字段(抽卡 + 原石,由 Features 层填充)
TotalPulls:所有卡池的总抽数FiveStars:所有卡池的五星总数CurrentPity:角色池当前保底距离(取 301 池优先,回退 400 池)Dim4HasGacha:是否存在抽卡数据(无数据时维度4 退化为中性 50)CurrentMonthPrimogems:当月原石收入(旅行札记)RecentTwoMonthsPrimogems:最近两个月原石总收入Dim4HasPrimogems:是否成功获取原石数据(失败时维度4 不使用原石信号)
3.6 维度5 字段(壶经营)
HomeComfort:洞天仙力(取所有洞天中最高值)HomeLevel:信任等阶(取洞天仙力最高处的等阶)HomeItems:摆设数量(取洞天仙力最高处)
四、五维评分算法
每个维度产出 0~100 的整数分数,其中 0 代表一端,100 代表另一端。
4.0 工具函数
三个核心工具函数贯穿所有维度:
Clamp01(x) = Math.Clamp(x, 0, 1) 将值限制在 [0, 1]
NormalizeHigh(v) = Clamp01(v / reference) 将值除以参考上限后截断
RatioScore(a, b) = Round(100 × a / (a + b + ε)) 两端比值打分,ε=1e-6 防除零
RatioScore 的直觉:这是一个"天平"函数。a 端和 b 端各自有一个 0~1 的得分,谁的得分更高,分数就偏向谁。两端相等时返回 50(中性)。完全偏向 a 端时返回接近 100,完全偏向 b 端时返回接近 0。
4.1 维度1:强度党(0) vs 真爱党(100)
设计思路:对比"角色练度的强度投入"与"角色练度的情感投入"。
满命率已移除:满命率是中性指标——强度党为追求极致伤害抽满命(如满命夜兰),真爱党为心爱角色抽满命(如满命安柏),无法区分倾向,不参与两端计算。
强度端得分(3 项加权求和,权重之和 = 1.0):
- 深渊出场练度
AbyssInvestment× 权重 0.40 - 满级率
MaxLevelCount / AvatarCount× 权重 0.35 - 平均命座归一化
Clamp01(AvgConstellation / 6)× 权重 0.25
其中 AbyssInvestment(深渊出场角色练度):
AbyssInvestment = (Clamp01(AbyssAvgLevel / 90) + Clamp01(AbyssAvgConstellation / 6)) / 2
取出场角色平均等级和平均命座各归一化后的均值。无深渊出场数据时为 0。
真爱端得分(2 项加权求和,权重之和 = 1.0):
- 好感满率
Fetter10Count / AvatarCount× 权重 0.55 - 平均好感归一化
Clamp01(AvgFetter / 10)× 权重 0.45
最终分数:
ScoreDim1 = RatioScore(love, strength)
love 越高越偏真爱(100),strength 越高越偏强度(0)。
4.2 维度2:摆烂党(0) vs 探索者(100)
设计思路:直接衡量地图探索投入度。探索度拉满 + 神瞳全收集 = 探索者;啥都不探索 = 摆烂党。
维度2 采用直接评分法(非 RatioScore),因为"探索程度"是一个单一维度的递增指标,不存在两端对立。壶经营已独立到维度5。
探索度得分(2 项加权):
explore = 0.6 × Clamp01(ExploreProgressAvg / 1000) + 0.4 × OculusRate
- 世界探索度均值归一化(权重 0.60,API 返回值为 0~1000,即百分比×10)
- 八类神瞳收集率均值(权重 0.40,已经是 0~1)
最终分数:
ScoreDim2 = Round(explore × 100)
explore 越高越偏探索者(100),越低越偏摆烂党(0)。
4.3 维度3:剧情党(0) vs 跳过党(100)
设计思路:"看剧情" = "做了任务" + "对角色投入了感情",两者缺一不可。
核心问题与解决:
- 成就完成率只能反映"做了多少任务"——原神过任务就给成就,跳过剧情也能拿满成就,所以成就高 ≠ 看了剧情
- 好感度间接反映"对角色投入的感情/时间"——认真看剧情的玩家会对角色产生感情,更愿意提升好感;跳过党对角色无感情,只练深渊角色,好感低
- 活跃天数已移除:不反映剧情参与度,每天打深渊的跳过党也可能活跃天数很高
- 角色拥有率已移除:可通过抽卡获得,不反映剧情参与度
沉浸度得分(几何平均):
ach = Clamp01(AchievementNumber / 600) // 做了多少任务
fetter = Clamp01(AvgFetter / 10) // 投入了多少时间/感情
immersion = √(ach × fetter) // 几何平均,两者缺一不可
为什么用几何平均(乘法)而不是加法?
- 加法的问题:成就 0.9 + 好感 0.2 = 0.55,仍偏剧情——跳过党做满任务但没感情,被误判为剧情党
- 几何平均的优势:好感低会"拖低"整体,成就再高也救不回来——
√(0.9 × 0.2) = 0.42→ 跳过党
| 玩家类型 | 成就 | 好感 | 几何平均 | 判定 |
|---|---|---|---|---|
| 认真看剧情 | 0.9 | 0.8 | 0.85 | 剧情党 |
| 跳过党做满任务 | 0.9 | 0.2 | 0.42 | 跳过党 |
| 只看主线不肝支线 | 0.4 | 0.8 | 0.57 | 偏剧情 |
| 萌新 | 0.2 | 0.3 | 0.24 | 跳过党 |
最终分数(反向映射):
ScoreDim3 = Round(100 - immersion × 100)
沉浸度越高,分数越低(偏剧情党,0);沉浸度越低,分数越高(偏跳过党,100)。
好感度在维度1 和维度3 中均被使用,但角度不同:维度1 用好感 vs 练度(RatioScore 对比,衡量"爱 vs 强");维度3 用成就 × 好感(几何平均,衡量"有感情的参与度")。
4.4 维度4:赌狗(0) vs 规划党(100)
设计思路:对比"抽卡行为的冲动程度"与"原石规划的理性程度"。
核心改进:用"五星密度"(五星数/总抽数)代替"绝对五星数量"。绝对数量与游玩时长正相关——玩了3年的规划党可能抽了5000次但每次精打细算,不能因为抽得多就判为赌狗。五星密度消除了游玩时长的影响:密度高 → 只抽特定角色池、出五星就停手 → 规划党;密度低 → 什么池子都下 → 赌狗。
维度4 支持"原石收入信号"双模式:当
UsePrimogemsForDim4 = true且成功获取原石数据时使用四因子算法;否则回退到三因子算法。
前置归一化:
currentPityRate = Clamp01(CurrentPity / 90) // 保底距离,90 抽为角色池上限
pullsRate = NormalizeHigh(TotalPulls, 5000) // 总抽数,参考上限 5000
fiveStarDensity = Clamp01((FiveStars/TotalPulls - 0.005) // 五星密度,期望值约 1.6%
/ (0.04 - 0.005)) // 0.5%以下=纯赌狗,4%以上=纯规划
无抽数时
fiveStarDensity取中性值 0.5。
模式 A:启用原石信号(四因子)
当 UsePrimogemsForDim4 = true 且 Dim4HasPrimogems = true 时启用。原石收入高 = 在囤原石 → 规划党;原石收入低 = 有石就抽 → 赌狗。
monthRate = Clamp01(CurrentMonthPrimogems / 6000) // 当月原石收入
twoMonthRate = Clamp01(RecentTwoMonthsPrimogems / 12000) // 近两月原石总收入
primogemsRate = 0.5 × monthRate + 0.5 × twoMonthRate // 原石信号综合得分
赌狗端得分(4 项加权,权重之和 = 1.0):
gamble = (1 - fiveStarDensity) × 0.30 // 五星密度低=什么池都抽
+ (1 - currentPityRate) × 0.25 // 保底距离远=刚抽完
+ (1 - primogemsRate) × 0.25 // 原石收入低=有石就花
+ pullsRate × 0.20 // 总抽数多=抽得频繁
规划端得分(4 项加权,权重之和 = 1.0):
planner = fiveStarDensity × 0.30 // 五星密度高=出五星就停
+ currentPityRate × 0.25 // 保底距离近=在囤抽数
+ primogemsRate × 0.25 // 原石收入高=在囤原石
+ (1 - pullsRate) × 0.20 // 总抽数少=克制
模式 B:不使用原石信号(三因子,降级回退)
当原石信号关闭或获取失败时使用三因子算法:
gamble = (1 - fiveStarDensity) × 0.40
+ (1 - currentPityRate) × 0.35
+ pullsRate × 0.25
planner = fiveStarDensity × 0.40
+ currentPityRate × 0.35
+ (1 - pullsRate) × 0.25
最终分数:
ScoreDim4 = RatioScore(planner, gamble)
planner 越高越偏规划党(100),gamble 越高越偏赌狗(0)。
无抽卡数据时:
Dim4HasGacha = false,直接返回 50(中性),不参与代号倾向判定。
4.5 维度5:闲云野鹤(0) vs 壶中仙(100)
设计思路:直接衡量尘歌壶经营投入度。洞天仙力拉满 + 信任等阶满 + 摆设多 = 壶中仙;不经营壶 = 闲云野鹤。
维度5 采用直接评分法(非 RatioScore),因为"壶经营程度"是一个单一维度的递增指标。原维度5 的"休闲 vs 硬核"(活跃天数+成就+角色数)与维度3 数据重叠率高,已替换为壶经营评分,使五个维度各自独立。
壶经营得分(3 项加权求和,权重之和 = 1.0):
home = Clamp01(HomeComfort / 30000) × 0.50
+ Clamp01(HomeLevel / 10) × 0.30
+ Clamp01(HomeItems / 2000) × 0.20
- 洞天仙力归一化(上限 30000,权重 0.50)
- 信任等阶归一化(上限 10,权重 0.30)
- 摆设数量归一化(上限 2000,权重 0.20)
最终分数:
ScoreDim5 = Round(home × 100)
home 越高越偏壶中仙(100),越低越偏闲云野鹤(0)。
五、神级代号匹配
5.1 布尔倾向与索引计算
五个维度各自产出一个 0~100 的分数,以 50 分为阈值 转换为布尔倾向:
b1 = (d1 >= 50)→ 真爱党(True)/ 强度党(False)b2 = (d2 >= 50)→ 探索者(True)/ 摆烂党(False)b3 = (d3 >= 50)→ 跳过党(True)/ 剧情党(False)b4 = (d4 >= 50)→ 规划党(True)/ 赌狗(False)b5 = (d5 >= 50)→ 壶中仙(True)/ 闲云野鹤(False)
将 5 个布尔值组合为一个 5 位二进制索引(0~31):
idx = b1 | (b2 << 1) | (b3 << 2) | (b4 << 3) | (b5 << 4)
位权分配:
- bit0(值 1):真爱
- bit1(值 2):探索者
- bit2(值 4):跳过
- bit3(值 8):规划
- bit4(值 16):壶中仙
5.2 32 种代号
代号库存储在 Assets/Config/GenshinMbtiCodex.json,共 32 条代号(version: 3),每条代号包含:代号名、对应形象、主色/副色(用于 UI 渐变)、暖心评语、毒舌评语。
索引按 (b1, b2, b3, b4, b5) 五位布尔组合,从 0(全 False)到 31(全 True)排列。例如:
- index 0(强度+摆烂+剧情+赌狗+闲云)
- index 16(强度+摆烂+剧情+赌狗+壶中仙)— 仅 b5 翻转
- index 31(真爱+探索+跳过+规划+壶中仙)— 全 True
完整 32 条代号详见
GenshinMbtiCodex.json文件。
5.3 匹配逻辑
GenshinMbtiCodex.Get(index) 从内部字典中按索引查找代号:
- 若索引命中 → 返回对应代号
- 若索引未命中 → 尝试返回 index=0 的兜底代号
- 若代号库为空 → 返回
MbtiPersona.Fallback("提瓦特的旅人")
六、重测微调机制
用户点击"重新测试"后,页面展开 5 个滑块(0~100),分别对应五个维度的分数。用户手动微调后,点击确认:
- 将滑块值写入
_manualScores数组,覆盖算法原始分数 - 重新计算每个维度的
PositiveSide(分数 ≥ 50 为正端) - 重新计算 5 位二进制索引
idx - 从代号库重新匹配神级代号
- 重绘雷达图、分数条、代号、评语
重测不是真随机,而是让用户"承认自己的倾向"。例如玩家手动将维度4 拉到 100(规划党),系统会重新匹配到对应的代号。这确保测出来的结果让玩家觉得"太准了,简直在照镜子"。
七、优雅降级策略
MBTI 功能对数据缺失有完善的降级处理,不会因单一数据源失败而崩溃:
- index 获取失败:抛出异常交由 UI 处理(显示错误提示 + 回到开始页)
- 深渊获取失败:维度1 的
AbyssInvestment退化为 0,仅用 index 角色数据评分(满级率、命座率、好感率),不影响其他维度 - 抽卡数据缺失(用户未同步抽卡记录):
Dim4HasGacha = false,维度4 直接返回 50(中性),不参与代号倾向判定 - 旅行札记获取失败:
Dim4HasPrimogems = false,维度4 自动回退到三因子算法(不使用原石信号),不影响其他维度 - 代号库加载失败:返回
MbtiPersona.Fallback("提瓦特的旅人"),不阻塞功能 - 头像加载失败:忽略错误,不显示头像
八、配置常量参考
所有可调参数集中在 GenshinMbtiConfig 中,便于调参和二期功能复用:
维度1 权重
W1_Abyss = 0.40(深渊出场练度)W1_Lvl90 = 0.35(满级率)W1_Const = 0.25(平均命座)W1_C6已移除(满命率是中性指标,不参与两端)W1_Fetter10 = 0.55(好感满率)W1_AvgFetter = 0.45(平均好感)
维度2/5 共用上限(探索/壶经营)
ComfortCap = 30000(洞天仙力上限)HomeLevelCap = 10(信任等阶上限)HomeItemCap = 1000(摆设数量参考上限)- 神瞳收集上限(
OculusCap字典,随版本变化):
- 风 65 / 岩 130 / 雷 180 / 草 270 / 水 270 / 火 270 / 月 270 - 冰 0(至冬·冰神瞳,7.0 版本开放后填入实际上限即生效,上限为 0 时自动跳过)
维度3
AchievementCap = 600(成就总数归一上限)- 活跃天数已移除(不反映剧情参与度)
- 角色拥有率已移除(可通过抽卡获得)
- 算法:成就完成率 × 好感度,几何平均
维度4 参考量
TotalPullsRef = 5000(总抽数参考上限)PityCap = 90(保底距离上限,角色池 90 抽)FiveStarDensityMin = 0.005(五星密度归一化下限,0.5%)FiveStarDensityMax = 0.04(五星密度归一化上限,4%)UsePrimogemsForDim4 = true(是否启用原石余额信号,当前已启用)PrimogemsMonthRef = 6000(当月原石收入参考上限)PrimogemsTwoMonthRef = 12000(最近两个月原石总收入参考上限)
维度5 权重(壶经营综合得分)
W5_Comfort = 0.50(洞天仙力权重)W5_HomeLevel = 0.30(信任等阶权重)W5_HomeItems = 0.20(摆设数量权重)