11 KiB
Build 系统重构 PRD:标签-属性相似度模型
更新时间:2026-04-02
1. 背景
当前 Build 系统的核心实现位于:
src/data/buildDamage.tssrc/data/buildTags.tssrc/data/buildTagSimilarity.generated.ts
现状不是“标签各自独立生效”,而是:
- 先收集角色标签、装备标签、套装标签、Buff 标签。
- 再计算“每个标签与其他所有标签”的相似度。
- 用标签之间的整体相互作用,得到最终
buildDamageMultiplier。
这套机制已经能跑,但存在 4 个明显问题:
- 解释成本高。玩家很难理解“为什么我多带一个标签,所有旧标签的贡献都变了”。
- 平衡难度高。任意新增一个标签,都会对整个标签集合产生连锁影响。
- 角色感不够强。当前倍率更像“标签团簇强度”,而不是“这个标签是否适合当前角色属性”。
- 扩展不稳定。策划继续扩标签、套装、Buff 时,组合爆炸会越来越明显。
因此,本次重构目标是把 Build 系统从“标签互相影响”改为“标签分别匹配玩家扮演角色的属性画像”,让每个标签的收益来源更直观、更可控。
2. 目标
2.1 产品目标
建立一套新的 Build 计算模型:
- 不再计算标签与标签之间的互相影响。
- 改为计算“每个标签”和“角色每个属性”的相似度。
- 再根据角色属性分布,决定该标签的修正加成倍数。
- 所有标签的总收益由“单标签贡献求和”得到,而不是由“标签网络效应”得到。
2.2 设计目标
新系统需要满足:
- 可解释:每个标签为什么强、强在哪个属性上,都能拆出来看。
- 可控:新增一个标签,只影响它自己的贡献,不扰动全局。
- 贴角色:敏捷型角色更容易吃满“突进/快剑/追击”类标签,智力/精神型角色更容易吃满“法修/法力/符阵”类标签。
- 可扩展:装备、Buff、套装仍然可以继续产出标签,但标签结算方式统一且稳定。
2.3 非目标
本期不做:
- 不重做掉落、锻造、拆解循环。
- 不引入防御端 Build 抗性系统。
- 不重新设计角色基础四维属性。
- 不依赖运行时在线 embedding 服务。
3. 核心方案
3.1 基本思想
每个 Build 标签不再和其他标签比较,而是改为和以下 4 个角色属性做比较:
strengthagilityintelligencespirit
每个标签都会拥有一个“属性亲和度向量”,表示它分别贴近哪类属性。
示例:
快剑:更偏agility,次偏strength重击:更偏strength法修:更偏intelligence护体:偏spirit + strength符阵:偏intelligence + spirit
角色自身也有属性分布。系统将角色属性归一化后,与标签属性亲和度做匹配,得到该标签在当前角色身上的“适配度”。
最终伤害加成不再来自“标签互相增幅”,而来自“每个标签在当前角色上的适配度贡献”。
3.2 新公式
角色属性权重
roleAttributeWeight[attr] = character.attributes[attr] / totalAttributes
其中:
totalAttributes =
strength + agility + intelligence + spirit
标签属性亲和度
每个标签维护一个四维向量:
tagAttributeAffinity = {
strength: 0~1,
agility: 0~1,
intelligence: 0~1,
spirit: 0~1,
}
单标签适配度
tagFitScore(tag, character) =
sum(attr in [str, agi, int, spr])(
roleAttributeWeight[attr] * tagAttributeAffinity[attr]
)
tagFitScore 结果区间固定在 0 ~ 1。
单标签加成倍数
tagBonusMultiplier =
1 + baseTagBonus * tagFitScore * sourceCoefficient
建议首版参数:
baseTagBonus = 0.12sourceCoefficient- Buff 标签:
1.0 - 角色固有标签:
0.9 - 武器标签:
0.85 - 防具标签:
0.75 - 饰品标签:
0.8 - 套装合成标签:
0.9
- Buff 标签:
最终 Build 总倍率
为了避免标签过多时指数膨胀,首版采用“加法累计,再转倍率”的方式:
buildBonus =
clamp(sum(eachTagBonusDelta), 0, 0.6)
buildDamageMultiplier = 1 + buildBonus
其中:
eachTagBonusDelta = baseTagBonus * tagFitScore * sourceCoefficient
这意味着:
- 标签越多,总收益越高。
- 但每个标签只看自己和角色属性是否匹配。
- 新增一个标签,不会反向修改旧标签贡献。
3.3 示例
角色属性:
strength = 8agility = 10intelligence = 4spirit = 3
归一化后:
strength = 0.32agility = 0.40intelligence = 0.16spirit = 0.12
标签亲和度假设:
快剑: { strength: 0.35, agility: 1.0, intelligence: 0.1, spirit: 0.05 }
突进: { strength: 0.45, agility: 0.95, intelligence: 0.0, spirit: 0.0 }
法修: { strength: 0.0, agility: 0.1, intelligence: 1.0, spirit: 0.6 }
则:
快剑 fit = 0.32*0.35 + 0.40*1.0 + 0.16*0.1 + 0.12*0.05 = 0.534
突进 fit = 0.32*0.45 + 0.40*0.95 = 0.524
法修 fit = 0.40*0.1 + 0.16*1.0 + 0.12*0.6 = 0.272
可以直观看到:
- 同样是标签,
快剑/突进对敏捷角色收益高。 法修在这名角色身上的收益明显偏低。- 原因不再是“它和其他标签不合群”,而是“它和当前角色属性画像不匹配”。
4. 数据结构改造
4.1 BuildTagDefinition 扩展
当前 src/types/build.ts 中的 BuildTagDefinition 需要新增:
attributeAffinity: {
strength: number;
agility: number;
intelligence: number;
spirit: number;
};
完整建议:
interface BuildTagDefinition {
id: string;
label: string;
category: BuildTagCategory;
aliases: string[];
description: string;
attributeAffinity: {
strength: number;
agility: number;
intelligence: number;
spirit: number;
};
}
4.2 运行时明细结构
src/data/buildDamage.ts 需要将当前的 BuildDamageBreakdown 从“标签两两贡献表”改成“标签-属性贡献表”:
type BuildDamageBreakdown = {
tags: string[];
buildDamageBonus: number;
buildDamageMultiplier: number;
rows: Array<{
label: string;
source: 'buff' | 'character' | 'equipment' | 'set' | 'monster';
fitScore: number;
sourceCoefficient: number;
bonusDelta: number;
attributeContributions: {
strength: number;
agility: number;
intelligence: number;
spirit: number;
};
}>;
};
这样 UI 或调试日志能直接回答:
- 这个标签吃的是哪条属性
- 吃了多少
- 为什么它比另一个标签强
4.3 相似度来源
当前仓库已有 src/data/buildTagSimilarity.generated.ts,但新方案不再以“标签-标签相似度矩阵”为主数据源。
建议改为新增:
src/data/buildTagAttributeAffinity.ts
用于存放标签到四维属性的静态向量。
首版推荐手工维护,原因:
- 标签总量不大,人工校准更稳定。
- 当前目标是产品可控性,不是自动发现语义簇。
- 四维属性向量远比标签两两矩阵更容易审表和平衡。
后续如果要半自动化,可再增加脚本从标签描述中生成建议值,但运行时仍只读取本地静态表。
5. 标签来源规则
标签来源不变,计算方式变化。
保留来源
- 角色固有
combatTags - 装备
buildProfile.tags - 套装标签
- Buff 标签
新规则
- 所有标签统一做规范化和去重。
- 每个标签独立计算与角色属性的适配度。
- 不再计算标签与标签之间的 pair / product / cluster。
- 套装标签本质上仍是标签,只是
sourceCoefficient更高。
6. 伤害接入方式
当前 calculateOutgoingDamage() 的接法可以保留:
finalDamage =
round(
baseDamage
* functionMultiplier
* equipmentMultiplier
* buildDamageMultiplier
)
本次只替换 buildDamageMultiplier 的来源,不改整体伤害主链路。
7. 与旧系统的关键差异
| 维度 | 旧系统 | 新系统 |
|---|---|---|
| 核心逻辑 | 标签之间互相影响 | 标签分别匹配角色属性 |
| 新增标签的影响范围 | 会扰动整个标签集合 | 只影响自身贡献 |
| 可解释性 | 低 | 高 |
| 平衡成本 | 高 | 低 |
| 角色属性参与感 | 弱 | 强 |
| 套装/装备/Buff 接入 | 已支持 | 继续支持 |
8. 实施方案
阶段 A:数据层
- 在
src/types/build.ts扩展BuildTagDefinition.attributeAffinity - 在
src/data/buildTags.ts为所有规范标签补齐四维亲和度 - 新增
src/data/buildTagAttributeAffinity.ts或直接内联到标签注册表
阶段 B:规则层
- 重写
src/data/buildDamage.ts - 删除或下线标签两两
contributionRows计算 - 新增
tagFitScore、bonusDelta、attributeContributions计算
阶段 C:展示层
- 调整 Build 面板展示文案
- 从“标签协同”改成“标签适配度”
- 为每个标签展示主属性来源,例如:
快剑:敏捷主导,少量力量修正法修:智力主导,精神辅助
阶段 D:平衡层
- 补一份全标签四维向量审表
- 选 5 个预设角色跑样例验证
- 校准
baseTagBonus与sourceCoefficient
9. 验收标准
功能验收
- 任意标签的贡献都可以拆解到四个属性。
- 删除一个标签时,只减少它自己的收益,不应重算其他标签的贡献值。
- 同一套装备给不同属性角色使用时,Build 倍率应体现明显差异。
- 套装标签、Buff 标签仍能正常进入最终 Build 倍率。
数值验收
- 单标签弱匹配时收益接近 0。
- 单标签强匹配时收益稳定且可预期。
- 3 到 6 个高匹配标签可形成清晰 build 成型感。
- 8 标签上限下,总 Build 加成不超过设计封顶值。
体验验收
- 玩家能理解“为什么这个标签适合我当前角色”。
- 策划能直接通过改四维向量调数,不需要反复查标签图谱。
- 调试日志能一眼看出收益来源,而不是只能看到复杂的 pair 乘积。
10. 风险与对策
风险 1:标签语义被压平
问题: 去掉标签-标签协同后,Build 可能变得过于线性。
对策:
- 保留套装标签和 Buff 标签作为高价值来源。
- 用
sourceCoefficient区分来源权重。 - 后续如需要,可增加“少量同流派奖励”,但必须是弱规则,不能回到全图互相影响。
风险 2:四维向量定义主观
问题: 不同策划对“快剑更像敏捷还是力量”可能判断不同。
对策:
- 首版先建立审表规范。
- 每个标签必须附一句属性说明。
- 先让预设角色覆盖主要 archetype,再扩充长尾标签。
风险 3:旧数据迁移成本
问题:
现有 buildTagSimilarity.generated.ts 将弱化甚至失去主要用途。
对策:
- 本期不强制删除旧文件。
- 新逻辑只依赖新 affinity 表。
- 等新系统稳定后,再清理旧相似度矩阵和旧展示逻辑。
11. 一句话结论
本次 Build 系统重构的核心,不是再优化“标签之间怎么互相放大”,而是把判断标准改成“这个标签和当前玩家角色的属性画像有多匹配”,从而让 Build 倍率从复杂的标签网络效应,变成可解释、可调优、可控的单标签属性适配模型。