From 5b7c5613f519a663b871e25a697a28652045bd8d Mon Sep 17 00:00:00 2001 From: let5sne Date: Fri, 24 Jul 2026 22:36:14 +0800 Subject: [PATCH] feat(agent): move mobile ask to unified agent --- .../aihr/agent/AihrAgentActionService.java | 2 +- .../aihr/agent/AihrAgentOrchestrator.java | 12 +- .../dromara/aihr/agent/AihrAgentPlanner.java | 8 ++ .../agent/AihrAgentActionServiceTest.java | 1 + .../aihr/agent/AihrAgentOrchestratorTest.java | 11 ++ .../aihr/agent/AihrAgentPlannerTest.java | 20 +++ .../components/chat/MemoryCandidateCard.vue | 4 +- mobile-uni/src/pages/user/sop/index.vue | 136 +++++++++++------- mobile-uni/src/services/agent.ts | 120 ++++++++++++++++ mobile-uni/src/services/personal-assistant.ts | 12 +- mobile-uni/src/types/api.ts | 54 +++++++ mobile-uni/tests/agent.test.mjs | 50 +++++++ 12 files changed, 368 insertions(+), 62 deletions(-) create mode 100644 mobile-uni/src/services/agent.ts create mode 100644 mobile-uni/tests/agent.test.mjs diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/agent/AihrAgentActionService.java b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/agent/AihrAgentActionService.java index a8fcf52f..3f95e405 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/agent/AihrAgentActionService.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/agent/AihrAgentActionService.java @@ -38,7 +38,7 @@ public class AihrAgentActionService { index.set(draftId, DRAFT_TTL); } redissonClient.getBucket(PREFIX + "draft:" + draftId).set(candidate.id(), DRAFT_TTL); - return new ActionDraft(draftId, candidate.targetDomain(), candidate.version(), candidate.draft()); + return new ActionDraft(draftId, candidate.targetDomain(), candidate.version(), candidate); } public ConfirmMemoryResponse confirm(String draftId, ConfirmMemoryRequest request) { diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/agent/AihrAgentOrchestrator.java b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/agent/AihrAgentOrchestrator.java index c483e431..79fd13d3 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/agent/AihrAgentOrchestrator.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/agent/AihrAgentOrchestrator.java @@ -134,13 +134,19 @@ public class AihrAgentOrchestrator { : AgentStatus.NEEDS_INPUT; sourceType = "MEMORY_DRAFT"; } - String sourceLabel = response.citations().isEmpty() ? sourceType - : response.citations().get(0).title(); + List sources = response.citations().isEmpty() + && "ENTERPRISE_KNOWLEDGE".equals(sourceType) + ? List.of() + : List.of(new SourceSummary( + sourceType, + response.citations().isEmpty() ? sourceType : response.citations().get(0).title(), + OffsetDateTime.now().toString() + )); String answer = actionDraft == null ? response.answer() : "已整理为待确认记录,请核对后保存。"; return new AgentResponse( runId(), response.conversationId(), response.contextVersion(), plan.intent(), status, answer, - List.of(new SourceSummary(sourceType, sourceLabel, OffsetDateTime.now().toString())), + sources, response.citations(), response.resources(), response.data(), actionDraft, null, List.of() ); } diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/agent/AihrAgentPlanner.java b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/agent/AihrAgentPlanner.java index 8adde2f1..6bba088c 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/agent/AihrAgentPlanner.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/agent/AihrAgentPlanner.java @@ -52,6 +52,14 @@ public class AihrAgentPlanner { return plan(Intent.RESOURCE_DELIVERY, request, Tool.KNOWLEDGE_RESOURCE, false, false, ResponseStyle.GROUNDED); } + if (containsAny(request, "团队训练概况", "团队训练情况", "团队完训情况")) { + return plan(Intent.LIVE_TEAM_WORK, request, Tool.TEAM_PRACTICE_SUMMARY, false, false, + ResponseStyle.FACT); + } + if (containsAny(request, "我的训练概况", "我的训练情况", "我的练习概况", "我练得怎么样")) { + return plan(Intent.PRACTICE_COACHING, request, Tool.MY_PRACTICE_SUMMARY, false, false, + ResponseStyle.FACT); + } if (containsAny(request, "我今天有什么待办", "我有什么待办", "我的待办", "我的任务", "我今天该做什么", "我现在该做什么", "今天要做什么", "当前待办")) { return plan(Intent.LIVE_MY_WORK, request, Tool.MY_CURRENT_TASKS, false, false, ResponseStyle.FACT); diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/agent/AihrAgentActionServiceTest.java b/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/agent/AihrAgentActionServiceTest.java index 24d9518c..23daebf0 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/agent/AihrAgentActionServiceTest.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/agent/AihrAgentActionServiceTest.java @@ -38,6 +38,7 @@ class AihrAgentActionServiceTest { var result = service.confirm(draft.draftId(), request); + assertEquals(candidate, draft.payload()); assertEquals("ASSISTANT_CAPTURE", result.targetDomain()); assertEquals(88L, result.targetId()); verify(memory).confirm(7L, request); diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/agent/AihrAgentOrchestratorTest.java b/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/agent/AihrAgentOrchestratorTest.java index ec86f052..630fceda 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/agent/AihrAgentOrchestratorTest.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/agent/AihrAgentOrchestratorTest.java @@ -21,6 +21,7 @@ import static org.dromara.aihr.agent.AihrAgentDto.Intent.KNOWLEDGE_QA; import static org.dromara.aihr.agent.AihrAgentDto.Intent.LIVE_MY_WORK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; @Tag("dev") class AihrAgentOrchestratorTest { @@ -52,6 +53,16 @@ class AihrAgentOrchestratorTest { assertEquals(AgentStatus.COMPLETED, result.status()); } + @Test + void knowledgeNoEvidenceDoesNotInventASource() { + var query = new CapturingQueryService(response("当前授权资料中没有明确依据。", null, true)); + + var result = orchestrator(query).handle(request("装修人员怎么进场?")); + + assertEquals(AgentStatus.NO_EVIDENCE, result.status()); + assertTrue(result.sourceSummary().isEmpty()); + } + @Test void socialAndClarificationDoNotInvokeKnowledge() { var query = new CapturingQueryService(response("unused", null, false)); diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/agent/AihrAgentPlannerTest.java b/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/agent/AihrAgentPlannerTest.java index 6c898511..265d5df1 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/agent/AihrAgentPlannerTest.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/agent/AihrAgentPlannerTest.java @@ -11,7 +11,9 @@ import static org.dromara.aihr.agent.AihrAgentDto.Intent.CAPTURE_FACT; import static org.dromara.aihr.agent.AihrAgentDto.Intent.CLARIFY; import static org.dromara.aihr.agent.AihrAgentDto.Intent.KNOWLEDGE_QA; import static org.dromara.aihr.agent.AihrAgentDto.Intent.LIVE_MY_WORK; +import static org.dromara.aihr.agent.AihrAgentDto.Intent.LIVE_TEAM_WORK; import static org.dromara.aihr.agent.AihrAgentDto.Intent.MEDIA_UNDERSTANDING; +import static org.dromara.aihr.agent.AihrAgentDto.Intent.PRACTICE_COACHING; import static org.dromara.aihr.agent.AihrAgentDto.Intent.RESOURCE_DELIVERY; import static org.dromara.aihr.agent.AihrAgentDto.Intent.SOCIAL; import static org.dromara.aihr.agent.AihrAgentDto.Tool.CAPTURE_MEMORY_DRAFT; @@ -19,7 +21,9 @@ import static org.dromara.aihr.agent.AihrAgentDto.Tool.KNOWLEDGE_RESOURCE; import static org.dromara.aihr.agent.AihrAgentDto.Tool.KNOWLEDGE_SEARCH; import static org.dromara.aihr.agent.AihrAgentDto.Tool.MEDIA_ANALYZE; import static org.dromara.aihr.agent.AihrAgentDto.Tool.MY_CURRENT_TASKS; +import static org.dromara.aihr.agent.AihrAgentDto.Tool.MY_PRACTICE_SUMMARY; import static org.dromara.aihr.agent.AihrAgentDto.Tool.NONE; +import static org.dromara.aihr.agent.AihrAgentDto.Tool.TEAM_PRACTICE_SUMMARY; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -38,6 +42,22 @@ class AihrAgentPlannerTest { assertFalse(plan.requiresConfirmation()); } + @Test + void routesOwnTrainingSummaryToLivePracticeData() { + var plan = planner.plan("查询我的训练概况", false); + + assertEquals(PRACTICE_COACHING, plan.intent()); + assertEquals(MY_PRACTICE_SUMMARY, plan.tool()); + } + + @Test + void routesTeamTrainingSummaryToSupervisorData() { + var plan = planner.plan("查询我的团队训练概况", false); + + assertEquals(LIVE_TEAM_WORK, plan.intent()); + assertEquals(TEAM_PRACTICE_SUMMARY, plan.tool()); + } + @Test void routesExplicitCaptureToConfirmationDraft() { var plan = planner.plan("记一下,3栋1201要回访", false); diff --git a/mobile-uni/src/components/chat/MemoryCandidateCard.vue b/mobile-uni/src/components/chat/MemoryCandidateCard.vue index 81f2f5a0..c15ced8a 100644 --- a/mobile-uni/src/components/chat/MemoryCandidateCard.vue +++ b/mobile-uni/src/components/chat/MemoryCandidateCard.vue @@ -278,7 +278,7 @@ const confirm = async (saveScope: '' | 'PRIVATE' | 'COMPANY' = '') => { errorText.value = ''; const requestAccountKey = currentAccountKey(); try { - const result = await confirmMemoryCandidate(props.candidate.id, { + const result = await confirmMemoryCandidate(props.candidate.agentDraftId || props.candidate.id, { expectedVersion: props.candidate.version, idempotencyKey: idempotencyKey.value, draft: { @@ -306,7 +306,7 @@ const dismiss = async () => { errorText.value = ''; const requestAccountKey = currentAccountKey(); try { - await dismissMemoryCandidate(props.candidate.id); + await dismissMemoryCandidate(props.candidate.agentDraftId || props.candidate.id); if (requestAccountKey !== currentAccountKey()) return; emit('dismissed', props.candidate.id); } catch (error) { diff --git a/mobile-uni/src/pages/user/sop/index.vue b/mobile-uni/src/pages/user/sop/index.vue index 3947b39b..301973a8 100644 --- a/mobile-uni/src/pages/user/sop/index.vue +++ b/mobile-uni/src/pages/user/sop/index.vue @@ -121,7 +121,26 @@ v-if="msg.result.rewrittenQuery && msg.result.rewrittenQuery !== msg.result.queryText" class="context-used" >已结合本次对话理解 + + {{ source.label }} + {{ msg.result.answer || '未生成直接答案,请查看引用依据。' }} + + {{ msg.result.clarification.prompt }} + + {{ index + 1 }}. {{ cleanOrderedText(point) }} @@ -133,7 +152,7 @@ {{ item }} - 当前授权空间内没有足够依据。 + {{ noEvidenceText(msg.result) }} - - + -