From 3d3960a3b3d1057db9d2f4016512915e7a5c517d Mon Sep 17 00:00:00 2001 From: Administrator <15274802129@163.com> Date: Thu, 25 Sep 2025 09:56:21 +0800 Subject: [PATCH] feat(ai): 集成百炼工作流实现AI流式对话功能 - 新增百炼工作流SDK相关依赖和工具类 - 实现llmInvokeStreamingWithThink方法用于流式调用 - 配置API Key和应用ID以连接百炼平台 - 启用思考模式(enableThinking)和思维输出(hasThoughts) - 处理流式响应并封装为FebsResponse返回 - 添加异常处理机制捕获API调用错误 - 移除原有的静态提示词配置逻辑 -重构answerStreamV3接口直接调用新实现 --- src/main/java/cc/mrbird/febs/ai/controller/TestController.java | 82 ++++++++++++++++++++++++++++++++-------- 1 files changed, 65 insertions(+), 17 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 a25deb7..4df6fa5 100644 --- a/src/main/java/cc/mrbird/febs/ai/controller/TestController.java +++ b/src/main/java/cc/mrbird/febs/ai/controller/TestController.java @@ -4,13 +4,15 @@ 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.res.memberTalk.ApiMemberTalkStreamVoOld; import cc.mrbird.febs.ai.service.AiService; +import cc.mrbird.febs.ai.strategy.enumerates.LlmStrategyContextEnum; 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.exception.FebsException; import cc.mrbird.febs.common.utils.AppContants; import cc.mrbird.febs.common.utils.RedisUtils; import cc.mrbird.febs.mall.entity.MallMember; @@ -20,6 +22,11 @@ import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.asymmetric.KeyType; import cn.hutool.crypto.asymmetric.RSA; +import com.alibaba.dashscope.app.Application; +import com.alibaba.dashscope.app.ApplicationParam; +import com.alibaba.dashscope.app.ApplicationResult; +import com.alibaba.dashscope.app.FlowStreamMode; +import com.alibaba.dashscope.utils.JsonUtils; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import io.reactivex.Flowable; @@ -106,7 +113,7 @@ @ApiOperation("提问AI(流式)V2") @ApiResponses({ - @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVo.class), + @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVoOld.class), }) @PostMapping("/answer-streamV2") public Flux<FebsResponse> answerStreamV2(@RequestBody @Validated AiTalkAnswerStream dto) { @@ -146,37 +153,78 @@ @ApiOperation("提问AI(流式)V3") @ApiResponses({ - @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVo.class), + @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVoOld.class), }) @PostMapping("/answerStreamV3") public Flux<FebsResponse> answerStreamV3(@RequestBody @Validated AiTalkAnswerStream dto) { - if (StrUtil.isEmpty(dto.getQuestion())){ - return Flux.just(new FebsResponse().fail().message("请输入问题")); + + return llmInvokeStreamingWithThink(); + } + + private Flux<FebsResponse> llmInvokeStreamingWithThink(){ + + long startTime = System.currentTimeMillis(); + ApplicationParam param = ApplicationParam.builder() + // 若没有配置环境变量,可用百炼API Key将下行替换为:.apiKey("sk-xxx")。但不建议在生产环境中直接将API Key硬编码到代码中,以减少API Key泄露风险。 + .apiKey("sk-babdcf8799144134915cee2683794b2f") + .appId("f94539c7e54d44e2a7cac5e85f2ae61d") //替换为实际的应用 ID + .flowStreamMode(FlowStreamMode.MESSAGE_FORMAT) + .prompt("你是谁?") + .enableThinking( true) + .hasThoughts( true) + .build(); + + Application application = new Application(); + Flowable<ApplicationResult> result; + try { + result = application.streamCall(param); + } catch (NoApiKeyException | InputRequiredException e) { + throw new FebsException(StrUtil.format("百炼工作流输出失败:{}",e.getMessage())); } - ArrayList<LlmStrategyDto> llmStrategyDtoList = new ArrayList<>(); - if (dto.getPrompt() != null){ - LlmStrategyDto llmStrategyDto = new LlmStrategyDto(); + return Flux.from(result) + .map(message -> { + HashMap<String, String> stringStringHashMap = new HashMap<>(); + + System.out.print(message.getOutput().getThoughts()); + if (!message.getOutput().getFinishReason().equals("stop")){ + stringStringHashMap.put(LlmStrategyContextEnum.CONTENT.name(),message.getOutput().getWorkflowMessage().getMessage().getContent()); + } + return new FebsResponse().success().data(stringStringHashMap); + }) + .doOnComplete(() -> { + long endTime = System.currentTimeMillis(); + System.out.println("百炼工作流输出:" + (endTime - startTime) + "毫秒"); + }) + .doOnError(error -> { + throw new FebsException(StrUtil.format("百炼工作流输出失败:{}",error)); + }); + } + + private LlmStrategyDto buildLlmStrategyDtoList(String Str, Integer type){ + LlmStrategyDto llmStrategyDto = new LlmStrategyDto(); + if (type == 1){ llmStrategyDto.setRole(Role.SYSTEM.getValue()); - llmStrategyDto.setContent(dto.getPrompt()); - llmStrategyDtoList.add(llmStrategyDto); } - if (dto.getQuestion() != null){ - LlmStrategyDto llmStrategyDto = new LlmStrategyDto(); + if (type == 2){ llmStrategyDto.setRole(Role.USER.getValue()); - llmStrategyDto.setContent(dto.getQuestion()); - llmStrategyDtoList.add(llmStrategyDto); } - String modelName = LlmStrategyEnum.getName(aiService.getSystemSetAiType()); + if (type == 3){ + llmStrategyDto.setRole(Role.ASSISTANT.getValue()); + } + if (type == 4){ + llmStrategyDto.setRole(Role.TOOL.getValue()); + } + llmStrategyDto.setContent(Str); - return llmStrategyFactory.getCalculationStrategyMap().get(modelName).llmInvokeStreamingWithThink(llmStrategyDtoList); + return llmStrategyDto; } @ApiOperation("提问AI(非流式响应)V4") @ApiResponses({ - @ApiResponse(code = 200, message = "非流式响应", response = ApiMemberTalkStreamVo.class), + @ApiResponse(code = 200, message = "非流式响应", response = ApiMemberTalkStreamVoOld.class), }) @PostMapping("/answerStreamV4") public FebsResponse answerStreamV4(@RequestBody @Validated AiTalkAnswerStream dto) { -- Gitblit v1.9.1