Spring AI架构设计

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();
}

}

/*
期望效果:

  1. 只扫描指定包下的AI功能,提高启动速度
  2. 所有AI调用默认使用qwen-vl-plus模型
  3. 失败的AI调用会自动重试
  4. 提供统一的性能监控和指标收集
  5. 可以通过配置文件覆盖这些默认设置
    */
    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对话流程
    1. 用户输入:“北京今天天气怎么样?”
    1. AI模型分析用户意图,识别出这是天气查询请求
    1. AI模型自动调用 getCurrentWeather(“北京”) 函数
    1. 函数返回 WeatherInfo 对象
    1. AI模型将结果转换为自然语言:“北京今天晴天,温度25°C,湿度60%,风速微风,空气质量良好”
    1. 返回给用户最终回复
      */
      高级使用场景: 企业级CRM系统的AI助手,需要处理复杂的客户查询和业务计算

/**

  • 企业业务功能服务类 - 为AI模型提供复杂的业务操作能力

  • 业务场景:

    1. 客服人员询问:“帮我找一下姓张的VIP客户”
    1. HR询问:“2024年1月1日到3月31日有多少个工作日?”
    1. 销售询问:“客户编号CUST001的详细信息”
  • 期望输出:

    1. 返回符合条件的客户列表,包含完整的客户信息
    1. 返回精确的工作日计算结果
    1. 提供结构化的业务数据供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();
      }
      }

    /**

    • 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模型生成准确的回复
    */
    @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提示词模板进行文本处理

  • 业务场景:

    1. 电商平台需要分析用户评论的情感倾向(正面/负面/中性)
    1. 国际化应用需要将内容翻译成不同语言
    1. 内容审核系统需要快速判断文本的情感色彩
  • 期望输出:

    1. 情感分析:返回"positive"、“negative"或"neutral”
    1. 文本翻译:返回目标语言的翻译结果
      */
      @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自动填充返回值
      }

    /**

    • 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自动处理
      }

    /**

    • 辅助方法:简单的语言检测

    • 用于日志记录,不是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提示词模板

  • 业务场景:

    1. 企业官网需要定期发布行业文章
    1. 营销部门需要快速生成产品文案
    1. 内容团队需要批量创作不同风格的文章
    1. SEO团队需要优化搜索引擎友好的内容
      */
      @Component
      @Slf4j
      public class ContentGenerationService {

    /**

    • 高级文章生成模板

    • 模板特点:

      1. 支持多个参数的复杂组合
      1. 使用条件逻辑 {#if} 根据参数动态调整提示词
      1. 定义了变量的默认值和描述
      1. 支持专业领域的定制化内容生成
    • 使用场景示例:

      • 科技博客文章: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}

        要求:

        1. 内容原创,有深度和价值
        2. 结构清晰,逻辑性强
        3. 语言流畅,符合{audience}的阅读习惯
        4. 包含实用的建议或见解
          “”",
          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调用
      }
      }

    /**

    • 营销文案生成模板
    • 业务场景:
      1. 电商平台需要为新产品快速生成吸引人的文案
      1. 营销团队需要针对不同客户群体定制文案
      1. 广告投放需要多个版本的文案进行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自动处理
    

    }
    }
    }
    条件模板使用场景: 智能客服系统,需要根据客户等级提供差异化服务

/**

  • 智能客服机器人 - 使用条件模板实现个性化服务

  • 业务场景:

    1. 大型电商平台的客服系统,每天处理数万客户咨询
    1. 需要根据客户等级(VIP、普通、新客户)提供不同级别的服务
    1. VIP客户需要更加贴心的服务和专属优惠
    1. 新客户需要更多的引导和解释
    1. 普通客户需要标准化的专业服务
  • 条件模板特点:

    • 使用 {#if} 条件语句根据客户等级动态调整提示词
    • 同一个模板可以处理不同等级客户的差异化需求
    • 避免了为每个客户等级创建单独模板的复杂性
      */
      @Component
      @Slf4j
      public class CustomerServiceBot {

    @Autowired
    private CustomerService customerService; // 客户信息服务

    @Autowired
    private OrderService orderService; // 订单服务

    /**

    • 智能客服条件模板

    • 模板逻辑:

      1. 基础部分:所有客户都会收到的标准服务指引
      1. VIP条件:只有VIP客户才会触发的特殊服务指引
      1. 新客户条件:只有新客户才会触发的引导性服务
    • 实际效果示例:

    • 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模型

  • 业务场景:

    1. 企业内部有多种AI处理需求:简单问答、复杂分析、图像处理
    1. 需要在成本和性能之间找到平衡
    1. 不同任务对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);
      }
      }
      }

/*
使用示例和期望输出:

  1. 复杂任务处理:
    输入:processComplexTask(“请分析2024年人工智能行业的发展趋势,包括技术突破、市场机会和挑战”)
    期望输出:详细的行业分析报告,包含多个维度的深度分析,约1000-2000字

  2. 简单任务处理:
    输入:processSimpleTask(“今天天气怎么样?”)
    期望输出:简洁的回答,如"我无法获取实时天气信息,建议您查看天气预报应用"

  3. 多模态任务处理:
    输入: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服务 - 使用重试机制提高服务可靠性

  • 业务场景:

    1. 生产环境中AI服务偶尔会因为网络问题、服务器负载等原因失败
    1. 用户不应该因为这些临时性问题而得到错误响应
    1. 通过自动重试可以大大提高服务的成功率和用户体验
    1. 不同类型的任务需要不同的重试策略
  • 重试策略说明:

    • 简单重试:固定次数重试,适合快速失败的场景
    • 指数退避:逐渐增加重试间隔,适合服务器负载过高的场景
      */
      @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);
        }
        }
        }

