From 18fdf89338e84e1cab48c2795631777e22b05b81 Mon Sep 17 00:00:00 2001 From: Administrator <15274802129@163.com> Date: Wed, 03 Sep 2025 14:37:54 +0800 Subject: [PATCH] feat(ai): 添加灵通角色设定PROMPT功能 --- src/main/java/cc/mrbird/febs/ai/controller/TestController.java | 192 +++++++++++++++++++++++++++++------------------ 1 files changed, 118 insertions(+), 74 deletions(-) diff --git a/src/main/java/cc/mrbird/febs/ai/controller/TestController.java b/src/main/java/cc/mrbird/febs/ai/controller/TestController.java index 04318c3..a25deb7 100644 --- a/src/main/java/cc/mrbird/febs/ai/controller/TestController.java +++ b/src/main/java/cc/mrbird/febs/ai/controller/TestController.java @@ -1,9 +1,14 @@ package cc.mrbird.febs.ai.controller; import cc.mrbird.febs.ai.entity.AiMember; +import cc.mrbird.febs.ai.enumerates.AiPromptEnum; import cc.mrbird.febs.ai.mapper.AiMemberMapper; import cc.mrbird.febs.ai.req.talk.AiTalkAnswerStream; import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkStreamVo; +import cc.mrbird.febs.ai.service.AiService; +import cc.mrbird.febs.ai.strategy.enumerates.LlmStrategyEnum; +import cc.mrbird.febs.ai.strategy.LlmStrategyFactory; +import cc.mrbird.febs.ai.strategy.param.LlmStrategyDto; import cc.mrbird.febs.ai.utils.UUID; import cc.mrbird.febs.common.entity.FebsResponse; import cc.mrbird.febs.common.utils.AppContants; @@ -15,8 +20,6 @@ import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.asymmetric.KeyType; import cn.hutool.crypto.asymmetric.RSA; -import cn.hutool.json.JSONUtil; -import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import io.reactivex.Flowable; @@ -39,9 +42,7 @@ import com.alibaba.dashscope.exception.NoApiKeyException; import reactor.core.publisher.Flux; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; +import java.util.*; /** * @author Administrator @@ -56,7 +57,9 @@ private final MallMemberMapper mallMemberMapper; private final AiMemberMapper aiMemberMapper; + private final AiService aiService; private final RedisUtils redisUtils; + private final LlmStrategyFactory llmStrategyFactory; @ApiOperation(value = "登录测试", notes = "登录测试") @GetMapping(value = "/login") public FebsResponse info() { @@ -117,7 +120,7 @@ Flowable<GenerationResult> result; try { - result = callWithMessage(question,prompt); + result = callWithMessageStream(question,prompt); } catch (NoApiKeyException | InputRequiredException e) { e.printStackTrace(); return Flux.just(new FebsResponse().fail().message("调用AI服务失败: " + e.getMessage())); @@ -140,7 +143,66 @@ } - public static Flowable<GenerationResult> callWithMessage(String question,String prompt) throws NoApiKeyException, InputRequiredException { + + @ApiOperation("提问AI(流式)V3") + @ApiResponses({ + @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVo.class), + }) + @PostMapping("/answerStreamV3") + public Flux<FebsResponse> answerStreamV3(@RequestBody @Validated AiTalkAnswerStream dto) { + if (StrUtil.isEmpty(dto.getQuestion())){ + return Flux.just(new FebsResponse().fail().message("请输入问题")); + } + + ArrayList<LlmStrategyDto> llmStrategyDtoList = new ArrayList<>(); + if (dto.getPrompt() != null){ + LlmStrategyDto llmStrategyDto = new LlmStrategyDto(); + llmStrategyDto.setRole(Role.SYSTEM.getValue()); + llmStrategyDto.setContent(dto.getPrompt()); + llmStrategyDtoList.add(llmStrategyDto); + } + if (dto.getQuestion() != null){ + LlmStrategyDto llmStrategyDto = new LlmStrategyDto(); + llmStrategyDto.setRole(Role.USER.getValue()); + llmStrategyDto.setContent(dto.getQuestion()); + llmStrategyDtoList.add(llmStrategyDto); + } + String modelName = LlmStrategyEnum.getName(aiService.getSystemSetAiType()); + + return llmStrategyFactory.getCalculationStrategyMap().get(modelName).llmInvokeStreamingWithThink(llmStrategyDtoList); + } + + + + @ApiOperation("提问AI(非流式响应)V4") + @ApiResponses({ + @ApiResponse(code = 200, message = "非流式响应", response = ApiMemberTalkStreamVo.class), + }) + @PostMapping("/answerStreamV4") + public FebsResponse answerStreamV4(@RequestBody @Validated AiTalkAnswerStream dto) { + if (StrUtil.isEmpty(dto.getQuestion())){ + return new FebsResponse().fail().message("请输入问题"); + } + ArrayList<LlmStrategyDto> llmStrategyDtoList = new ArrayList<>(); + if (dto.getPrompt() != null){ + LlmStrategyDto llmStrategyDto = new LlmStrategyDto(); + llmStrategyDto.setRole(Role.SYSTEM.getValue()); + llmStrategyDto.setContent(dto.getPrompt()); + llmStrategyDtoList.add(llmStrategyDto); + } + if (dto.getQuestion() != null){ + LlmStrategyDto llmStrategyDto = new LlmStrategyDto(); + llmStrategyDto.setRole(Role.USER.getValue()); + llmStrategyDto.setContent(dto.getQuestion()); + llmStrategyDtoList.add(llmStrategyDto); + } + String modelName = LlmStrategyEnum.getName(aiService.getSystemSetAiType()); + + return llmStrategyFactory.getCalculationStrategyMap().get(modelName).llmInvokeNonStreaming(llmStrategyDtoList); + } + + + public static Flowable<GenerationResult> callWithMessageStream(String question,String prompt) throws NoApiKeyException, InputRequiredException { Generation gen = new Generation(); Message systemMsg = Message.builder() .role(Role.SYSTEM.getValue()) @@ -154,95 +216,77 @@ // 若没有配置环境变量,请用阿里云百炼API Key将下行替换为:.apiKey("sk-xxx") .apiKey("sk-babdcf8799144134915cee2683794b2f") // 模型列表:https://help.aliyun.com/zh/model-studio/getting-started/models - .model("qwen-plus") + .model("qwen3-14b-ft-202509031002-7446") // .model("deepseek-r1") // .model("qwen-turbo-0624-ft-202508281725-c2dc") .messages(Arrays.asList(systemMsg, userMsg)) // .resultFormat(GenerationParam.ResultFormat.TEXT) .resultFormat(GenerationParam.ResultFormat.MESSAGE) + .enableThinking( true) .incrementalOutput(true) .build(); return gen.streamCall(param); } + + + public static GenerationResult callWithMessage(String question,String prompt) throws ApiException, NoApiKeyException, InputRequiredException { + Generation gen = new Generation(); + Message systemMsg = Message.builder() + .role(Role.SYSTEM.getValue()) + .content(prompt) + .build(); + Message userMsg = Message.builder() + .role(Role.USER.getValue()) + .content(question) + .build(); + GenerationParam param = GenerationParam.builder() + // 若没有配置环境变量,请用阿里云百炼API Key将下行替换为:.apiKey("sk-xxx") + .apiKey("sk-babdcf8799144134915cee2683794b2f") + // 模型列表:https://help.aliyun.com/zh/model-studio/getting-started/models + .model("qwen3-14b-ft-202509031002-7446") + .messages(Arrays.asList(systemMsg, userMsg)) + .resultFormat(GenerationParam.ResultFormat.MESSAGE) + .enableThinking( false) + .build(); + return gen.call(param); + } public static void main(String[] args) { //定义一个开始时间为启动这个main方法的开始时间,用于计算运行时间 long startTime = System.currentTimeMillis(); - String question = "1"; - String prompt = "假如你是一个表扬题目生成专家,你将根据多样化结构表扬场景题目的生成需求,来解决生成多样化结构的表扬场景题目的任务。根据以下规则一步步执行:\n" + - "1. 从角色视角/员工类型/成就类型/场景要素中各随机选择一项进行组合。\n" + - "\t- 角色视角(上级对下级、下级对上级、平级同事、跨部门同事、项目负责人对临时团队)\n" + - "\t- 员工类型(新入职员工、资深骨干员工、基层管理者、中层管理者、高层管理者、跨部门协作人员、远程办公团队成员、实习生 / 管培生、技术研发人员、业务 / 销售一线人员)\n" + - "\t- 成就类型(项目攻坚、创新改进、危机处理、长期贡献、团队建设、知识分享、客户满意度、成本控制、新人培养、跨部门协作)\n" + - "\t- 场景要素(公开会议、私下沟通、书面形式、线上场景、庆典活动、突发场景、例行场景、特殊时刻、外部场合、非正式场合)\n" + - "2. 采用 3 种可变句式结构动态生成题目:\n" + - " - 结构 A:\"作为 [角色]的你,如何在 [场景] 中认可 [员工类型] 的 [成就(带有具体细节描述)]?\"\n" + - " - 结构 B:\"当 [员工类型] 在 [场景] 中达成 [成就(带有具体细节描述)] 时,[角色]的你 应如何表达赞赏?\"\n" + - " - 结构 C:\"在 [场景] 下,[角色]的你 发现 [员工类型] 取得 [成就(带有具体细节描述)],适合采取何种表扬方式?\"\n" + - "3. 自动添加如 \"提前完成项目 deadline\"、\"创新方案节省 20% 成本\" 等具体情境细节描述。\n" + - "4. 无论用户输入什么内容只生成 1 个独特题目,覆盖 100 + 可能组合。\n" + - "5. 支持通过添加限定词定制题目,如 \"生成远程团队相关题目\"、\"包含成本控制成就的题目\"。\n" + - "6. 题目设计兼顾传统与新兴职场场景(如远程办公、跨文化团队)。\n" + - "\n" + - "参考例子:\n" + - "示例1:\n" + - "输出:作为跨部门同事,如何在视频会议中认可技术研发人员提前完成创新改进项目的贡献?\n" + - "\n" + - "示例2:\n" + - "输出:当实习生在团队庆功宴的危机处理中成功化解客户投诉时,作为部门经理应如何表达赞赏?\n" + - "\n" + - "示例3:\n" + - "输出:在年度颁奖典礼上,基层管理者发现远程办公团队成员凭借长期稳定的工作表现达成长期贡献,适合采取何种表扬方式?\n" + - "\n" + - "示例4:\n" + - "输出:作为新入职员工,如何在非正式交流中向高层管理者表达对其成功处理突发危机的认可?\n" + - "\n" + - "输出:\n" + - "\n" + - "要求:\n" + - "1 输出一个符合上述规则生成的表扬场景题目。\n" + - "2 题目需包含角色视角、员工类型、成就类型、场景要素等关键信息,且符合三种结构中的一种,并带有具体细节描述。\n" + - "###"; - - Flowable<GenerationResult> result = null; + String question = "下属负责的项目高质量按期交付,除了表扬,你希望 下属要多注意和同事的沟通,应如何表达"; + String prompt = AiPromptEnum.STREAM_NORMAL.getPrompt(); + String prompt1 = "{ \"question\":\"下属负责的项目高质量按期交付,除了表扬,你希望 下属要多注意和同事的沟通,应如何表达\", \"task\": \"作为专业的表扬能力评估分析师,根据表扬场景题目及用户输入内容,实现对表扬能力的全方位评估与指导。\", \"rules\": [ \"用户输入内容需符合问题中的场景要素与角色设定,若无关则返回:[请回答提出的问题]\", \"生成四维评价体系[evaluation],每部分不少于50字:\", \" - 亮点[highlight]:识别符合表扬原则的积极策略,关注角色视角适配性、员工类型特点、具体行为描述、情感表达真诚度与个性化认可方式\", \" - 建议[suggestion]:提供针对性优化方案,涵盖场景要素匹配度、成就类型适配、STAR法则强化、跨文化/远程场景策略\", \" - 参考答案[referenceAnswer]:遵循平级表扬'三明治法则'、危机处理三维度、长期贡献认可策略\", \" - 核心知识点[keyKnowledge]:包含心理学依据、组织行为学理论、标杆案例、文化适配分析\", \"生成五维评分模型[radarDataItems],采用1-10分制:\", \" - 针对性(problemUnderstanding):表扬内容与实际贡献匹配度\", \" - 具体性(fluency):量化成果、行为细节、独特贡献描述\", \" - 情感温度(principleAdherence):语言真诚度和情感连接强度\", \" - 激励性(logicality):对后续工作动力和行为导向的积极影响\", \" - 文化契合度(knowledgeMastery):表扬方式与组织价值观一致性\", \"评分标准:1-4分(需重大改进)、5-7分(基本合格)、8-10分(优秀示范)\", \"特殊场景处理:\", \" - 下级对上级表扬:评估谦逊度与事实依据,避免过度恭维\", \" - 跨部门协作场景:关注协作价值强调与横向影响力评价\", \" - 远程团队情境:评价异步沟通适应性与技术工具合理运用\" ], \"output_format\": { \"type\": \"json\", \"structure\": { \"evaluation\": { \"highlight\": \"字符串(≥50字)\", \"suggestion\": \"字符串(≥50字)\", \"referenceAnswer\": \"字符串\", \"keyKnowledge\": \"字符串(≥50字)\" }, \"radarDataItems\": [ { \"code\": \"problemUnderstanding\", \"score\": \"整数(1-10)\", \"name\": \"针对性\" }, { \"code\": \"fluency\", \"score\": \"整数(1-10)\", \"name\": \"具体性\" }, { \"code\": \"principleAdherence\", \"score\": \"整数(1-10)\", \"name\": \"情感温度\" }, { \"code\": \"logicality\", \"score\": \"整数(1-10)\", \"name\": \"激励性\" }, { \"code\": \"knowledgeMastery\", \"score\": \"整数(1-10)\", \"name\": \"文化契合度\" } ] } }}"; + String prompt2 = "{\"task\": \"作为专业的表扬能力评估分析师,分析question和用户输入内容,对用户输入内容进行评估与指导。\",\"question\":\"当资深骨干员工在突发场景中迅速响应并解决了持续一周的客户投诉达成客户满意度成就时,作为上级的你应如何表达赞赏?\",\"reference_answer\": \"根据问题用户的回答,生成参考示例\"}"; + String prompt3 = "{\"task\":\"假如你是一个表扬题目生成专家,你将根据多样化结构表扬场景题目的生成需求,来解决生成多样化结构的表扬场景题目的任务。示例1:作为跨部门同事,如何在视频会议中认可技术研发人员提前完成创新改进项目的贡献?示例2:当实习生在团队庆功宴的危机处理中成功化解客户投诉时,作为部门经理应如何表达赞赏?示例3:在年度颁奖典礼上,基层管理者发现远程办公团队成员凭借长期稳定的工作表现达成长期贡献,适合采取何种表扬方式?\",\"rules\":\"要求:1 输出一个符合上述规则生成的表扬场景题目。2 题目需包含角色视角、员工类型、成就类型、场景要素等关键信息,且符合三种结构中的一种,并带有具体细节描述。3 无论用户输入什么内容只生成 1 个独特题目。\",\"output\":\"纯文本输出\"}"; +// GenerationResult result = null; +// try { +// result = callWithMessage(question, prompt); +// } catch (NoApiKeyException e) { +// e.printStackTrace(); +// } catch (InputRequiredException e) { +// e.printStackTrace(); +// } +// System.out.println(result.getOutput().getChoices().get(0).getMessage().getContent()); +// long endTime = System.currentTimeMillis(); +// System.out.println("运行时间:" + (endTime - startTime) + "毫秒"); + long startTimeStream = System.currentTimeMillis(); + Flowable<GenerationResult> resultStream = null; try { - result = callWithMessage(question, prompt); + resultStream = callWithMessageStream(question, prompt); } catch (NoApiKeyException e) { e.printStackTrace(); } catch (InputRequiredException e) { e.printStackTrace(); } - Flux.from(result) + Flux.from(resultStream) .doOnNext(message -> { + String reasoningContent = message.getOutput().getChoices().get(0).getMessage().getReasoningContent(); + System.out.print(reasoningContent); String content = message.getOutput().getChoices().get(0).getMessage().getContent(); System.out.print(content); }) .subscribe(); - long endTime = System.currentTimeMillis(); - System.out.println("运行时间:" + (endTime - startTime) + "毫秒"); -// result.blockingForEach(item -> { -//// log.info("item: {}", JSONUtil.toJsonStr(item)); -// // 提取文本内容 -// if (item.getOutput() != null && item.getOutput().getChoices() != null) { -// item.getOutput().getChoices().forEach(choice -> { -// if (choice.getMessage() != null) { -// // 根据实际 API 文档确定使用哪个方法 -//// if (choice.getMessage().getContents() != null) { -//// try { -//// choice.getMessage().getContents().forEach(content -> { -//// if (content != null) { -//// System.out.print(content.getType()); -//// } -//// }); -//// } catch (NullPointerException e) { -//// log.error("Error processing contents", e); -//// } -//// } -// if (choice.getMessage().getContent() != null) { -// System.out.print(choice.getMessage().getContent()); -// } -// } -// }); -// } -// }); + long endTimeStream = System.currentTimeMillis(); + System.out.println("运行时间:" + (endTimeStream - startTimeStream) + "毫秒"); } } -- Gitblit v1.9.1