From 34effb23193bf24c793d31dfde3805c4653f0fe9 Mon Sep 17 00:00:00 2001 From: let5sne Date: Wed, 15 Jul 2026 00:43:26 +0800 Subject: [PATCH] fix(aihr): suppress rejected sop answers --- .../dromara/aihr/service/AihrSopSeedService.java | 14 ++++++++++---- .../aihr/service/AihrSopSeedServiceTest.java | 12 ++++++++++++ docs/BRD_IMPLEMENTATION_AUDIT.md | 2 ++ scripts/demo-check.sh | 1 + 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java index cfde93f4..cda909bc 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java @@ -1858,6 +1858,9 @@ public class AihrSopSeedService { return null; } FeedbackFilterResult filtered = filterDownFeedback(queryText, hits); + if (filtered.hits().isEmpty()) { + return noEvidenceResponse(queryText, category, filtered.cautions()); + } return responseFromHits(category, queryText, filtered.hits(), filtered.cautions()); } catch (DataAccessException e) { return null; @@ -2198,7 +2201,10 @@ public class AihrSopSeedService { } private FeedbackFilterResult filterDownFeedback(String queryText, List hits) { - Set rejected = downFeedbackFragmentIds(queryText); + return filterDownFeedback(hits, downFeedbackFragmentIds(queryText)); + } + + static FeedbackFilterResult filterDownFeedback(List hits, Set rejected) { if (rejected.isEmpty()) { return new FeedbackFilterResult(hits, List.of()); } @@ -2207,8 +2213,8 @@ public class AihrSopSeedService { .toList(); if (filtered.isEmpty()) { return new FeedbackFilterResult( - hits, - List.of("该问题下命中的片段均曾被点踩,本次保留原结果避免无答案。") + List.of(), + List.of("该问题下命中的片段均曾被点踩,本次不再推送原答案。") ); } return new FeedbackFilterResult(filtered, List.of()); @@ -3538,7 +3544,7 @@ public class AihrSopSeedService { record KnowledgeHit(Long fragmentId, String title, String category, String description, String docId, String content, int idx, double score) { } - private record FeedbackFilterResult(List hits, List cautions) { + static record FeedbackFilterResult(List hits, List cautions) { } private record KnowledgeConfig(long knowledgeId, int blockSize, int overlap) { diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrSopSeedServiceTest.java b/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrSopSeedServiceTest.java index 1916cfe3..269a943c 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrSopSeedServiceTest.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrSopSeedServiceTest.java @@ -10,6 +10,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import java.util.Optional; +import java.util.Set; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -102,6 +103,17 @@ public class AihrSopSeedServiceTest { assertEquals(3L, evidence.get(2).fragmentId()); } + @Test + @Tag("dev") + public void allDownVotedHitsAreSuppressed() { + List hits = List.of(hit(1L, "投诉处理 SOP.pdf")); + + AihrSopSeedService.FeedbackFilterResult filtered = AihrSopSeedService.filterDownFeedback(hits, Set.of(1L)); + + assertTrue(filtered.hits().isEmpty()); + assertTrue(filtered.cautions().get(0).contains("不再推送")); + } + @Test @Tag("dev") public void displaySnippetTextCleansVideoAsrNoise() { diff --git a/docs/BRD_IMPLEMENTATION_AUDIT.md b/docs/BRD_IMPLEMENTATION_AUDIT.md index 0f2b8726..db2dd621 100644 --- a/docs/BRD_IMPLEMENTATION_AUDIT.md +++ b/docs/BRD_IMPLEMENTATION_AUDIT.md @@ -1,5 +1,7 @@ # BRD 功能审查与未完成项记录 +- 2026-07-15 BRD 4.7 知识答案负反馈闭环修复:SOP 检索此前在某问题命中的片段全部被点踩时仍保留原答案,违背“同一问题后续不再推送该条目”的约定;现由共享检索过滤返回无明确依据的答案并保留提示,不再把被点踩片段作为答案证据。新增 `AihrSopSeedServiceTest.allDownVotedHitsAreSuppressed` 和 `demo-check` marker;未修改业务数据,后续仍需正式员工问答样本验证替代答案质量。 + - 2026-07-15 严格试点门禁可读性补强:`scripts/demo-check.sh` 新增 `catalog_schema=3/3`,严格模式在场景/Rubric 三张基础表缺失时明确失败,而不是只输出空的场景统计;临时库回归覆盖缺少 Rubric 表的 `catalog_schema=1/3` 状态。该修复不改变生产数据和业务门槛,仅让生产迁移缺口可被明确识别。 - 2026-07-15 严格试点门禁补强:`scripts/demo-check.sh` 原先只检查 SOP 评审的 `prompt_version` 字段,未检查 6 个内置 Prompt 是否实际落库;现新增 `prompt_templates=6/6` 查询和 strict 失败条件,并在 `scripts/tests/demo-check-pilot-gates.test.sh` 的临时库加入 6 个模板回归。该修复能阻止“schema 已迁移但 Prompt 内容为 0”的生产状态被误判为可验收;未修改生产数据。 diff --git a/scripts/demo-check.sh b/scripts/demo-check.sh index 4a43b05b..da40848c 100755 --- a/scripts/demo-check.sh +++ b/scripts/demo-check.sh @@ -403,6 +403,7 @@ contains mobile-uni/src/services/practice.ts "/api/aihr/mobile/profile/promotion contains mobile-uni/src/pages/user/practice/index.vue "训练完成,主管端待复盘已更新" contains mobile-uni/src/pages/user/profile/index.vue "人工贡献分" contains mobile-uni/src/services/knowledge.ts "/api/knowledge/answer-feedback" +contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java "本次不再推送原答案" contains mobile-uni/src/pages/user/sop/index.vue "有帮助" contains mobile-uni/src/pages/user/sop/index.vue "没解决" contains mobile-uni/src/services/knowledge.ts "/api/knowledge/summary-card"