SpringAI RAG MCP Agent,AI 超级智能体企业级实战(25 年必学) - 5 - RAG 知识库进阶 笔记
功能需求:自定义QueryTransformer查询转换器,将用户提示词翻译后进行提问
实现思路:
- 寻找合适的翻译API(最终确定使用阿里云的翻译)
- 实现自定义QueryTransFormer(翻译API调用代码去实现public Query transform(Query query)方法)
- 将自定义QueryTransFormer注入RetrievalAugmentationAdvsior中实现翻译用户提示词
开发过程中遇到的问题:
API翻译成功,RetrievalAugmentationAdvsior中也成功调用了自定义QueryTransFormer,但是最终的用户提示词中还是未翻译的提问。
发生问题的原因:
RetrievalAugmentationAdvsior中QueryTransFormer翻译后的提示词只会用作文档检索,对AI模型进行提问时还是用原始的提示词,导致翻译失效


解决方法:
由于RetrievalAugmentationAdvsior是final类无法继承,只能通过RetrievalAugmentationAdvsior源码去重构 before方法

评论
问答助学
相关内容
0个评论
全部评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
内容推荐
AI 超级智能体 - 基于mysql的消息存储
4
SpringAl+RAG+MCP全栈|AI超级智能体企业级实战项目中:stdio连接方式调用MCP服务问题运行测试时解决:1. 先查看MCP server那的yml文件,文件名有没有写错2. 修改server端的"application-stdio.yml",把每一个报错发给deepseek再验证之后,得出结论:Server 的 stdout 完全被污染了:Spring Boot Banner 完
3
SpringAI + RAG + MCP 全栈 | AI 超级智能体企业级实战(26年必学) - 第三期:基础内容 笔记
3
AI超级智能体项目_踩坑记录_PGVector维度冲突
2
Code Log-AI超级智能体项目,开发日志。SpringAI + RAG + MCP 全栈 | AI 超级智能体企业级实战(26年必学)
2
作者分享
提问 项目
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;
}
11
#提问# 问答
需求:游戏房间入座抢座位(人数满16或者已开不能进入房间)
技术栈:java、spring boot、mybatisplus、mysql
数据库表:房间表(房间人数字段最大16)、房间游戏玩家关系表
问题:抢座位涉及数据同步问题,想用房间表行锁实现人数字段 1,若发现人数大于等于16或者房间状态不是等待状态不允许加入房间并解锁,如加入成功然后添加房间玩家关系并释放锁。
不知道这样设计会不会有问题,是service层控制还是用存储过程好一些,求大神指点。
11
问答 java转义符\r
在命令提示符中行运行中运行 System.out.println("abcdef\r123"); 结果为 123def
在IDEA运行中运行 System.out.println("abcdef\r123"); 结果为 123
这是为什么?
5
提问 问答 鱼泡项目使用vant,在调用Toast组件时只能,触发时只能显示内容,黑色半透框无法显示,如何解决
9
#问答# #提问# 《从0到1开发用户中心(终)》2:17:00左右引入了ProFrom后就无法正常访问页面了,尝试重新导包无效
7