/*
重试效果示例:

  1. 简单重试场景:
    调用:simpleRetry(“今天天气怎么样?”)
    如果失败:立即重试,最多3次
    日志输出:
  • 第1次失败:AI调用失败,将自动重试: Connection timeout
  • 第2次失败:AI调用失败,将自动重试: Service unavailable
  • 第3次成功:AI调用成功,响应长度: 45字符
  1. 指数退避重试场景:
    调用: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服务 - 使用缓存策略提高性能和降低成本

  • 业务场景:

    1. 客服系统中用户经常问相同的问题
    1. 翻译服务中相同的文本被多次翻译
    1. 内容分析中相同的文档被重复分析
    1. 图像识别中相同的图片被多次处理
  • 缓存价值:

    • 性能提升:缓存命中时响应时间从秒级降到毫秒级
    • 成本节约:避免重复的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;
      }
      }

    /**

    • 高级缓存策略 - 翻译服务

    • 适用场景:

      • 多语言翻译服务
      • 相同文本翻译成不同语言
      • 翻译结果相对稳定,可以长期缓存
    • 缓存策略:

      • 自定义缓存键:文本内容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);
      }
      }
      }

/*
缓存效果示例:

  1. 首次调用(缓存未命中):
    调用:cachedCall(“什么是人工智能?”)
    执行:实际调用AI服务,耗时2000ms
    结果:缓存结果,下次相同问题直接返回
    日志:执行AI调用(缓存未命中),消息: 什么是人工智能?
    AI调用完成,耗时: 2000ms,结果将缓存1小时

  2. 重复调用(缓存命中):
    调用:cachedCall(“什么是人工智能?”)
    执行:直接从缓存返回,耗时5ms
    结果:立即返回缓存的结果
    日志:无日志(方法体未执行)

  3. 翻译缓存示例:
    首次调用: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-EAzure OpenAI: 微软云上的OpenAI服务
Anthropic: Claude系列模型
Google Vertex AI: Gemini系列模型
Ollama: 本地部署的开源模型
百炼平台: 阿里云通义千问系列(通过OpenAI兼容接口)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值