fix(aihr): align fallback scoring with BRD dimensions

This commit is contained in:
2026-07-14 15:19:07 +08:00
parent 56c146ea0a
commit c76c500dc7
5 changed files with 52 additions and 28 deletions
@@ -717,18 +717,19 @@ public class AihrPracticeSeedService {
} }
private PracticeResult seedPracticeResult(ActiveSession activeSession, ScenarioSeed scenario) { private PracticeResult seedPracticeResult(ActiveSession activeSession, ScenarioSeed scenario) {
int compliance = scoreValue(scenario.scores(), "合规", scenario.total()); int taskCompletion = scoreValue(scenario.scores(), "任务完成度", scenario.total());
int communication = scoreValue(scenario.scores(), "沟通", scenario.total()); int standardization = scoreValue(scenario.scores(), "话术规范性", taskCompletion);
int emotion = scoreValue(scenario.scores(), "情绪", scenario.total()); int emotion = scoreValue(scenario.scores(), "情绪管理能力", scenario.total());
int marketing = scoreValue(scenario.scores(), "营销", scenario.total()); int marketing = scoreValue(scenario.scores(), "增值转化潜力", scenario.total());
Integer response = responseTimelinessScore(activeSession); Integer response = scoreValue(scenario.scores(), "响应时效");
response = response == null ? responseTimelinessScore(activeSession) : response;
int total = response == null int total = response == null
? scenario.total() ? scenario.total()
: weightedPracticeScore(compliance, average(compliance, communication), emotion, response, marketing); : weightedPracticeScore(taskCompletion, standardization, emotion, response, marketing);
return new PracticeResult( return new PracticeResult(
total, total,
brdDimensions(compliance, average(compliance, communication), emotion, response, marketing), brdDimensions(taskCompletion, standardization, emotion, response, marketing),
scenario.rewrite(), scenario.summary(), compliance, communication, compliance, response, scenario.rewrite(), scenario.summary(), standardization, standardization, taskCompletion, response,
averageResponseLatencyMs(activeSession) averageResponseLatencyMs(activeSession)
); );
} }
@@ -3957,10 +3958,11 @@ public class AihrPracticeSeedService {
private List<DimensionResponse> defaultScores(String scenarioCode) { private List<DimensionResponse> defaultScores(String scenarioCode) {
boolean feeScenario = !isBlank(scenarioCode) && scenarioCode.contains("fee"); boolean feeScenario = !isBlank(scenarioCode) && scenarioCode.contains("fee");
return List.of( return List.of(
new DimensionResponse("合规", feeScenario ? 82 : 84, "SOP关键点覆盖"), new DimensionResponse("任务完成度", feeScenario ? 82 : 84, "SOP关键点覆盖;训练回退代理"),
new DimensionResponse("沟通", 84, "承诺与表达清晰度"), new DimensionResponse("话术规范性", 84, "承诺与表达清晰度;训练回退代理"),
new DimensionResponse("情绪", 82, "安抚与承接能力"), new DimensionResponse("情绪管理能力", 82, "安抚与承接能力;训练回退代理"),
new DimensionResponse("营销", feeScenario ? 80 : 76, "政策解释与办理引导") new DimensionResponse("响应时效", "待采集", "无真实回合耗时证据时不回填"),
new DimensionResponse("增值转化潜力", feeScenario ? 80 : 76, "政策解释与办理引导;训练回退代理")
); );
} }
@@ -3998,10 +4000,11 @@ public class AihrPracticeSeedService {
) )
), ),
List.of( List.of(
new DimensionResponse("合规", 84, "有升级路径"), new DimensionResponse("任务完成度", 84, "有升级路径;训练回退代理"),
new DimensionResponse("沟通", 88, "承诺清楚"), new DimensionResponse("话术规范性", 86, "承诺清楚;训练回退代理"),
new DimensionResponse("情绪", 82, "先承接诉求"), new DimensionResponse("情绪管理能力", 82, "先承接诉求"),
new DimensionResponse("错题", "1条", "补费用争议") new DimensionResponse("响应时效", "待采集", "无真实回合耗时证据时不回填"),
new DimensionResponse("增值转化潜力", 76, "训练回退代理")
), ),
86, 86,
"建议表达为:“我先确认责任人和到场时间,10 分钟内回复您;如果今天无法完成,我同步主管给您替代方案和下一次反馈时间。”", "建议表达为:“我先确认责任人和到场时间,10 分钟内回复您;如果今天无法完成,我同步主管给您替代方案和下一次反馈时间。”",
@@ -4032,10 +4035,11 @@ public class AihrPracticeSeedService {
) )
), ),
List.of( List.of(
new DimensionResponse("合规", 80, "复核明确"), new DimensionResponse("任务完成度", 80, "复核明确;训练回退代理"),
new DimensionResponse("沟通", 83, "拆分得当"), new DimensionResponse("话术规范性", 82, "拆分得当;训练回退代理"),
new DimensionResponse("情绪", 78, "安抚一般"), new DimensionResponse("情绪管理能力", 78, "安抚一般"),
new DimensionResponse("错题", "2条", "补开场安抚") new DimensionResponse("响应时效", "待采集", "无真实回合耗时证据时不回填"),
new DimensionResponse("增值转化潜力", 80, "训练回退代理")
), ),
81, 81,
"建议先承接情绪:“您觉得服务不到位,我先把问题负责跟到底。”再说明缴费和整改并行,最后给出主管复核与反馈时间。", "建议先承接情绪:“您觉得服务不到位,我先把问题负责跟到底。”再说明缴费和整改并行,最后给出主管复核与反馈时间。",
@@ -2,6 +2,7 @@ package org.dromara.aihr.service;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.dromara.aihr.domain.AihrPracticeDto.CompetencyResponse; import org.dromara.aihr.domain.AihrPracticeDto.CompetencyResponse;
import org.dromara.aihr.domain.AihrPracticeDto.DimensionResponse;
import org.dromara.aihr.domain.AihrPracticeDto.FinishRequest; import org.dromara.aihr.domain.AihrPracticeDto.FinishRequest;
import org.dromara.aihr.domain.AihrPracticeDto.PracticeAssignmentRequest; import org.dromara.aihr.domain.AihrPracticeDto.PracticeAssignmentRequest;
import org.dromara.aihr.domain.AihrPracticeDto.ReviewAdviceRequest; import org.dromara.aihr.domain.AihrPracticeDto.ReviewAdviceRequest;
@@ -131,6 +132,20 @@ public class AihrPracticeSeedServiceTest {
assertTrue(result.isEmpty()); assertTrue(result.isEmpty());
} }
@Test
@SuppressWarnings("unchecked")
public void seedFallbackScoresUseBrdFiveDimensions() throws Exception {
AihrPracticeSeedService service = new AihrPracticeSeedService(new ObjectMapper(), null, null, null);
Method method = AihrPracticeSeedService.class.getDeclaredMethod("defaultScores", String.class);
method.setAccessible(true);
List<DimensionResponse> scores = (List<DimensionResponse>) method.invoke(service, "fee-collection");
assertEquals(List.of("任务完成度", "话术规范性", "情绪管理能力", "响应时效", "增值转化潜力"),
scores.stream().map(DimensionResponse::label).toList());
assertEquals("待采集", scores.get(3).value());
}
@Test @Test
public void supervisorAssignmentSourceIsServerOwned() throws Exception { public void supervisorAssignmentSourceIsServerOwned() throws Exception {
String source = Files.readString(Path.of("src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java")); String source = Files.readString(Path.of("src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java"));
+1
View File
@@ -293,4 +293,5 @@
- 2026-07-14 最新线上只读复核:生产根站、`/h5/` 和 `/prod-api/auth/tenant/list` 均返回 `200`;线上仍加载管理端 `assets/index-CJZ3Ax3Z.js`(SHA-256 `8b9278a26ccb760abce489b12a20b221748c64d4c4153613d2511777bb9677bc`)与 H5 `assets/index-D4-NrEpb.js`(SHA-256 `ab15bfd17cabe58e2f34b0ac61ee198a837128ed85dc6bb0ddf77bc3e22dcd9c`),本地最新提交 `e0da5f0a` 尚未发布;本轮未执行生产同步、后端重启或业务数据写入。 - 2026-07-14 最新线上只读复核:生产根站、`/h5/` 和 `/prod-api/auth/tenant/list` 均返回 `200`;线上仍加载管理端 `assets/index-CJZ3Ax3Z.js`(SHA-256 `8b9278a26ccb760abce489b12a20b221748c64d4c4153613d2511777bb9677bc`)与 H5 `assets/index-D4-NrEpb.js`(SHA-256 `ab15bfd17cabe58e2f34b0ac61ee198a837128ed85dc6bb0ddf77bc3e22dcd9c`),本地最新提交 `e0da5f0a` 尚未发布;本轮未执行生产同步、后端重启或业务数据写入。
- 2026-07-14 BRD 4.4 入职日期数据链路补齐:组织快照初始化 DDL、外部组织同步和旧库懒迁移现在统一保存 `hire_date`,每日三题在存在该字段但记录缺日期时仍只允许本地 `dev/local` 的显式训练次数兼容回退,生产不会用训练次数推断新员工;新增 MySQL 8 版本迁移与严格预检字段/身份门禁。未写入试点业务数据,正式环境仍需外部组织同步实际提供入职日期并执行迁移。 - 2026-07-14 BRD 4.4 入职日期数据链路补齐:组织快照初始化 DDL、外部组织同步和旧库懒迁移现在统一保存 `hire_date`,每日三题在存在该字段但记录缺日期时仍只允许本地 `dev/local` 的显式训练次数兼容回退,生产不会用训练次数推断新员工;新增 MySQL 8 版本迁移与严格预检字段/身份门禁。未写入试点业务数据,正式环境仍需外部组织同步实际提供入职日期并执行迁移。
- 2026-07-14 BRD 4.5.1 五维评分规则数据对齐:对练 `/finish`、复盘、校准和画像代码已补齐任务完成度、话术规范性、情绪管理能力、响应时效、增值转化潜力五项;本轮同步 reset SQL、运行时 seed fallback 和现有生活顾问 Rubric 迁移为 40%/25%/20%/10%/5%,严格预检新增五维 Rubric 数量与权重和检查。任务完成度当前以 SOP 执行/问题推进代理,响应时效当前以陪练回合响应耗时代理;工单闭环率、首解率、正式首响/处理周期仍待业务系统与 HR 确认,未把代理指标宣称为正式绩效口径。迁移只改评分规则结构,不写训练、校准或 SOP 业务样本。 - 2026-07-14 BRD 4.5.1 五维评分规则数据对齐:对练 `/finish`、复盘、校准和画像代码已补齐任务完成度、话术规范性、情绪管理能力、响应时效、增值转化潜力五项;本轮同步 reset SQL、运行时 seed fallback 和现有生活顾问 Rubric 迁移为 40%/25%/20%/10%/5%,严格预检新增五维 Rubric 数量与权重和检查。任务完成度当前以 SOP 执行/问题推进代理,响应时效当前以陪练回合响应耗时代理;工单闭环率、首解率、正式首响/处理周期仍待业务系统与 HR 确认,未把代理指标宣称为正式绩效口径。迁移只改评分规则结构,不写训练、校准或 SOP 业务样本。
- 2026-07-14 BRD 4.5.1 回退路径一致性修复:数据库异常或演示回退时,后端 seed 和管理端本地场景此前仍可能返回旧四维/错题卡;现统一返回 BRD 五维,缺少真实回合耗时的响应时效明确为“待采集”,不使用旧错题字段冒充评估维度。新增运行时回归测试与 `demo-check` marker,未修改业务数据。
- 2026-07-14 BRD 最新线上只读复核:生产根站与 `/h5/` 返回 `200`,线上仍加载管理端 `assets/index-CJZ3Ax3Z.js` 与 H5 `assets/index-D4-NrEpb.js`;当前本地提交 `94d483d3` 构建资源分别为 `assets/index-Cv2wI9UI.js`(SHA-256 `cd6e3eab4a684141ccd64617dcde4d99030c9c13f7da618c11e1709c04f244a0`)和 `assets/index-Dq7sfWZP.js`(SHA-256 `f8499e5f261cc06d02de275e285e4a7c946dd6ef54fd29b3a1c0bc7a9a689c3d`)。本轮只读核验,未执行生产静态资源同步、后端重启或业务数据写入;五维修复仍未被证明在线上生效。 - 2026-07-14 BRD 最新线上只读复核:生产根站与 `/h5/` 返回 `200`,线上仍加载管理端 `assets/index-CJZ3Ax3Z.js` 与 H5 `assets/index-D4-NrEpb.js`;当前本地提交 `94d483d3` 构建资源分别为 `assets/index-Cv2wI9UI.js`(SHA-256 `cd6e3eab4a684141ccd64617dcde4d99030c9c13f7da618c11e1709c04f244a0`)和 `assets/index-Dq7sfWZP.js`(SHA-256 `f8499e5f261cc06d02de275e285e4a7c946dd6ef54fd29b3a1c0bc7a9a689c3d`)。本轮只读核验,未执行生产静态资源同步、后端重启或业务数据写入;五维修复仍未被证明在线上生效。
+10 -8
View File
@@ -414,10 +414,11 @@ const fallbackScenarios: ScenarioSeed[] = [
} }
], ],
scores: [ scores: [
{ label: '合规', value: 84, note: '有升级路径' }, { label: '任务完成度', value: 84, note: '有升级路径;训练回退代理' },
{ label: '沟通', value: 88, note: '承诺清楚' }, { label: '话术规范性', value: 86, note: '承诺清楚;训练回退代理' },
{ label: '情绪', value: 82, note: '先承接诉求' }, { label: '情绪管理能力', value: 82, note: '先承接诉求' },
{ label: '错题', value: '1条', note: '补费用争议' } { label: '响应时效', value: '待采集', note: '无真实回合耗时证据时不回填' },
{ label: '增值转化潜力', value: 76, note: '训练回退代理' }
], ],
total: 86, total: 86,
rewrite: '建议表达为:“我先确认责任人和到场时间,10 分钟内回复您;如果今天无法完成,我同步主管给您替代方案和下一次反馈时间。”', rewrite: '建议表达为:“我先确认责任人和到场时间,10 分钟内回复您;如果今天无法完成,我同步主管给您替代方案和下一次反馈时间。”',
@@ -446,10 +447,11 @@ const fallbackScenarios: ScenarioSeed[] = [
} }
], ],
scores: [ scores: [
{ label: '合规', value: 80, note: '复核明确' }, { label: '任务完成度', value: 80, note: '复核明确;训练回退代理' },
{ label: '沟通', value: 83, note: '拆分得当' }, { label: '话术规范性', value: 82, note: '拆分得当;训练回退代理' },
{ label: '情绪', value: 78, note: '安抚一般' }, { label: '情绪管理能力', value: 78, note: '安抚一般' },
{ label: '错题', value: '2条', note: '补开场安抚' } { label: '响应时效', value: '待采集', note: '无真实回合耗时证据时不回填' },
{ label: '增值转化潜力', value: 80, note: '训练回退代理' }
], ],
total: 81, total: 81,
rewrite: '建议先承接情绪:“您觉得服务不到位,我先把问题负责跟到底。”再说明缴费和整改并行,最后给出主管复核与反馈时间。', rewrite: '建议先承接情绪:“您觉得服务不到位,我先把问题负责跟到底。”再说明缴费和整改并行,最后给出主管复核与反馈时间。',
+2
View File
@@ -497,6 +497,8 @@ contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/control
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "mobileCompletedCount" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "mobileCompletedCount"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "任务完成度" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "任务完成度"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "响应时效" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "响应时效"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "new DimensionResponse(\"响应时效\", \"待采集\""
contains frontend/src/views/train/practice.vue "label: '任务完成度'"
contains backend/script/sql/aihr_practice_mysql8.sql "task_completion" contains backend/script/sql/aihr_practice_mysql8.sql "task_completion"
contains backend/script/sql/update/aihr_20260714_practice_five_dimensions_mysql8.sql "aihr_brd_rubric_codes" contains backend/script/sql/update/aihr_20260714_practice_five_dimensions_mysql8.sql "aihr_brd_rubric_codes"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/domain/AihrPracticeDto.java "MistakeAggregateResponse" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/domain/AihrPracticeDto.java "MistakeAggregateResponse"