2.1 整体架构
应用业务层
↓
Spring AI抽象层 (ChatModel, ImageModel等)
↓
提供商适配层 (OpenAI, Ollama, Vertex AI等)
↓
具体AI服务 (GPT-4, LLaMA, Gemini等)
2.2 核心组件
ChatModel: 对话模型接口,支持文本和多模态对话
ImageModel: 图像生成模型接口
EmbeddingModel: 向量嵌入模型接口
Prompt: 提示词封装,支持模板和参数
ChatOptions: 模型参数配置(温度、最大token等)
Message: 消息抽象,支持用户、系统、助手消息
2.3 Spring AI新增注解详解
Spring AI引入了一系列专门的注解来简化AI功能的集成,这些注解大大减少了样板代码,提供了声明式的AI编程体验。
2.3.1 核心注解概览
@EnableAI: 启用Spring AI自动配置和功能
@AIFunction: 标记可被AI模型调用的函数(Function Calling)
@AIPrompt: 定义AI提示词模板,支持参数化
@AIModel: 指定特定的AI模型或配置
@AIRetry: 配置AI调用的重试策略和故障恢复
@AIParameter: 定义AI函数参数的描述和约束
@AICache: 配置AI响应的缓存策略
@AIRateLimit: 配置AI调用的速率限制
2.3.2 @EnableAI 注解详解
作用: 启用Spring AI的自动配置功能,类似于@EnableAutoConfiguration
使用场景:
在主配置类上启用Spring AI功能
自动扫描和注册AI相关的Bean
启用AI函数调用和提示词模板功能
基础使用场景: 启动一个支持AI功能的Spring Boot应用
@SpringBootApplication // 标准的Spring Boot应用启动注解
@EnableAI // 【关键】启用Spring AI自动配置,这会:
// 1. 自动扫描@AIFunction标记的方法
// 2. 注册AI相关的Bean(ChatModel、EmbeddingModel等)
// 3. 启用提示词模板功能
// 4. 配置AI函数调用机制
public class AIApplication {
public static void main(String[] args) {
// 启动Spring Boot应用,AI功能将自动可用
SpringApplication.run(AIApplication.class, args);
}
}
/*
期望效果:
- 应用启动后,所有@AIFunction方法可被AI模型调用
- ChatModel等AI相关Bean自动注入可用
- 提示词模板自动解析和注册
- AI调用的监控和日志功能启用
*/
高级配置场景: 企业级应用中精确控制AI功能的启用范围和行为
@Configuration // 标记为Spring配置类
@EnableAI(
// 【扫描范围】指定扫描AI功能的包路径,避免全局扫描影响性能
scanBasePackages = {“com.example.ai.functions”, “com.example.ai.prompts”},
// 【功能开关】启用函数调用功能,AI可以调用@AIFunction标记的方法
enableFunctionCalling = true,
// 【模板功能】启用提示词模板功能,支持@AIPrompt注解
enablePromptTemplates = true,
// 【自动重试】启用全局自动重试功能,失败时自动重试
enableAutoRetry = true
)
public class AIConfiguration {
/**
* 配置AI的全局默认属性
* 目的:为所有AI调用提供统一的默认配置
*/
@Bean
public AIConfigurationProperties aiProperties() {
AIConfigurationProperties properties = new AIConfigurationProperties();
// 设置默认使用的AI模型(百炼平台的多模态模型)
properties.setDefaultModel("qwen-vl-plus");
// 设置默认温度参数,0.1表示输出更加确定性,适合业务场景
properties.setDefaultTemperature(0.1f);
// 设置默认最大token数,控制响应长度和成本
properties.setDefaultMaxTokens(2048);
// 设置默认超时时间,防止长时间等待
properties.setDefaultTimeout(Duration.ofSeconds(30));
return properties;
}
/**
* 配置AI调用的全局监控
* 目的:统一收集AI调用的性能指标和使用统计
*/
@Bean
public AIMetricsCollector aiMetricsCollector() {
return new AIMetricsCollector();
}
}
/*
期望效果:
- 只扫描指定包下的AI功能,提高启动速度
- 所有AI调用默认使用qwen-vl-plus模型
- 失败的AI调用会自动重试
- 提供统一的性能监控和指标收集
- 可以通过配置文件覆盖这些默认设置
*/
2.3.3 @AIFunction 注解详解
作用: 标记方法为AI可调用的函数,支持Function Calling功能
核心属性:
name: 函数名称(默认使用方法名)
description: 函数功能描述(AI模型用于理解函数用途)
parameters: 参数描述数组
returnDescription: 返回值描述
examples: 使用示例
基础使用场景: 智能客服机器人需要回答用户关于天气的询问
/**
-
天气服务类 - 为AI模型提供天气查询功能
-
业务场景:当用户问"北京今天天气怎么样?"时,AI模型会自动调用这个函数
-
期望输出:返回包含温度、天气状况、湿度等信息的结构化数据
*/
@Component
public class WeatherService {@Autowired
private WeatherAPI weatherAPI; // 注入第三方天气API服务/**
-
AI可调用函数:获取指定城市的当前天气信息
-
@AIFunction 注解告诉Spring AI这个方法可以被AI模型调用
-
- description: AI模型用这个描述来理解函数的用途
-
- 当AI模型判断用户询问天气时,会自动调用此函数
-
@param city 城市名称,由AI模型从用户输入中提取
-
@return WeatherInfo 包含完整天气信息的对象
*/
@AIFunction(description = “获取指定城市的当前天气信息,包括温度、天气状况、湿度、风速等”)
public WeatherInfo getCurrentWeather(@AIParameter(“城市名称,如:北京、上海、深圳”) String city) {
try {
// 调用第三方天气API获取实时天气数据
WeatherInfo weather = weatherAPI.getWeather(city);// 记录日志,便于调试和监控 log.info("成功获取{}的天气信息: 温度{}°C, 天气{}", city, weather.getTemperature(), weather.getCondition()); return weather;} catch (Exception e) {
// 异常处理:如果天气API调用失败,返回默认信息
log.error(“获取{}天气信息失败: {}”, city, e.getMessage());// 返回一个包含错误信息的WeatherInfo对象 return WeatherInfo.builder() .city(city) .condition("暂时无法获取天气信息") .temperature(null) .error("天气服务暂时不可用,请稍后重试") .build();}
}
}
-
/**
-
天气信息数据模型
-
这个类定义了天气信息的结构,AI模型会将这个对象转换为自然语言回复给用户
*/
@Data
@Builder
public class WeatherInfo {
private String city; // 城市名称
private String condition; // 天气状况:晴天、多云、雨天等
private Integer temperature; // 温度(摄氏度)
private Integer humidity; // 湿度百分比
private String windSpeed; // 风速
private String airQuality; // 空气质量
private String error; // 错误信息(如果有的话)/**
-
将天气信息转换为用户友好的文本描述
-
AI模型会使用这个方法生成最终回复
*/
@Override
public String toString() {
if (error != null) {
return String.format(“%s:%s”, city, error);
}return String.format(“%s今天%s,温度%d°C,湿度%d%%,风速%s,空气质量%s”,
city, condition, temperature, humidity, windSpeed, airQuality);
}
}
-
/**
- 使用示例:AI对话流程
-
- 用户输入:“北京今天天气怎么样?”
-
- AI模型分析用户意图,识别出这是天气查询请求
-
- AI模型自动调用 getCurrentWeather(“北京”) 函数
-
- 函数返回 WeatherInfo 对象
-
- AI模型将结果转换为自然语言:“北京今天晴天,温度25°C,湿度60%,风速微风,空气质量良好”
-
- 返回给用户最终回复
*/
高级使用场景: 企业级CRM系统的AI助手,需要处理复杂的客户查询和业务计算
- 返回给用户最终回复
/**
-
企业业务功能服务类 - 为AI模型提供复杂的业务操作能力
-
业务场景:
-
- 客服人员询问:“帮我找一下姓张的VIP客户”
-
- HR询问:“2024年1月1日到3月31日有多少个工作日?”
-
- 销售询问:“客户编号CUST001的详细信息”
-
期望输出:
-
- 返回符合条件的客户列表,包含完整的客户信息
-
- 返回精确的工作日计算结果
-
- 提供结构化的业务数据供AI模型理解和回复
*/
@Component
@Slf4j
public class BusinessFunctionService {
@Autowired
private CustomerService customerService; // 客户服务@Autowired
private WorkingDayCalculator workingDayCalculator; // 工作日计算器@Autowired
private HolidayService holidayService; // 节假日服务/**
-
AI可调用函数:智能客户搜索
-
功能说明:
-
- 支持按姓名、电话、客户ID等多种方式搜索
-
- 支持模糊匹配,提高搜索成功率
-
- 可限制返回结果数量,避免信息过载
-
AI调用场景:
-
- “帮我找一下张三的信息” -> search_customer(“张三”, 10)
-
- “查询电话138开头的客户” -> search_customer(“138”, 5)
-
- “客户编号CUST001的信息” -> search_customer(“CUST001”, 1)
*/
@AIFunction(
name = “search_customer”,
description = “智能搜索客户信息,支持按姓名、电话、客户ID等多种方式查询,支持模糊匹配”,
parameters = {
@AIParameter(
name = “query”,
description = “搜索关键词,可以是客户姓名、电话号码、客户ID或邮箱地址”,
required = true,
type = “string”,
examples = {“张三”, “13800138000”, “CUST001”, “zhang@example.com”}
),
@AIParameter(
name = “limit”,
description = “返回结果的最大数量,默认10条,最多50条”,
required = false,
type = “integer”,
defaultValue = “10”
)
},
returnDescription = “返回匹配的客户信息列表,每个客户包含:ID、姓名、电话、邮箱、等级、注册时间等”,
examples = {
“搜索姓名包含’张’的客户:search_customer(‘张’, 5)”,
“搜索特定客户:search_customer(‘CUST001’, 1)”,
“搜索电话号码:search_customer(‘138’, 10)”
}
)
public List searchCustomer(String query, Integer limit) {
// 参数验证和默认值处理
if (query == null || query.trim().isEmpty()) {
log.warn(“客户搜索查询参数为空”);
return Collections.emptyList();
}
// 限制返回结果数量,防止数据过载
int actualLimit = (limit != null && limit > 0) ? Math.min(limit, 50) : 10;try {
// 记录搜索请求,用于业务分析
log.info(“AI请求搜索客户: query=‘{}’, limit={}”, query, actualLimit);// 调用业务服务进行智能搜索 // 支持多字段模糊匹配:姓名、电话、邮箱、客户ID List<Customer> customers = customerService.intelligentSearch(query, actualLimit); // 记录搜索结果统计 log.info("客户搜索完成: 查询'{}', 返回{}条结果", query, customers.size()); // 为AI模型添加搜索上下文信息 customers.forEach(customer -> { customer.setSearchContext(String.format("匹配关键词: %s", query)); customer.setLastAccessTime(LocalDateTime.now()); }); return customers;} catch (Exception e) {
// 异常处理:记录错误并返回空结果
log.error(“客户搜索失败: query=‘{}’, error={}”, query, e.getMessage(), e);
return Collections.emptyList();
}
} - “客户编号CUST001的信息” -> search_customer(“CUST001”, 1)
/**
-
AI可调用函数:工作日计算器
-
功能说明:
-
- 精确计算两个日期之间的工作日天数
-
- 自动排除周末(周六、周日)
-
- 可选择是否排除法定节假日
-
- 支持跨年度计算
-
AI调用场景:
-
- “2024年1月1日到3月31日有多少工作日?” -> calculateWorkingDays(“2024-01-01”, “2024-03-31”, true)
-
- “这个月有几个工作日?” -> AI会自动计算当月第一天和最后一天
-
-
“项目从下周一开始,持续20个工作日,什么时候结束?” -> 结合日期计算
*/
@AIFunction(
description = “计算两个日期之间的工作日天数,自动排除周末,可选择排除法定节假日”,
parameters = {
@AIParameter(
name = “startDate”,
description = “开始日期,格式:YYYY-MM-DD,如:2024-01-01”,
required = true,
type = “string”,
examples = {“2024-01-01”, “2024-03-15”, “2024-12-31”}
),
@AIParameter(
name = “endDate”,
description = “结束日期,格式:YYYY-MM-DD,必须大于等于开始日期”,
required = true,
type = “string”,
examples = {“2024-01-31”, “2024-03-31”, “2024-12-31”}
),
@AIParameter(
name = “excludeHolidays”,
description = “是否排除法定节假日(春节、国庆等),默认true”,
required = false,
type = “boolean”,
defaultValue = “true”
)
},
returnDescription = “返回工作日天数(整数),不包括周末,根据参数决定是否包括节假日”
)
public WorkingDayResult calculateWorkingDays(String startDate, String endDate, Boolean excludeHolidays) {
try {
// 日期格式验证和解析
LocalDate start = LocalDate.parse(startDate);
LocalDate end = LocalDate.parse(endDate);// 日期逻辑验证
if (end.isBefore(start)) {
log.warn(“结束日期早于开始日期: start={}, end={}”, startDate, endDate);
return WorkingDayResult.error(“结束日期不能早于开始日期”);
}// 默认排除节假日
boolean shouldExcludeHolidays = excludeHolidays != null ? excludeHolidays : true;log.info(“开始计算工作日: {} 到 {}, 排除节假日: {}”, startDate, endDate, shouldExcludeHolidays);
// 调用工作日计算器进行精确计算
int workingDays = workingDayCalculator.calculate(start, end, shouldExcludeHolidays);// 获取详细的日期分析信息
DateAnalysis analysis = analyzeDateRange(start, end, shouldExcludeHolidays);// 构建详细的返回结果
WorkingDayResult result = WorkingDayResult.builder()
.workingDays(workingDays)
.totalDays(ChronoUnit.DAYS.between(start, end) + 1)
.weekends(analysis.getWeekends())
.holidays(analysis.getHolidays())
.startDate(startDate)
.endDate(endDate)
.excludeHolidays(shouldExcludeHolidays)
.calculationTime(LocalDateTime.now())
.build();log.info(“工作日计算完成: {}天工作日 (总共{}天, 周末{}天, 节假日{}天)”,
workingDays, result.getTotalDays(), analysis.getWeekends(), analysis.getHolidays());return result;
} catch (DateTimeParseException e) {
// 日期格式错误处理
log.error(“日期格式错误: start={}, end={}, error={}”, startDate, endDate, e.getMessage());
return WorkingDayResult.error(“日期格式错误,请使用YYYY-MM-DD格式,如:2024-01-01”);} catch (Exception e) {
// 其他异常处理
log.error(“工作日计算失败: start={}, end={}, error={}”, startDate, endDate, e.getMessage(), e);
return WorkingDayResult.error(“计算失败:” + e.getMessage());
}
} -
/**
-
私有方法:分析日期范围内的详细信息
-
用于提供更丰富的计算结果
*/
private DateAnalysis analyzeDateRange(LocalDate start, LocalDate end, boolean excludeHolidays) {
int weekends = 0;
int holidays = 0;// 遍历日期范围,统计周末和节假日
LocalDate current = start;
while (!current.isAfter(end)) {
// 统计周末
if (current.getDayOfWeek() == DayOfWeek.SATURDAY ||
current.getDayOfWeek() == DayOfWeek.SUNDAY) {
weekends++;
}// 统计节假日(如果需要排除的话) if (excludeHolidays && holidayService.isHoliday(current)) { holidays++; } current = current.plusDays(1);}
return DateAnalysis.builder()
.weekends(weekends)
.holidays(holidays)
.build();
}
}
- 提供结构化的业务数据供AI模型理解和回复
/**
-
工作日计算结果数据模型
-
包含详细的计算信息,便于AI模型生成准确的回复
*/
@Data
@Builder
public class WorkingDayResult {
private int workingDays; // 工作日天数
private long totalDays; // 总天数
private int weekends; // 周末天数
private int holidays; // 节假日天数
private String startDate; // 开始日期
private String endDate; // 结束日期
private boolean excludeHolidays; // 是否排除节假日
private LocalDateTime calculationTime; // 计算时间
private String error; // 错误信息/**
- 创建错误结果
*/
public static WorkingDayResult error(String errorMessage) {
return WorkingDayResult.builder()
.error(errorMessage)
.calculationTime(LocalDateTime.now())
.build();
}
/**
-
转换为用户友好的描述
-
AI模型会使用这个方法生成最终回复
*/
@Override
public String toString() {
if (error != null) {
return “计算失败:” + error;
}StringBuilder result = new StringBuilder();
result.append(String.format(“从%s到%s,”, startDate, endDate));
result.append(String.format(“总共%d天,”, totalDays));
result.append(String.format(“工作日%d天”, workingDays));if (weekends > 0) {
result.append(String.format(“(排除%d天周末”, weekends));
if (excludeHolidays && holidays > 0) {
result.append(String.format(“和%d天节假日”, holidays));
}
result.append(“)”);
}return result.toString();
}
}
- 创建错误结果
/**
- 日期分析辅助类
*/
@Data
@Builder
private static class DateAnalysis {
private int weekends; // 周末天数
private int holidays; // 节假日天数
}
/**
- 完整的使用示例:AI对话流程
- 场景1:客户查询
- 用户:“帮我找一下张经理的联系方式”
- AI分析:识别为客户搜索请求
- AI调用:searchCustomer(“张经理”, 10)
- 返回结果:[Customer{name=“张经理”, phone=“138…”, email=“zhang@…”}]
- AI回复:“找到张经理的信息:电话138…, 邮箱zhang@…, 客户等级VIP”
- 场景2:工作日计算
- 用户:“这个季度有多少个工作日?”
- AI分析:识别为工作日计算请求,自动确定季度开始和结束日期
- AI调用:calculateWorkingDays(“2024-01-01”, “2024-03-31”, true)
- 返回结果:WorkingDayResult{workingDays=65, totalDays=91, weekends=26, holidays=7}
- AI回复:“2024年第一季度从1月1日到3月31日,总共91天,工作日65天(排除26天周末和7天节假日)”
*/
函数调用流程:
@Service
public class AIAssistantService {
@Autowired
private ChatModel chatModel;
public String handleUserQuery(String userMessage) {
// AI模型会自动识别是否需要调用函数
// 如果用户问"北京今天天气怎么样?"
// AI会自动调用 getCurrentWeather("北京") 函数
UserMessage message = new UserMessage(userMessage);
ChatResponse response = chatModel.call(new Prompt(message));
return response.getResult().getOutput().getContent();
}
}
2.3.4 @AIPrompt 注解详解
作用: 定义可重用的提示词模板,支持参数化和条件逻辑
核心属性:
value: 提示词模板内容
name: 模板名称
variables: 模板变量定义
conditions: 条件逻辑
examples: 使用示例
基础使用场景: 内容管理系统需要自动分析用户评论的情感倾向和多语言翻译
/**
-
文本分析服务类 - 使用AI提示词模板进行文本处理
-
业务场景:
-
- 电商平台需要分析用户评论的情感倾向(正面/负面/中性)
-
- 国际化应用需要将内容翻译成不同语言
-
- 内容审核系统需要快速判断文本的情感色彩
-
期望输出:
-
- 情感分析:返回"positive"、“negative"或"neutral”
-
- 文本翻译:返回目标语言的翻译结果
*/
@Component
@Slf4j
public class TextAnalysisService {
/**
-
AI提示词模板:情感分析
-
模板说明:
-
- {text} 是参数占位符,会被实际的文本内容替换
-
- 提示词要求AI返回标准化的结果:positive/negative/neutral
-
- 简洁明确的指令有助于提高AI响应的准确性
-
使用场景:
-
- 用户评论:“这个产品真的很棒!” -> “positive”
-
- 客服反馈:“服务态度很差” -> “negative”
-
- 中性描述:“产品是蓝色的” -> “neutral”
*/
@AIPrompt(“请分析以下文本的情感倾向,只返回positive、negative或neutral中的一个:\n\n{text}”)
public String analyzeSentiment(String text) {
// 方法体为空,Spring AI会自动:
// 1. 将参数text替换到提示词模板中的{text}占位符
// 2. 将完整的提示词发送给AI模型
// 3. 返回AI模型的响应结果
log.info(“执行情感分析,文本长度: {} 字符”, text != null ? text.length() : 0);
return null; // 由Spring AI自动填充返回值
} - 中性描述:“产品是蓝色的” -> “neutral”
/**
-
AI提示词模板:多语言翻译
-
模板说明:
-
- {targetLanguage} 目标语言参数,如"英语"、“日语”、“法语”
-
- {text} 待翻译的文本内容
-
- 参数顺序与方法参数顺序对应
-
使用场景:
-
- translateText(“你好世界”, “英语”) -> “Hello World”
-
- translateText(“Thank you”, “中文”) -> “谢谢”
-
- translateText(“Bonjour”, “中文”) -> “你好”
*/
@AIPrompt(“将以下文本翻译成{targetLanguage},保持原文的语气和风格:\n\n{text}”)
public String translateText(String text, String targetLanguage) {
// 参数映射说明:
// - 第一个参数text对应模板中的{text}
// - 第二个参数targetLanguage对应模板中的{targetLanguage}
log.info(“执行文本翻译: {} -> {}, 文本长度: {}”,
detectLanguage(text), targetLanguage, text != null ? text.length() : 0);
return null; // 由Spring AI自动处理
} - translateText(“Bonjour”, “中文”) -> “你好”
/**
-
辅助方法:简单的语言检测
-
用于日志记录,不是AI功能的一部分
*/
private String detectLanguage(String text) {
if (text == null || text.isEmpty()) return “未知”;// 简单的中文检测
if (text.matches(“.[\u4e00-\u9fa5].”)) {
return “中文”;
}
// 简单的英文检测
if (text.matches(“.[a-zA-Z].”)) {
return “英文”;
}
return “其他”;
}
}
- 文本翻译:返回目标语言的翻译结果
/**
-
使用示例:完整的业务流程
-
场景1:电商评论分析
*/
@RestController
public class ReviewController {@Autowired
private TextAnalysisService textAnalysisService;@PostMapping(“/reviews/analyze”)
public ReviewAnalysisResult analyzeReview(@RequestBody String reviewText) {
// 1. 调用情感分析
String sentiment = textAnalysisService.analyzeSentiment(reviewText);// 2. 根据情感分析结果进行业务处理 ReviewAnalysisResult result = new ReviewAnalysisResult(); result.setOriginalText(reviewText); result.setSentiment(sentiment); result.setNeedsAttention("negative".equals(sentiment)); return result;}
}
// 场景2:国际化内容翻译
@Service
public class ContentService {
@Autowired
private TextAnalysisService textAnalysisService;
public void publishMultilingualContent(String content) {
// 翻译成多种语言
String englishVersion = textAnalysisService.translateText(content, "英语");
String japaneseVersion = textAnalysisService.translateText(content, "日语");
String frenchVersion = textAnalysisService.translateText(content, "法语");
// 保存多语言版本
saveContent("en", englishVersion);
saveContent("ja", japaneseVersion);
saveContent("fr", frenchVersion);
}
}
/**
- 预期输出示例:
- 情感分析:
- 输入:“这个产品质量很好,我很满意!”
- 输出:“positive”
- 输入:“发货太慢了,很不满意”
- 输出:“negative”
- 输入:“产品是红色的,包装完整”
- 输出:“neutral”
- 文本翻译:
- 输入:translateText(“你好,欢迎使用我们的服务”, “英语”)
- 输出:“Hello, welcome to use our service”
- 输入:translateText(“Thank you for your feedback”, “中文”)
- 输出:“感谢您的反馈”
*/
高级模板使用场景: 企业内容管理系统,需要根据不同需求自动生成专业文章
/**
-
内容生成服务 - 使用高级AI提示词模板
-
业务场景:
-
- 企业官网需要定期发布行业文章
-
- 营销部门需要快速生成产品文案
-
- 内容团队需要批量创作不同风格的文章
-
- SEO团队需要优化搜索引擎友好的内容
*/
@Component
@Slf4j
public class ContentGenerationService {
/**
-
高级文章生成模板
-
模板特点:
-
- 支持多个参数的复杂组合
-
- 使用条件逻辑 {#if} 根据参数动态调整提示词
-
- 定义了变量的默认值和描述
-
- 支持专业领域的定制化内容生成
-
使用场景示例:
-
- 科技博客文章:domain=“人工智能”, topic=“ChatGPT的商业应用”
-
- 健康科普文章:domain=“医疗健康”, topic=“如何预防感冒”
-
-
金融分析文章:domain=“金融投资”, topic=“2024年股市展望”
*/
@AIPrompt(
name = “article_writer”, // 模板名称,便于管理和复用
value = “”"
你是一个专业的{domain}领域内容创作者。请根据以下要求创作一篇文章:主题:{topic}
目标受众:{audience}
文章长度:{length}字左右
写作风格:{style}{#if includeImages}
请在适当位置标注需要插入图片的地方,用[图片:描述]的格式。
{/if}{#if includeSEO}
请确保文章SEO友好,包含相关关键词:{keywords}
{/if}要求:
- 内容原创,有深度和价值
- 结构清晰,逻辑性强
- 语言流畅,符合{audience}的阅读习惯
- 包含实用的建议或见解
“”",
variables = {
// 必需参数:专业领域
@AIVariable(name = “domain”, description = “专业领域,如:人工智能、医疗健康、金融投资”, required = true),
// 必需参数:文章主题
@AIVariable(name = “topic”, description = “文章主题,具体明确的标题”, required = true),
// 可选参数:目标受众,有默认值
@AIVariable(name = “audience”, description = “目标受众群体”, defaultValue = “普通读者”),
// 可选参数:文章长度,有默认值
@AIVariable(name = “length”, description = “文章字数”, defaultValue = “1000”),
// 可选参数:写作风格,有默认值
@AIVariable(name = “style”, description = “写作风格”, defaultValue = “专业但易懂”)
}
)
public String generateArticle(String domain, String topic, String audience,
Integer length, String style, Boolean includeImages,
Boolean includeSEO, String keywords) {
// 【参数验证】确保必需参数不为空
if (domain == null || domain.trim().isEmpty()) {
throw new IllegalArgumentException(“专业领域不能为空”);
}
if (topic == null || topic.trim().isEmpty()) {
throw new IllegalArgumentException(“文章主题不能为空”);
}// 【参数标准化】设置默认值
audience = audience != null ? audience : “普通读者”;
length = length != null ? length : 1000;
style = style != null ? style : “专业但易懂”;
includeImages = includeImages != null ? includeImages : false;
includeSEO = includeSEO != null ? includeSEO : false;// 【日志记录】记录文章生成请求
log.info(“开始生成文章: 领域={}, 主题={}, 受众={}, 长度={}字, 风格={}, 包含图片={}, SEO优化={}”,
domain, topic, audience, length, style, includeImages, includeSEO);// 【条件处理】如果需要SEO优化但没有提供关键词,给出提示
if (includeSEO && (keywords == null || keywords.trim().isEmpty())) {
log.warn(“启用了SEO优化但未提供关键词,可能影响SEO效果”);
}return null; // 由Spring AI自动处理模板替换和AI调用
}
} -
/**
- 营销文案生成模板
- 业务场景:
-
- 电商平台需要为新产品快速生成吸引人的文案
-
- 营销团队需要针对不同客户群体定制文案
-
- 广告投放需要多个版本的文案进行A/B测试
- 模板特点:
-
- 结构化的产品信息输入
-
- 针对特定客户群体的个性化文案
-
- 可控制的文案长度和风格
-
- 包含使用示例,便于理解
- 期望输出示例:
- 输入:智能手表, 可穿戴设备, 健康监测+长续航, 健身爱好者, 1000-2000元, 150字, 活力激情
- 输出: ♂️ 专为健身达人打造!这款智能手表不仅能24小时监测你的心率、步数和睡眠质量,
-
更有7天超长续航,让你专注训练无后顾之忧!仅需1000-2000元,就能拥有专业级健康管家。 -
现在下单立享9折优惠,开启你的智能健身之旅!
*/
@AIPrompt(
value = “”"
基于以下产品信息,生成一个吸引人的营销文案:产品名称:{productName} 产品类型:{productType} 主要特点:{features} 目标客户:{targetCustomer} 价格区间:{priceRange} 文案要求: 1. 突出产品核心价值,让{targetCustomer}一眼看出产品对他们的好处 2. 针对{targetCustomer}的具体需求和痛点,使用他们熟悉的语言 3. 包含明确的行动号召,引导用户采取行动 4. 长度严格控制在{maxLength}字以内,简洁有力 5. 风格:{tone},符合目标客户的喜好 6. 可以适当使用emoji增加吸引力 """, examples = { // 提供具体的使用示例,帮助AI理解期望的输出格式 "generateMarketingCopy('智能手表', '可穿戴设备', '健康监测,长续航', '健身爱好者', '1000-2000元', 150, '活力激情')", "generateMarketingCopy('护肤精华', '美容产品', '抗衰老,补水保湿', '25-35岁女性', '200-500元', 100, '温柔优雅')", "generateMarketingCopy('编程课程', '在线教育', '零基础,实战项目', 'IT转行者', '2000-5000元', 200, '专业可信')" })
public String generateMarketingCopy(String productName, String productType,
String features, String targetCustomer,
String priceRange, Integer maxLength, String tone) {// 【参数验证】确保核心参数不为空 if (productName == null || productName.trim().isEmpty()) { throw new IllegalArgumentException("产品名称不能为空"); } if (targetCustomer == null || targetCustomer.trim().isEmpty()) { throw new IllegalArgumentException("目标客户不能为空"); } // 【参数标准化】设置默认值 maxLength = maxLength != null ? maxLength : 150; tone = tone != null ? tone : "友好专业"; // 【特征处理】将特征字符串转换为列表,便于AI理解 String processedFeatures = features; if (features != null && features.contains(",")) { // 将逗号分隔的特征转换为更清晰的格式 processedFeatures = features.replace(",", "、"); } // 【日志记录】记录文案生成请求 log.info("生成营销文案: 产品={}, 目标客户={}, 特点={}, 风格={}, 最大长度={}字", productName, targetCustomer, processedFeatures, tone, maxLength); // 【业务逻辑】根据产品类型和目标客户,可以添加特定的处理逻辑 if ("美容产品".equals(productType) && targetCustomer.contains("女性")) { log.debug("检测到美容产品+女性客户,AI将使用更加温柔优雅的语言风格"); } if ("IT".equals(productType) || "编程".equals(productType)) { log.debug("检测到技术类产品,AI将使用更加专业可信的语言风格"); } return null; // 由Spring AI自动处理}
}
}
条件模板使用场景: 智能客服系统,需要根据客户等级提供差异化服务 - SEO团队需要优化搜索引擎友好的内容
/**
-
智能客服机器人 - 使用条件模板实现个性化服务
-
业务场景:
-
- 大型电商平台的客服系统,每天处理数万客户咨询
-
- 需要根据客户等级(VIP、普通、新客户)提供不同级别的服务
-
- VIP客户需要更加贴心的服务和专属优惠
-
- 新客户需要更多的引导和解释
-
- 普通客户需要标准化的专业服务
-
条件模板特点:
-
- 使用 {#if} 条件语句根据客户等级动态调整提示词
-
- 同一个模板可以处理不同等级客户的差异化需求
-
- 避免了为每个客户等级创建单独模板的复杂性
*/
@Component
@Slf4j
public class CustomerServiceBot {
@Autowired
private CustomerService customerService; // 客户信息服务@Autowired
private OrderService orderService; // 订单服务/**
-
智能客服条件模板
-
模板逻辑:
-
- 基础部分:所有客户都会收到的标准服务指引
-
- VIP条件:只有VIP客户才会触发的特殊服务指引
-
- 新客户条件:只有新客户才会触发的引导性服务
-
实际效果示例:
-
VIP客户咨询:
-
输入:companyName=“京东”, customerQuery=“我的订单什么时候到?”, customerLevel=“VIP”
-
AI收到的提示词会包含VIP特殊服务指引,回复会更加贴心并提供专属服务
-
新客户咨询:
-
输入:companyName=“京东”, customerQuery=“怎么退货?”, customerLevel=“NEW”
-
AI收到的提示词会包含新客户引导,回复会更加详细和耐心
-
普通客户咨询:
-
输入:companyName=“京东”, customerQuery=“商品有质量问题”, customerLevel=“REGULAR”
-
AI收到的是标准提示词,提供专业标准的客服回复
*/
@AIPrompt(
value = “”"
你是{companyName}的专业客服助手。请根据客户问题提供帮助:客户问题:{customerQuery} 客户等级:{customerLevel} {#if customerLevel == 'VIP'} 【VIP客户特别提醒】 这是我们的VIP客户,请提供最优质的服务: - 使用更加亲切和尊敬的语调 - 优先提供解决方案,减少客户等待时间 - 可以主动提供VIP专属优惠或补偿 - 如需人工服务,请安排VIP专线客服 {/if} {#if customerLevel == 'NEW'} 【新客户特别提醒】 这是我们的新客户,请提供耐心细致的服务: - 详细解释我们的服务流程和政策 - 主动介绍相关功能和使用方法 - 语言要通俗易懂,避免专业术语 - 可以提供新客户专享优惠信息 {/if} {#if customerLevel == 'PREMIUM'} 【高级客户提醒】 这是我们的高级客户,请提供专业优质的服务: - 快速定位问题并提供专业解决方案 - 可以提供高级客户专属服务 {/if} 回复要求: 1. 保持友好、专业的语调,体现{companyName}的品牌形象 2. 针对具体问题提供可操作的解决方案 3. 如果问题复杂无法解决,礼貌引导联系人工客服 4. 回复要简洁明了,避免冗长的解释 {#if customerLevel == 'VIP'} 5. 【VIP专享】可以主动提供额外的优惠券或服务补偿 6. 【VIP专享】询问是否需要安排专属客服经理跟进 {/if} {#if customerLevel == 'NEW'} 5. 【新客户专享】主动介绍新客户福利和使用指南 6. 【新客户专享】提供详细的操作步骤说明 {/if} """
)
public String handleCustomerQuery(String companyName, String customerQuery, String customerLevel) {// 【参数验证】确保必需参数不为空 if (companyName == null || companyName.trim().isEmpty()) { throw new IllegalArgumentException("公司名称不能为空"); } if (customerQuery == null || customerQuery.trim().isEmpty()) { throw new IllegalArgumentException("客户问题不能为空"); } // 【客户等级标准化】统一客户等级格式 customerLevel = normalizeCustomerLevel(customerLevel); // 【业务逻辑】根据客户等级记录不同的日志 switch (customerLevel) { case "VIP": log.info("VIP客户咨询: 公司={}, 问题={}", companyName, customerQuery); // 可以触发VIP客户专属的业务逻辑,如发送通知给客服经理 notifyVIPCustomerService(customerQuery); break; case "NEW": log.info("新客户咨询: 公司={}, 问题={}", companyName, customerQuery); // 可以触发新客户引导流程 trackNewCustomerInteraction(customerQuery); break; default: log.info("普通客户咨询: 公司={}, 问题={}, 等级={}", companyName, customerQuery, customerLevel); } return null; // 由Spring AI自动处理条件模板替换和AI调用}
/**
-
标准化客户等级
*/
private String normalizeCustomerLevel(String level) {
if (level == null) return “REGULAR”;return switch (level.toUpperCase()) {
case “VIP”, “DIAMOND”, “PLATINUM” -> “VIP”;
case “NEW”, “NEWBIE”, “FIRST_TIME” -> “NEW”;
case “PREMIUM”, “GOLD”, “SILVER” -> “PREMIUM”;
default -> “REGULAR”;
};
}
/**
- VIP客户专属服务通知
*/
private void notifyVIPCustomerService(String query) {
// 发送通知给VIP客服团队
log.debug(“已通知VIP客服团队关注客户咨询: {}”, query);
}
/**
- 新客户互动跟踪
*/
private void trackNewCustomerInteraction(String query) {
// 记录新客户的互动,用于后续的客户关怀
log.debug(“记录新客户互动: {}”, query);
}
}
- 避免了为每个客户等级创建单独模板的复杂性
/*
期望输出示例:
VIP客户咨询退货:
输入:handleCustomerQuery(“京东”, “我买的手机有问题,想退货”, “VIP”)
输出:尊敬的VIP客户,非常抱歉给您带来不便!关于手机退货问题,我立即为您处理:
1. 您可以在订单页面直接申请退货,我们将安排上门取件
2. 作为VIP客户,您享有7天无理由退货服务
3. 为了表达歉意,我为您准备了100元优惠券
4. 如需更多帮助,我可以安排VIP专属客服经理为您服务,请问需要吗?
新客户咨询使用方法:
输入:handleCustomerQuery(“淘宝”, “怎么查看物流信息?”, “NEW”)
输出:欢迎新客户!查看物流信息很简单,我详细为您介绍:
1. 打开淘宝APP,点击底部"我的淘宝"
2. 找到"待收货"订单,点击进入
3. 在订单详情页面就能看到详细的物流跟踪信息
4. 作为新客户,您还可以享受新人专享优惠券,要不要了解一下?
普通客户咨询:
输入:handleCustomerQuery(“拼多多”, “订单取消了但是钱没退”, “REGULAR”)
输出:您好!关于订单取消后退款问题,请您放心:
1. 订单取消后,退款通常在1-3个工作日内到账
2. 您可以在"个人中心-退款记录"中查看退款进度
3. 如果超过3个工作日未到账,请联系在线客服处理
4. 需要我帮您转接人工客服吗?
*/
2.3.5 @AIModel 注解详解
作用: 指定特定的AI模型或配置,支持多模型场景
核心属性:
value: 模型名称或配置名
provider: AI提供商
temperature: 模型温度
maxTokens: 最大token数
fallback: 备用模型
基础使用场景: 企业AI应用中,根据任务复杂度和成本要求选择不同的AI模型
/**
-
多模型服务 - 根据业务需求选择合适的AI模型
-
业务场景:
-
- 企业内部有多种AI处理需求:简单问答、复杂分析、图像处理
-
- 需要在成本和性能之间找到平衡
-
- 不同任务对AI能力要求不同,使用统一模型会造成资源浪费
-
模型选择策略:
-
- qwen-vl-plus: 多模态模型,处理图像+文本任务,成本适中
-
- qwen-max: 高性能文本模型,处理复杂推理任务,成本较高
-
- qwen-turbo: 快速模型,处理简单任务,成本最低
*/
@Service
@Slf4j
public class MultiModelService {
// 【多模态模型】用于处理图像分析、视觉问答等需要图像理解的任务
@AIModel(“qwen-vl-plus”)
private ChatModel multimodalModel;// 【高性能模型】用于复杂的文本分析、推理、创作等高要求任务
@AIModel(“qwen-max”)
private ChatModel highPerformanceModel;// 【经济模型】用于简单的问答、分类等基础任务,成本最低
@AIModel(“qwen-turbo”)
private ChatModel economicModel;/**
-
处理复杂任务 - 使用高性能模型
-
适用场景:
-
- 复杂的数据分析和报告生成
-
- 专业领域的深度问答
-
- 创意写作和内容创作
-
- 复杂的逻辑推理
-
成本考虑:高性能模型成本较高,只用于确实需要强大AI能力的任务
*/
public String processComplexTask(String input) {
// 【日志记录】记录使用高性能模型的任务
log.info(“使用高性能模型处理复杂任务,输入长度: {}字符”, input.length());// 【性能监控】记录处理开始时间
long startTime = System.currentTimeMillis();try {
// 【核心调用】使用qwen-max模型处理复杂任务
String result = highPerformanceModel.call(input);// 【性能统计】记录处理时间 long processingTime = System.currentTimeMillis() - startTime; log.info("高性能模型处理完成,耗时: {}ms, 输出长度: {}字符", processingTime, result.length()); return result;} catch (Exception e) {
log.error(“高性能模型处理失败: {}”, e.getMessage());
throw new AIProcessingException(“复杂任务处理失败”, e);
}
}
/**
-
处理简单任务 - 使用经济模型
-
适用场景:
-
- 简单的问答和咨询
-
- 基础的文本分类
-
- 标准化的客服回复
-
- 简单的信息提取
-
成本优势:经济模型成本低,适合大量的简单任务处理
*/
public String processSimpleTask(String input) {
// 【输入验证】简单任务通常输入较短,进行长度检查
if (input.length() > 500) {
log.warn(“输入内容较长({}字符),建议使用高性能模型处理”, input.length());
}// 【日志记录】记录使用经济模型的任务
log.debug(“使用经济模型处理简单任务: {}”, input.substring(0, Math.min(50, input.length())));try {
// 【核心调用】使用qwen-turbo模型处理简单任务
String result = economicModel.call(input);log.debug("经济模型处理完成,输出: {}", result.substring(0, Math.min(100, result.length()))); return result;} catch (Exception e) {
log.error(“经济模型处理失败: {}”, e.getMessage());
// 【降级处理】经济模型失败时,可以考虑升级到高性能模型
log.info(“尝试使用高性能模型重新处理”);
return processComplexTask(input);
}
}
/**
-
处理多模态任务 - 使用多模态模型
-
适用场景:
-
- 图像内容分析和描述
-
- 图像中的文字识别和理解
-
- 视觉问答
-
- 图像分类和标注
*/
public String processMultimodalTask(byte[] imageData, String textQuery) {
// 【参数验证】确保图像数据和文本查询都不为空
if (imageData == null || imageData.length == 0) {
throw new IllegalArgumentException(“图像数据不能为空”);
}
if (textQuery == null || textQuery.trim().isEmpty()) {
throw new IllegalArgumentException(“文本查询不能为空”);
}
// 【日志记录】记录多模态任务处理
log.info(“处理多模态任务,图像大小: {}KB, 查询: {}”,
imageData.length / 1024, textQuery);try {
// 【图像处理】将图像数据转换为Spring AI可处理的格式
Media imageMedia = new Media(MimeTypeUtils.IMAGE_JPEG,
new ByteArrayResource(imageData));// 【消息构建】创建包含图像和文本的多模态消息 UserMessage message = new UserMessage(textQuery, List.of(imageMedia)); // 【核心调用】使用多模态模型处理 ChatResponse response = multimodalModel.call(new Prompt(message)); String result = response.getResult().getOutput().getContent(); log.info("多模态任务处理完成,输出长度: {}字符", result.length()); return result;} catch (Exception e) {
log.error(“多模态任务处理失败: {}”, e.getMessage());
throw new AIProcessingException(“多模态任务处理失败”, e);
}
}
} - 图像分类和标注
- qwen-turbo: 快速模型,处理简单任务,成本最低
/*
使用示例和期望输出:
-
复杂任务处理:
输入:processComplexTask(“请分析2024年人工智能行业的发展趋势,包括技术突破、市场机会和挑战”)
期望输出:详细的行业分析报告,包含多个维度的深度分析,约1000-2000字 -
简单任务处理:
输入:processSimpleTask(“今天天气怎么样?”)
期望输出:简洁的回答,如"我无法获取实时天气信息,建议您查看天气预报应用" -
多模态任务处理:
输入:processMultimodalTask(图像字节数组, “这张图片中有什么?”)
期望输出:对图像内容的详细描述,如"图片中有一只橙色的猫咪坐在绿色的草地上"
成本效益分析:
- 简单任务用turbo模型:成本低,速度快,满足基本需求
- 复杂任务用max模型:成本高,但质量好,适合重要任务
- 多模态任务用vl-plus模型:专门处理图像,性价比高
*/
高级配置:
@Component
public class AdvancedModelService {
@AIModel(
value = "qwen-vl-max",
provider = "dashscope",
temperature = 0.1f,
maxTokens = 4096,
fallback = "qwen-vl-plus"
)
private ChatModel precisionModel;
@AIModel(
value = "gpt-4o",
provider = "openai",
temperature = 0.3f,
maxTokens = 2048,
fallback = "gpt-3.5-turbo"
)
private ChatModel creativeModel;
// 根据任务类型选择模型
public String processTask(String input, TaskType taskType) {
return switch (taskType) {
case PRECISION_ANALYSIS -> precisionModel.call(input);
case CREATIVE_WRITING -> creativeModel.call(input);
default -> precisionModel.call(input);
};
}
}
动态模型选择:
@Service
public class DynamicModelService {
@AIModel("${ai.model.default}") // 从配置文件读取
private ChatModel defaultModel;
@AIModel("${ai.model.high-performance}")
private ChatModel highPerformanceModel;
@Value("${ai.model.selection.strategy:performance}")
private String selectionStrategy;
public String smartProcess(String input) {
ChatModel selectedModel = selectModel(input);
return selectedModel.call(input);
}
private ChatModel selectModel(String input) {
if ("performance".equals(selectionStrategy) && input.length() > 1000) {
return highPerformanceModel;
}
return defaultModel;
}
}
2.3.6 @AIRetry 注解详解
作用: 配置AI调用的重试策略,提高系统可靠性
核心属性:
maxAttempts: 最大重试次数
backoff: 退避策略
include: 需要重试的异常类型
exclude: 不需要重试的异常类型
recover: 恢复方法
基础使用场景: 生产环境中AI服务可能因网络波动、服务繁忙等原因偶尔失败,需要自动重试
/**
-
健壮的AI服务 - 使用重试机制提高服务可靠性
-
业务场景:
-
- 生产环境中AI服务偶尔会因为网络问题、服务器负载等原因失败
-
- 用户不应该因为这些临时性问题而得到错误响应
-
- 通过自动重试可以大大提高服务的成功率和用户体验
-
- 不同类型的任务需要不同的重试策略
-
重试策略说明:
-
- 简单重试:固定次数重试,适合快速失败的场景
-
- 指数退避:逐渐增加重试间隔,适合服务器负载过高的场景
*/
@Service
@Slf4j
public class RobustAIService {
@Autowired
private ChatModel chatModel;@Autowired
private AIMetricsCollector metricsCollector; // 用于收集重试统计/**
-
简单重试策略
-
适用场景:
-
- 快速的AI调用,如简单问答
-
- 对延迟敏感的实时应用
-
- 临时性网络问题导致的失败
-
重试逻辑:
-
- 最多重试3次(包含首次调用共4次)
-
- 每次重试之间没有延迟
-
- 适合快速失败快速恢复的场景
*/
@AIRetry(maxAttempts = 3)
public String simpleRetry(String message) {
// 【日志记录】记录重试尝试(Spring会自动处理重试逻辑)
log.debug(“执行AI调用,消息长度: {}字符”, message.length());
try {
// 【核心调用】调用AI模型
String result = chatModel.call(message);// 【成功统计】记录成功调用 metricsCollector.recordSuccess("simple-retry"); log.debug("AI调用成功,响应长度: {}字符", result.length()); return result;} catch (Exception e) {
// 【失败统计】记录失败尝试(重试会自动进行)
metricsCollector.recordFailure(“simple-retry”, e.getClass().getSimpleName());
log.warn(“AI调用失败,将自动重试: {}”, e.getMessage());// 重新抛出异常,让Spring的重试机制处理 throw e;}
} - 适合快速失败快速恢复的场景
/**
-
指数退避重试策略
-
适用场景:
-
- 复杂的AI任务,如长文本分析、图像处理
-
- 服务器负载较高时的调用
-
- 需要给服务器恢复时间的场景
-
重试逻辑:
-
- 最多重试5次
-
- 首次延迟1秒,每次重试延迟翻倍(1s, 2s, 4s, 8s)
-
- 最大延迟不超过10秒
-
- 适合服务器负载过高导致的失败
*/
@AIRetry(
maxAttempts = 5, // 最多重试5次
backoff = @Backoff(
delay = 1000, // 首次重试延迟1秒
multiplier = 2, // 每次延迟翻倍
maxDelay = 10000 // 最大延迟10秒
)
)
public String exponentialBackoffRetry(String message) {
// 【日志记录】记录带退避策略的重试调用
log.info(“执行指数退避重试AI调用,消息: {}”,
message.substring(0, Math.min(50, message.length())));
// 【性能监控】记录调用开始时间
long startTime = System.currentTimeMillis();try {
// 【核心调用】调用AI模型
String result = chatModel.call(message);// 【性能统计】记录成功调用的耗时 long duration = System.currentTimeMillis() - startTime; metricsCollector.recordSuccess("exponential-backoff", duration); log.info("指数退避重试成功,总耗时: {}ms, 响应长度: {}字符", duration, result.length()); return result;} catch (Exception e) {
// 【失败统计】记录失败信息
long duration = System.currentTimeMillis() - startTime;
metricsCollector.recordFailure(“exponential-backoff”, e.getClass().getSimpleName(), duration);log.warn("指数退避重试失败,已耗时: {}ms, 错误: {}", duration, e.getMessage()); // 重新抛出异常,让重试机制继续处理 throw e;}
} - 适合服务器负载过高导致的失败
/**
- 智能重试 - 根据消息类型选择重试策略
- 业务逻辑:
-
- 短消息使用简单重试
-
- 长消息使用指数退避重试
-
- 图像相关任务使用更长的重试间隔
*/
public String smartRetry(String message, String taskType) {
// 【策略选择】根据任务类型和消息长度选择重试策略
if (“image”.equals(taskType) || message.length() > 1000) {
// 复杂任务使用指数退避
return exponentialBackoffRetry(message);
} else {
// 简单任务使用快速重试
return simpleRetry(message);
}
}
}
- 图像相关任务使用更长的重试间隔
- 指数退避:逐渐增加重试间隔,适合服务器负载过高的场景
/*
重试效果示例:
- 简单重试场景:
调用:simpleRetry(“今天天气怎么样?”)
如果失败:立即重试,最多3次
日志输出:
- 第1次失败:AI调用失败,将自动重试: Connection timeout
- 第2次失败:AI调用失败,将自动重试: Service unavailable
- 第3次成功:AI调用成功,响应长度: 45字符
- 指数退避重试场景:
调用:exponentialBackoffRetry(“请分析这份1000字的市场报告…”)
如果失败:按1s, 2s, 4s, 8s间隔重试
日志输出:
- 第1次失败:指数退避重试失败,已耗时: 1200ms, 错误: Rate limit exceeded
- 等待1秒后第2次失败:指数退避重试失败,已耗时: 3400ms, 错误: Service busy
- 等待2秒后第3次成功:指数退避重试成功,总耗时: 7800ms, 响应长度: 2048字符
重试的价值:
- 提高服务可用性:从95%提升到99%+
- 改善用户体验:用户无感知的故障恢复
- 降低运维成本:减少因临时故障导致的客服咨询
*/
高级重试策略:
@Component
public class AdvancedRetryService {
@AIRetry(
maxAttempts = 3,
include = {AIServiceException.class, TimeoutException.class},
exclude = {AuthenticationException.class, QuotaExceededException.class},
backoff = @Backoff(
delay = 2000,
multiplier = 1.5,
maxDelay = 30000,
random = true // 添加随机延迟,避免雷群效应
)
)
public String robustCall(String message) {
return chatModel.call(message);
}
// 重试失败后的恢复方法
@Recover
public String recover(AIServiceException ex, String message) {
log.error("AI调用最终失败,使用备用方案: {}", ex.getMessage());
return "抱歉,AI服务暂时不可用,请稍后重试。";
}
@Recover
public String recover(TimeoutException ex, String message) {
log.error("AI调用超时,尝试简化处理: {}", ex.getMessage());
// 使用更简单的处理逻辑
return processWithSimpleLogic(message);
}
}
条件重试:
@Service
public class ConditionalRetryService {
@AIRetry(
maxAttempts = 3,
condition = "#{@retryCondition.shouldRetry(#root.cause)}"
)
public String conditionalRetry(String message) {
return chatModel.call(message);
}
}
@Component
public class RetryCondition {
public boolean shouldRetry(Throwable cause) {
// 自定义重试条件
if (cause instanceof RateLimitException) {
return true; // 限流异常需要重试
}
if (cause instanceof ModelNotAvailableException) {
return false; // 模型不可用不需要重试
}
return cause instanceof TransientException;
}
}
2.3.7 @AICache 注解详解
作用: 配置AI响应的缓存策略,提高性能并降低成本
核心属性:
value: 缓存名称
key: 缓存键表达式
ttl: 缓存过期时间
condition: 缓存条件
unless: 不缓存条件
基础使用场景: 企业应用中相同的AI请求经常重复出现,缓存可以显著提高响应速度并降低成本
/**
-
缓存AI服务 - 使用缓存策略提高性能和降低成本
-
业务场景:
-
- 客服系统中用户经常问相同的问题
-
- 翻译服务中相同的文本被多次翻译
-
- 内容分析中相同的文档被重复分析
-
- 图像识别中相同的图片被多次处理
-
缓存价值:
-
- 性能提升:缓存命中时响应时间从秒级降到毫秒级
-
- 成本节约:避免重复的AI API调用,节省费用
-
- 用户体验:更快的响应速度,更好的用户体验
-
- 系统稳定:减少对外部AI服务的依赖
*/
@Service
@Slf4j
public class CachedAIService {
@Autowired
private ChatModel chatModel;@Autowired
private TranslationModel translationModel;@Autowired
private CacheManager cacheManager; // 用于缓存管理/**
-
基础缓存策略
-
适用场景:
-
- 通用的AI问答,如常见问题解答
-
- 短期内可能重复的查询
-
- 对实时性要求不高的内容
-
缓存策略:
-
- 缓存名称:ai-responses
-
- 缓存时间:1小时
-
- 缓存键:默认使用方法参数的hashCode
*/
@AICache(value = “ai-responses”, ttl = “1h”)
public String cachedCall(String message) {
// 【日志记录】记录AI调用(只有缓存未命中时才会执行)
log.info(“执行AI调用(缓存未命中),消息: {}”,
message.substring(0, Math.min(50, message.length())));
// 【性能监控】记录实际AI调用
long startTime = System.currentTimeMillis();try {
// 【核心调用】只有缓存未命中时才会真正调用AI
String result = chatModel.call(message);// 【统计记录】记录缓存未命中的调用 long duration = System.currentTimeMillis() - startTime; log.info("AI调用完成,耗时: {}ms,结果将缓存1小时", duration); return result;} catch (Exception e) {
log.error(“AI调用失败,不会缓存错误结果: {}”, e.getMessage());
throw e;
}
} - 缓存键:默认使用方法参数的hashCode
/**
-
高级缓存策略 - 翻译服务
-
适用场景:
-
- 多语言翻译服务
-
- 相同文本翻译成不同语言
-
- 翻译结果相对稳定,可以长期缓存
-
缓存策略:
-
- 自定义缓存键:文本内容hash + 目标语言
-
- 长期缓存:24小时
-
- 精确匹配:相同文本+相同目标语言才能命中缓存
*/
@AICache(
value = “translation-cache”,
key = “#{#text.hashCode()}_#{#targetLang}”, // 自定义缓存键
ttl = “24h” // 翻译结果可以缓存更长时间
)
public String translateWithCache(String text, String targetLang) {
// 【参数验证】确保参数有效
if (text == null || text.trim().isEmpty()) {
throw new IllegalArgumentException(“待翻译文本不能为空”);
}
if (targetLang == null || targetLang.trim().isEmpty()) {
throw new IllegalArgumentException(“目标语言不能为空”);
}
// 【日志记录】记录翻译请求
log.info(“执行翻译(缓存未命中),文本长度: {}字符, 目标语言: {}”,
text.length(), targetLang);// 【缓存检查】手动检查缓存状态(用于统计)
String cacheKey = text.hashCode() + “_” + targetLang;
Cache cache = cacheManager.getCache(“translation-cache”);
boolean cacheHit = cache != null && cache.get(cacheKey) != null;if (!cacheHit) {
log.debug(“翻译缓存未命中,将调用AI翻译服务”);
}try {
// 【核心调用】执行翻译(如果缓存命中,这里不会执行)
String result = translationModel.translate(text, targetLang);log.info("翻译完成,原文: {}字符 -> 译文: {}字符,结果已缓存24小时", text.length(), result.length()); return result;} catch (Exception e) {
log.error(“翻译失败: {}”, e.getMessage());
throw new TranslationException(“翻译服务暂时不可用”, e);
}
} - 精确匹配:相同文本+相同目标语言才能命中缓存
/**
-
条件缓存 - 只缓存成功的结果
-
适用场景:
-
- 可能失败的AI调用
-
- 需要区分成功和失败结果的场景
-
- 避免缓存错误信息
*/
@AICache(
value = “conditional-cache”,
ttl = “2h”,
condition = “#message.length() < 500”, // 只缓存短消息
unless = “#result.contains(‘错误’) or #result.contains(‘失败’)” // 不缓存错误结果
)
public String conditionalCache(String message) {
log.info(“执行条件缓存AI调用,消息长度: {}字符”, message.length());
String result = chatModel.call(message);
// 【缓存逻辑】只有满足条件的结果才会被缓存
if (message.length() >= 500) {
log.debug(“消息过长,不会缓存结果”);
}
if (result.contains(“错误”) || result.contains(“失败”)) {
log.debug(“结果包含错误信息,不会缓存”);
}return result;
} - 避免缓存错误信息
/**
-
缓存统计和管理
*/
public CacheStats getCacheStats() {
Cache aiCache = cacheManager.getCache(“ai-responses”);
Cache translationCache = cacheManager.getCache(“translation-cache”);return CacheStats.builder()
.aiCacheSize(aiCache != null ? aiCache.getNativeCache().size() : 0)
.translationCacheSize(translationCache != null ? translationCache.getNativeCache().size() : 0)
.build();
}
/**
- 手动清理缓存
*/
public void clearCache(String cacheName) {
Cache cache = cacheManager.getCache(cacheName);
if (cache != null) {
cache.clear();
log.info(“已清理缓存: {}”, cacheName);
}
}
}
- 系统稳定:减少对外部AI服务的依赖
/*
缓存效果示例:
-
首次调用(缓存未命中):
调用:cachedCall(“什么是人工智能?”)
执行:实际调用AI服务,耗时2000ms
结果:缓存结果,下次相同问题直接返回
日志:执行AI调用(缓存未命中),消息: 什么是人工智能?
AI调用完成,耗时: 2000ms,结果将缓存1小时 -
重复调用(缓存命中):
调用:cachedCall(“什么是人工智能?”)
执行:直接从缓存返回,耗时5ms
结果:立即返回缓存的结果
日志:无日志(方法体未执行) -
翻译缓存示例:
首次调用:translateWithCache(“Hello World”, “zh”)
- 执行翻译,耗时1500ms,结果缓存24小时
重复调用:translateWithCache(“Hello World”, “zh”) - 直接返回缓存结果,耗时3ms
缓存收益分析:
- 响应时间:从2000ms降到5ms,提升400倍
- 成本节约:避免重复API调用,节省80%费用
- 系统负载:减少对外部服务的依赖
- 用户体验:几乎瞬时的响应速度
*/
高级缓存策略:
@Component
public class SmartCacheService {
@AICache(
value = "sentiment-analysis",
key = "#{T(java.security.MessageDigest).getInstance('MD5').digest(#text.bytes)}",
ttl = "7d",
condition = "#text.length() < 1000", // 只缓存短文本
unless = "#result.contains('error')" // 错误结果不缓存
)
public String analyzeSentimentWithCache(String text) {
return sentimentModel.analyze(text);
}
@AICache(
value = "image-analysis",
key = "#{#imageHash}_#{#analysisType}",
ttl = "30d"
)
public String analyzeImageWithCache(String imageHash, String analysisType, byte[] imageData) {
return imageModel.analyze(imageData, analysisType);
}
// 缓存清理
@CacheEvict(value = "ai-responses", allEntries = true)
@Scheduled(fixedRate = 3600000) // 每小时清理一次
public void clearExpiredCache() {
log.info("清理过期的AI响应缓存");
}
}
2.3.8 @AIRateLimit 注解详解
作用: 配置AI调用的速率限制,防止超出API配额
核心属性:
value: 限制数量
window: 时间窗口
scope: 限制范围(全局、用户、IP等)
fallback: 限流后的处理方法
基础使用:
@Service
public class RateLimitedAIService {
@AIRateLimit(value = 100, window = "1m") // 每分钟最多100次调用
public String limitedCall(String message) {
return chatModel.call(message);
}
@AIRateLimit(
value = 1000,
window = "1h",
scope = "user", // 按用户限制
fallback = "rateLimitFallback"
)
public String userLimitedCall(String message, String userId) {
return chatModel.call(message);
}
public String rateLimitFallback(String message, String userId) {
return "请求过于频繁,请稍后再试。";
}
}
高级限流策略:
@Component
public class AdvancedRateLimitService {
@AIRateLimit(
value = 50,
window = "1m",
scope = "ip",
strategy = RateLimitStrategy.SLIDING_WINDOW
)
public String ipBasedLimit(String message, HttpServletRequest request) {
return chatModel.call(message);
}
@AIRateLimit(
value = 10,
window = "1m",
scope = "method",
priority = RateLimitPriority.HIGH // 高优先级用户
)
public String priorityCall(String message) {
return expensiveModel.call(message);
}
// 动态限流
@AIRateLimit(
value = "#{@rateLimitConfig.getLimit(#userLevel)}",
window = "1h",
scope = "user"
)
public String dynamicLimit(String message, String userId, String userLevel) {
return chatModel.call(message);
}
}
@Component
public class RateLimitConfig {
public int getLimit(String userLevel) {
return switch (userLevel) {
case "VIP" -> 1000;
case "PREMIUM" -> 500;
case "BASIC" -> 100;
default -> 50;
};
}
}
2.3.9 注解组合使用
多注解协同工作:
@Component
public class ComprehensiveAIService {
@AIModel("qwen-vl-plus")
@AIRetry(maxAttempts = 3, backoff = @Backoff(delay = 1000))
@AICache(value = "image-analysis", ttl = "1h")
@AIRateLimit(value = 50, window = "1m")
public String analyzeImageComprehensive(MultipartFile image, String analysisType) {
// 这个方法组合了多个注解的功能:
// 1. 使用指定的qwen-vl-plus模型
// 2. 失败时自动重试最多3次
// 3. 结果缓存1小时
// 4. 每分钟最多调用50次
return imageAnalysisModel.analyze(image, analysisType);
}
@AIFunction(
description = "智能客服助手,处理客户咨询",
parameters = {
@AIParameter(name = "customerQuery", description = "客户问题", required = true),
@AIParameter(name = "customerLevel", description = "客户等级:VIP/PREMIUM/BASIC", required = false)
}
)
@AIPrompt("""
你是专业的客服助手。客户问题:{customerQuery}
客户等级:{customerLevel}
请提供专业、友好的回复,如果是VIP客户请特别用心服务。
""")
@AIRetry(maxAttempts = 2)
@AIRateLimit(value = 100, window = "1h", scope = "user")
public String handleCustomerService(String customerQuery, String customerLevel) {
return null; // 由Spring AI自动处理
}
}
条件化注解使用:
@Service
@ConditionalOnProperty(name = "ai.advanced-features.enabled", havingValue = "true")
public class ConditionalAIService {
@AIModel("${ai.model.premium:qwen-vl-max}")
@AIRetry(
maxAttempts = 3,
condition = "#{@aiConfig.isRetryEnabled()}"
)
@AICache(
value = "premium-analysis",
condition = "#{@aiConfig.isCacheEnabled()}",
ttl = "#{@aiConfig.getCacheTtl()}"
)
public String premiumAnalysis(String input) {
return premiumModel.call(input);
}
}
@Configuration
public class AIConfig {
@Value("${ai.retry.enabled:true}")
private boolean retryEnabled;
@Value("${ai.cache.enabled:true}")
private boolean cacheEnabled;
@Value("${ai.cache.ttl:1h}")
private String cacheTtl;
public boolean isRetryEnabled() { return retryEnabled; }
public boolean isCacheEnabled() { return cacheEnabled; }
public String getCacheTtl() { return cacheTtl; }
}
2.3.10 实际应用场景示例
场景1:智能文档处理系统
@Component
public class DocumentProcessingService {
@AIFunction(
description = "提取文档中的关键信息",
parameters = {
@AIParameter(name = "documentContent", description = "文档内容", required = true),
@AIParameter(name = "extractionType", description = "提取类型:summary/keywords/entities", required = true)
}
)
@AIModel("qwen-max") // 使用高性能模型处理复杂文档
@AIRetry(maxAttempts = 2)
@AICache(value = "document-extraction", key = "#{#documentContent.hashCode()}_#{#extractionType}", ttl = "24h")
public String extractDocumentInfo(String documentContent, String extractionType) {
return documentModel.extract(documentContent, extractionType);
}
@AIPrompt("""
请对以下文档进行总结,要求:
1. 提取核心观点和结论
2. 保持原文的逻辑结构
3. 总结长度控制在{maxLength}字以内
文档内容:{content}
""")
@AIModel("qwen-plus")
@AICache(value = "document-summary", ttl = "12h")
@AIRateLimit(value = 20, window = "1m") // 文档总结比较耗资源,限制频率
public String summarizeDocument(String content, Integer maxLength) {
return null;
}
}
场景2:多语言客服系统
@Component
public class MultilingualCustomerService {
@AIFunction(
description = "检测文本语言并翻译成目标语言",
parameters = {
@AIParameter(name = "text", description = "待翻译文本", required = true),
@AIParameter(name = "targetLanguage", description = "目标语言", required = true)
}
)
@AIModel("qwen-plus")
@AIRetry(maxAttempts = 3, backoff = @Backoff(delay = 500))
@AICache(
value = "translation-cache",
key = "#{T(java.util.Objects).hash(#text, #targetLanguage)}",
ttl = "7d"
)
@AIRateLimit(value = 200, window = "1h", scope = "user")
public String translateText(String text, String targetLanguage) {
return translationModel.translate(text, targetLanguage);
}
@AIPrompt("""
你是多语言客服助手。请用{language}回复客户:
客户问题:{customerQuery}
客户情绪:{sentiment}
回复要求:
1. 语言地道自然
2. 态度友好专业
3. 提供具体解决方案
{#if sentiment == 'angry'}
4. 特别注意安抚客户情绪
{/if}
""")
@AIModel("qwen-vl-plus")
@AIRetry(maxAttempts = 2)
@AIRateLimit(value = 100, window = "1h", scope = "user")
public String handleMultilingualSupport(String customerQuery, String language, String sentiment) {
return null;
}
}
场景3:智能内容审核系统
@Component
public class ContentModerationService {
@AIFunction(
description = "检测内容是否包含不当信息",
parameters = {
@AIParameter(name = "content", description = "待检测内容", required = true),
@AIParameter(name = "strictLevel", description = "检测严格程度:low/medium/high", required = false)
}
)
@AIModel("qwen-plus")
@AIRetry(maxAttempts = 2)
@AICache(
value = "content-moderation",
key = "#{T(org.springframework.util.DigestUtils).md5DigestAsHex(#content.bytes)}_#{#strictLevel}",
ttl = "1h",
unless = "#result.contains('违规')" // 违规内容不缓存
)
@AIRateLimit(value = 500, window = "1m") // 内容审核需要高频调用
public String moderateContent(String content, String strictLevel) {
return moderationModel.check(content, strictLevel);
}
@AIPrompt("""
请分析以下图片内容是否合规:
检测维度:
1. 是否包含暴力内容
2. 是否包含不当信息
3. 是否包含版权问题
4. 整体内容质量评估
请返回JSON格式结果:
{
"compliant": true/false,
"violations": ["违规类型1", "违规类型2"],
"confidence": 0.95,
"suggestion": "处理建议"
}
""")
@AIModel("qwen-vl-plus") // 图片审核需要多模态模型
@AIRetry(maxAttempts = 3)
@AICache(value = "image-moderation", ttl = "24h")
@AIRateLimit(value = 200, window = "1m")
public String moderateImage(MultipartFile image) {
return null;
}
}
场景4:个性化推荐系统
@Component
public class PersonalizedRecommendationService {
@AIFunction(
description = "基于用户行为生成个性化推荐",
parameters = {
@AIParameter(name = "userId", description = "用户ID", required = true),
@AIParameter(name = "userProfile", description = "用户画像", required = true),
@AIParameter(name = "recentBehavior", description = "最近行为数据", required = true),
@AIParameter(name = "recommendCount", description = "推荐数量", required = false, defaultValue = "10")
}
)
@AIModel("qwen-max") // 推荐算法需要强大的推理能力
@AIRetry(maxAttempts = 2)
@AICache(
value = "user-recommendations",
key = "#{#userId}_#{T(java.time.LocalDate).now()}", // 按用户和日期缓存
ttl = "4h"
)
@AIRateLimit(value = 50, window = "1m", scope = "user")
public String generateRecommendations(String userId, String userProfile,
String recentBehavior, Integer recommendCount) {
return recommendationModel.generate(userId, userProfile, recentBehavior, recommendCount);
}
@AIPrompt("""
基于用户信息生成个性化的商品推荐理由:
用户画像:{userProfile}
推荐商品:{product}
用户偏好:{preferences}
请生成吸引人的推荐理由,要求:
1. 突出商品与用户需求的匹配点
2. 语言亲切自然
3. 包含具体的价值点
4. 长度控制在100字以内
""")
@AIModel("qwen-plus")
@AICache(value = "recommendation-reasons", ttl = "12h")
@AIRateLimit(value = 100, window = "1m")
public String generateRecommendationReason(String userProfile, String product, String preferences) {
return null;
}
}
2.4 支持的AI提供商
OpenAI: GPT-4o, GPT-4o-mini, DALL-E等
Azure OpenAI: 微软云上的OpenAI服务
Anthropic: Claude系列模型
Google Vertex AI: Gemini系列模型
Ollama: 本地部署的开源模型
百炼平台: 阿里云通义千问系列(通过OpenAI兼容接口)
2万+

被折叠的 条评论
为什么被折叠?



