SpringAI RAG MCP Agent,AI 智能体企业级实战(25年必学 - 3 - AI 应用开发 笔记

已实现 敏感词替换 Advisor,此时效果见图片,代码见末尾

image.png

java
复制代码
@Slf4j public class ProhibitedWordCheckAdvisor implements CallAroundAdvisor, StreamAroundAdvisor { @Resource private SensitiveWordHelper sensitiveWordHelper; @Override public String getName() { return this.getClass().getSimpleName(); } @Override public int getOrder() { return 0; } private AdvisedRequest before(AdvisedRequest request) { String userText = request.userText(); boolean hasSensitive = SensitiveWordHelper.contains(userText); if (hasSensitive) { List<String> sensitiveWords = SensitiveWordHelper.findAll(userText); // 1. 对每个敏感词单独脱敏,再组成新列表 List<String> maskedSensitiveWords = sensitiveWords.stream() .map(this::maskText) // 调用之前的maskText方法,每个词单独脱敏 .collect(Collectors.toList()); // 2. 打印脱敏后的敏感词列表 log.warn("Content contains {} sensitive words, will be replaced. Sensitive words (masked): {}", sensitiveWords.size(), // 第一个{}:敏感词总数 maskedSensitiveWords); // 第二个{}:脱敏后的敏感词列表 // 3. 替换敏感词并二次验证 - 直接替换成“*” userText = SensitiveWordHelper.replace(userText); if (sensitiveWordHelper.contains(userText)) { userText = SensitiveWordHelper.replace(userText, '*'); log.error("Sensitive words not completely replaced! "); // 日志首尾脱敏 } } // 仅在文本有修改时才创建新请求(优化性能) if (!userText.equals(request.userText())) { return AdvisedRequest.from(request) .userText(userText) .build(); } return request; // 文本未修改时返回原始请求 } // 辅助方法:对敏感词进行脱敏处理 // 两个字:显示第一个字,第二个字用*代替 // 大于两个字:保留首尾两个字,中间用*代替 private String maskText(String text) { // 空字符串直接返回 if (text == null || text.isEmpty()) { return text; } int length = text.length(); if (length <= 1) { return "*"; } // 处理两个字的情况:只保留第一个字 if (length == 2) { return text.charAt(0) + "*"; } // 处理大于两个字的情况:保留首尾,中间用*代替 return text.charAt(0) + "*".repeat(length - 2) + text.charAt(length - 1); } @Override public AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) { return chain.nextAroundCall(this.before(advisedRequest)); } @Override public Flux<AdvisedResponse> aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) { return chain.nextAroundStream(this.before(advisedRequest)); } }
0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
路哲萧笑
作者分享
有没有人记得鱼皮之前分享过一个Skill,可以让模型自己去看框架的官方文档,根据文档写代码……我找不到这个Skill,有人可以分享一下不~
1
求助:MCP - 使用过sse传递环境变量,显示无法调用搜图。但 stdio模式下已验证可行…… ```java package com.lzxx.lzxximagesearchmcpserver.tools; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ai.tool.annotation.Tool; import org.springframework.ai.tool.annotation.ToolParam; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Service public class ImageSearchTool { // 替换为你的 Pexels API 密钥(需从官网申请) private static final String API_KEY = "dsd"; // Pexels 常规搜索接口(请以文档为准) private static final String API_URL = "https://api.pexels.com/v1/search"; // 从环境变量读取图片数量限制,默认返回5张 private static final int DEFAULT_LIMIT = 5; // Pexels API 最大支持80张/页 private static final int MAX_LIMIT = 80; @Tool(description = "search image from web, return specified number of images controlled by environment variable IMAGE_SEARCH_LIMIT") public String searchImage(@ToolParam(description = "Search query keyword") String query) { try { int finalLimit = determineFinalLimit(); return String.join(",", searchMediumImages(query, finalLimit)); } catch (Exception e) { return "Error search image: " + e.getMessage(); } } // 确定最终使用的数量(优先级处理) private int determineFinalLimit() { // 1. 读取环境变量(区分大小写,Linux/macOS 环境变量通常为大写) String limitStr = System.getenv("IMAGE_SEARCH_LIMIT"); int limit = Integer.parseInt(limitStr); // 2. 完整的校验逻辑 if (StrUtil.isBlank(limitStr)) { limit = DEFAULT_LIMIT; } else if (!limitStr.matches("\\d+")) { limit = DEFAULT_LIMIT; } else if (limit <= 0 || limit > MAX_LIMIT) { limit = DEFAULT_LIMIT; } return limit; } /** * 搜索中等尺寸的图片列表 * * @param query * @return */ public List<String> searchMediumImages(String query, int limit) { // 设置请求头(包含API密钥) Map<String, String> headers = new HashMap<>(); headers.put("Authorization", API_KEY); // 设置请求参数(仅包含query,可根据文档补充page、per_page等参数) Map<String, Object> params = new HashMap<>(); params.put("query", query); params.put("per_page", limit); // 添加数量控制参数:从环境变量读取的限制值 // 发送 GET 请求 String response = HttpUtil.createGet(API_URL) .addHeaders(headers) .form(params) .execute() .body(); // 解析响应JSON(假设响应结构包含"photos"数组,每个元素包含"medium"字段) return JSONUtil.parseObj(response) .getJSONArray("photos") .stream() .map(photoObj -> (JSONObject) photoObj) .map(photoObj -> photoObj.getJSONObject("src")) .map(photo -> photo.getStr("medium")) .filter(StrUtil::isNotBlank) .collect(Collectors.toList()); } } ``` ```json { "mcpServers": { " lzxx-image-search-mcp-server": { "command": "java", "args": [ "-Dspring.ai.mcp.server.stdio=true", "-Dspring.main.web-application-type=none", "-Dlogging.pattern.console=", "-jar", "lzxx-image-search-mcp-server/target/lzxx-image-search-mcp-server-0.0.1-SNAPSHOT.jar" ], "env": {"IMAGE_SEARCH_LIMIT": "3"} } } } ```
1
超级智能体项目的 AI大模型接入 模块,如何使用 SpringAI框架 API 方式接入 doubao大模型? 豆包大模型是支持openAI协议的,所以我按照文档使用了 类open AI的方式接入,但一直无法编译通过。 (附报错图、yml图、代码图) 麻烦解决的朋友给我评论留言,感谢!(ps sdk和http方式不会的可以找我,那两种方式都成功接入了大模型)
2
项目 求一个 go版本 的oj项目。最近刚刚过了一遍语法,想看看项目中的go是咋用的
4
项目 关于【sdk上传maven中央仓库】的提问 我根据b站某球友的视频和博客顺利完成了前期的所有准备,包括:注册jira与提一个new project;弄一个gpg密钥;修改setting;修改pom。步骤与修改的细节我都检查了好几次,确认没问题(跟博客几乎一样,除了基本信息),但是就是无法部署工程,说没权限啥的。 希望解决过的朋友q我一下,如果能远程帮我看看的话,感激不尽了[抱拳][抱拳][抱拳]弄了好久,很崩溃的说[流泪][流泪][流泪]
6
下载 APP