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 | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 209 insertions(+), 4 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 a019a22..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.product.ApiProductInfoDto; -import cc.mrbird.febs.ai.res.product.ApiProductInfoVo; +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; @@ -17,6 +22,7 @@ import cn.hutool.crypto.asymmetric.RSA; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import io.reactivex.Flowable; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; @@ -26,8 +32,17 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import java.util.HashMap; -import java.util.Map; +import com.alibaba.dashscope.aigc.generation.Generation; +import com.alibaba.dashscope.aigc.generation.GenerationParam; +import com.alibaba.dashscope.aigc.generation.GenerationResult; +import com.alibaba.dashscope.common.Message; +import com.alibaba.dashscope.common.Role; +import com.alibaba.dashscope.exception.ApiException; +import com.alibaba.dashscope.exception.InputRequiredException; +import com.alibaba.dashscope.exception.NoApiKeyException; +import reactor.core.publisher.Flux; + +import java.util.*; /** * @author Administrator @@ -42,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() { @@ -84,4 +101,192 @@ //去掉时间戳 return rsa.encryptBase64(token, KeyType.PublicKey); } + + + + @ApiOperation("提问AI(流式)V2") + @ApiResponses({ + @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVo.class), + }) + @PostMapping("/answer-streamV2") + public Flux<FebsResponse> answerStreamV2(@RequestBody @Validated AiTalkAnswerStream dto) { + if (StrUtil.isEmpty(dto.getQuestion())){ + return Flux.just(new FebsResponse().fail().message("请输入问题")); + } + String question = dto.getQuestion(); + String prompt = dto.getPrompt() ; + + long startTime = System.currentTimeMillis(); + + Flowable<GenerationResult> result; + try { + result = callWithMessageStream(question,prompt); + } catch (NoApiKeyException | InputRequiredException e) { + e.printStackTrace(); + return Flux.just(new FebsResponse().fail().message("调用AI服务失败: " + e.getMessage())); + } + + return Flux.from(result) + .map(message -> { + String content = message.getOutput().getChoices().get(0).getMessage().getContent(); + System.out.print(content); + return new FebsResponse().success().data(content); + }) + .doOnComplete(() -> { + long endTime = System.currentTimeMillis(); + System.out.println("运行时间:" + (endTime - startTime) + "毫秒"); + }) + .doOnError(error -> { + long endTime = System.currentTimeMillis(); + System.err.println("运行时间:" + (endTime - startTime) + "毫秒,发生错误:" + error.getMessage()); + }); + } + + + + @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()) + .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") +// .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 = "下属负责的项目高质量按期交付,除了表扬,你希望 下属要多注意和同事的沟通,应如何表达"; + 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 { + resultStream = callWithMessageStream(question, prompt); + } catch (NoApiKeyException e) { + e.printStackTrace(); + } catch (InputRequiredException e) { + e.printStackTrace(); + } + 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 endTimeStream = System.currentTimeMillis(); + System.out.println("运行时间:" + (endTimeStream - startTimeStream) + "毫秒"); + } } -- Gitblit v1.9.1