从入门到放弃

从入门到放弃

暂无个人简介
知识星球
Java后端
2015
浙江理工大学

该用户为会员

会员专享项目教程/ 答疑等服务

SpringAI RAG MCP Agent,AI 超级智能体企业级实战(25 年必学) - 5 - RAG 知识库进阶 笔记

提问 项目 BI智能平台,想用定时任务重新分析失败的分析任务, 大致思路:是把controller层的线程池异步调用ai的代码抽成一个方法,供接口和定时任务共用,定时任务每隔一段时间通过chartService获取失败任务列表并遍历,遍历中调用controller层的异步调用ai的方法。 现在出现问题,定时任务在调用controller的异步调用ai的方法时,会报错。 报错信息:java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request. 是什么原因照成的问题和如何解决,请大神指教! ==================定时任务代码===================== @Component public class FailedGenChartWrokSchedule { private static ChartController chartController; @Autowired private void setChartController(ChartController chartController) { FailedGenChartWrokSchedule.chartController = chartController; } @Resource private ChartService chartService; @Scheduled(fixedRate = 50000) public void doFailedWrok(){ log.info("失败任务重启策略启动"); QueryWrapper<Chart> wrapper = new QueryWrapper<>(); wrapper.eq("status","failed"); List<Chart> chartList = chartService.list(wrapper); try { for (int i = 0; i < chartList.size(); i ) { Chart chart = chartList.get(i); StringBuffer userInput = format(chart); chartController.invokeAI(userInput,chart); log.info("失败任务id:" chart.getId() ",重启任务成功"); } }catch (Exception e){ log.error("失败分析任务重试失败," e); } } } ================controller部分代码=================== @RestController @RequestMapping("/chart") @Slf4j public class ChartController { /** * 智能分析(异步) * * @param multipartFile * @param genchartByAiRequest * @param request * @return */ @PostMapping("/gen") public BaseResponse<BiResponse> genChartByAi(@RequestPart("file") MultipartFile multipartFile, GenchartByAiRequest genchartByAiRequest, HttpServletRequest request) { User loginUser = userService.getLoginUser(request); //限流判断 redisLimiterManager.doRateLimit("genChartByAi_" loginUser.getId(),1); String name = genchartByAiRequest.getName(); String goal = genchartByAiRequest.getGoal(); String chartType = genchartByAiRequest.getChartType(); //校验表单信息 ThrowUtils.throwIf(StringUtils.isBlank(goal), ErrorCode.PARAMS_ERROR, "目标为空"); ThrowUtils.throwIf(StringUtils.isNotBlank(name) && name.length() > 100, ErrorCode.PARAMS_ERROR, "名字过长"); //校验文件 String fileName = multipartFile.getOriginalFilename(); long fileSize = multipartFile.getSize();//单位:byte final long ONE_MB = 1 * 1024 * 1024L; if (fileSize>ONE_MB) { throw new BusinessException(ErrorCode.PARAMS_ERROR,"数据文件不能超过1MB"); } String suffix = FileUtil.getSuffix(fileName); final List<String> validfileSuffixList = Arrays.asList("png","jpg","svg","webp","jpeg","xlsx"); if (!validfileSuffixList.contains(suffix)) { throw new BusinessException(ErrorCode.PARAMS_ERROR,"文件后缀非法"); } //Long biModelId = 1659171950288818178L; //数据格式整理 StringBuffer userInput = new StringBuffer(); userInput.append("分析需求:").append("\n"); String userGoal = goal; if (StringUtils.isNotBlank(chartType)) { userGoal = ",请使用" chartType; } userInput.append(userGoal).append("\n"); userInput.append("原始数据:").append("\n"); //读取Excel文件转成csv格式 String excelToCsv = ExcelUntils.excelToCsv(multipartFile); userInput.append(excelToCsv).append("\n"); //插入数据库 Chart chart = new Chart(); chart.setName(name); chart.setGoal(goal); chart.setChartType(chartType); chart.setStatus(ChartStatusEnum.WAIT.getStatus()); chart.setChartData(excelToCsv); chart.setUserId(loginUser.getId()); boolean save = chartService.save(chart); ThrowUtils.throwIf(!save, ErrorCode.SYSTEM_ERROR, "图表保存失败"); //调用AI invokeAI(userInput, chart); BiResponse biResponse = new BiResponse(); biResponse.setChartId(chart.getId()); return ResultUtils.success(biResponse); } @Async("invokeAI") public void invokeAI(StringBuffer userInput, Chart chart) { //异步调用ai try { CompletableFuture.runAsync(()->{ //把chart状态改为执行中,running Chart updateChartResult = new Chart(); Long chartId = chart.getId(); updateChartResult.setId(chartId); updateChartResult.setStatus(ChartStatusEnum.RUNNING.getStatus()); boolean result = chartService.updateById(updateChartResult); if (!result) { handleChartUpdateError(chartId,"更新图表执行中状态失败"); return; } //调用ai DevChatResponse answer = aiManager.doChat(biModelId, userInput.toString()); String[] split = answer.getContent().split("【【【【【"); if (split.length < 3){ handleChartUpdateError(chartId,"AI生成失败"); return; } String chartCode = split[1]; String analyzeResult = split[2]; updateChartResult.setGenChart(chartCode); updateChartResult.setGenResult(analyzeResult); updateChartResult.setStatus(ChartStatusEnum.SUCCEED.getStatus()); boolean updateResult = chartService.updateById(updateChartResult); if (!updateResult) { handleChartUpdateError(chartId,"更新图表成功状态失败"); return; } },threadPoolExecutor); } catch (RejectedExecutionException e) { throw new BusinessException(ErrorCode.SYSTEM_ERROR,"系统繁忙,请稍后再试"); }catch (Exception e){ throw new BusinessException(ErrorCode.SYSTEM_ERROR); } } private void handleChartUpdateError(long chartId,String execMessage){ Chart updateChartResult = new Chart(); updateChartResult.setId(chartId); updateChartResult.setStatus(ChartStatusEnum.FAILED.getStatus()); updateChartResult.setExecMessage(execMessage); boolean result = chartService.updateById(updateChartResult); if (!result) { log.error("更新图表失败状态失败" chartId "," execMessage); } } } =================原因及解决办法=============== 原因:项目中带的AuthInterceptor拦截器中调用RequestContextHolder.currentRequestAttributes(); ,定时任务没有RequestAttributes对象,所以异常了。 解决办法:在AuthInterceptor中的RequestContextHolder.currentRequestAttributes();时捕捉异常。 参考代码: public Object doInterceptor(ProceedingJoinPoint point) throws Throwable { // 计时 StopWatch stopWatch = new StopWatch(); stopWatch.start(); // 获取请求路径 RequestAttributes requestAttributes = getRequestAttributesSafely(); // 生成请求唯一 id String requestId = UUID.randomUUID().toString(); String url = ""; String remoteHost = ""; if (requestAttributes != null) { HttpServletRequest httpServletRequest = ((ServletRequestAttributes) requestAttributes).getRequest(); url = httpServletRequest.getRequestURI(); remoteHost = httpServletRequest.getRemoteHost(); } // 获取请求参数 Object[] args = point.getArgs(); String reqParam = "[" StringUtils.join(args, ", ") "]"; // 输出请求日志 log.info("request start,id: {}, path: {}, ip: {}, params: {}", requestId, url, remoteHost, reqParam); // 执行原方法 Object result = point.proceed(); // 输出响应日志 stopWatch.stop(); long totalTimeMillis = stopWatch.getTotalTimeMillis(); log.info("request end, id: {}, cost: {}ms", requestId, totalTimeMillis); return result; } private RequestAttributes getRequestAttributesSafely() { RequestAttributes requestAttributes = null; try { requestAttributes = RequestContextHolder.currentRequestAttributes(); } catch (IllegalStateException e) { log.warn("未能获取到requestAttributes,本地调用"); } return requestAttributes; }

#提问# 问答 需求:游戏房间入座抢座位(人数满16或者已开不能进入房间) 技术栈:java、spring boot、mybatisplus、mysql 数据库表:房间表(房间人数字段最大16)、房间游戏玩家关系表 问题:抢座位涉及数据同步问题,想用房间表行锁实现人数字段 1,若发现人数大于等于16或者房间状态不是等待状态不允许加入房间并解锁,如加入成功然后添加房间玩家关系并释放锁。 不知道这样设计会不会有问题,是service层控制还是用存储过程好一些,求大神指点。

问答 java转义符\r 在命令提示符中行运行中运行 System.out.println("abcdef\r123"); 结果为 123def 在IDEA运行中运行 System.out.println("abcdef\r123"); 结果为 123 这是为什么?

提问 问答 鱼泡项目使用vant,在调用Toast组件时只能,触发时只能显示内容,黑色半透框无法显示,如何解决

#问答# #提问# 《从0到1开发用户中心(终)》2:17:00左右引入了ProFrom后就无法正常访问页面了,尝试重新导包无效

#自我介绍# 大家好,我是一个没有正儿八经参与过项目的java程序员。入行就进入国企工作,没有团队,公司项目全凭自个摸索。经历三年还是觉得技术上欠缺很多,希望得到技术的提升运用和正经八百的项目经验。

下载 APP