03-OpenAI模型集成

学习目标

  • 掌握 Spring AI 集成 OpenAI 的完整流程
  • 理解 OpenAI API 的配置和使用方法
  • 能够在实际项目中集成 OpenAI 模型
  • 掌握 OpenAI 不同模型的选择和优化策略
  • 了解 OpenAI API 的成本控制和最佳实践

知识结构

OpenAI模型集成

环境准备

API密钥获取

依赖配置

连接测试

基础集成

ChatClient配置

简单对话

参数设置

模型选择

GPT-4

GPT-3.5-turbo

模型对比

高级功能

流式响应

Function Calling

Token管理

实战应用

智能客服

内容生成

代码助手

成本优化

Token计算

缓存策略

模型选择

一、项目场景引入

1.1 实际项目需求

在现代企业应用中,AI 能力已经成为提升用户体验和业务效率的关键因素。以下是几个典型的业务场景:

场景一:智能客服系统

一家电商公司需要构建智能客服系统,要求:

  • 7x24小时在线服务
  • 理解用户问题并提供准确答案
  • 支持订单查询、退换货咨询等业务
  • 能够处理复杂的多轮对话

场景二:内容生成平台
内容创作平台需要AI辅助功能:

  • 自动生成商品描述
  • 撰写营销文案
  • 优化SEO标题
  • 生成社交媒体内容

场景三:代码助手
开发团队需要提升编码效率:

  • 代码自动补全
  • Bug分析和修复建议
  • 代码审查和优化建议
  • 技术文档生成

1.2 为什么选择 OpenAI

OpenAI 提供了业界领先的大语言模型,具有以下优势:

  1. 强大的理解能力:GPT-4 能够理解复杂的上下文和意图
  2. 高质量输出:生成的内容自然流畅,符合人类表达习惯
  3. 丰富的API功能:支持对话、补全、嵌入等多种能力
  4. 持续更新:模型不断优化,性能持续提升
  5. 完善的文档:官方提供详细的API文档和最佳实践

1.3 技术挑战

在集成 OpenAI 时,我们需要解决以下问题:

挑战一:API密钥管理

  • 如何安全地存储和使用API密钥?
  • 如何在不同环境中管理不同的密钥?

挑战二:成本控制

  • OpenAI按Token计费,如何控制成本?
  • 如何选择合适的模型平衡性能和成本?

挑战三:性能优化

  • API调用延迟如何优化?
  • 如何处理高并发请求?

挑战四:错误处理

  • API调用失败如何处理?
  • 如何实现重试机制?

二、OpenAI API 基础

2.1 OpenAI API 概述

OpenAI API 是一个基于 REST 的 HTTP API,提供了访问 GPT 系列模型的能力。

核心概念:

用户请求 → Spring AI → OpenAI API → GPT模型 → 返回响应
    ↓           ↓            ↓           ↓          ↓
  输入文本   封装请求    HTTP调用    模型推理   生成文本

主要端点:

端点 功能 说明
/v1/chat/completions 对话补全 用于聊天和对话场景
/v1/completions 文本补全 用于文本生成场景
/v1/embeddings 文本嵌入 用于语义搜索和相似度计算
/v1/models 模型列表 查询可用的模型

2.2 获取 OpenAI API 密钥

步骤一:注册 OpenAI 账号

  1. 访问 https://platform.openai.com/
  2. 点击 “Sign up” 注册账号
  3. 验证邮箱并完成注册

步骤二:创建 API 密钥

  1. 登录后访问 https://platform.openai.com/api-keys
  2. 点击 “Create new secret key”
  3. 为密钥命名(如:spring-ai-dev)
  4. 复制并安全保存密钥(只显示一次)

步骤三:充值账户

  1. 访问 https://platform.openai.com/account/billing
  2. 添加支付方式
  3. 充值账户余额(建议先充值少量测试)

重要提示:

⚠️ API密钥安全注意事项:
1. 不要将密钥提交到代码仓库
2. 不要在前端代码中暴露密钥
3. 使用环境变量或配置中心管理密钥
4. 定期轮换密钥
5. 为不同环境使用不同的密钥

2.3 OpenAI 模型对比

OpenAI 提供了多个模型,各有特点:

模型 上下文长度 训练数据截止 特点 适用场景 成本
GPT-4 8K/32K 2023-04 最强理解和生成能力 复杂任务、代码生成
GPT-4-turbo 128K 2023-12 更长上下文、更快速度 长文档处理 中高
GPT-3.5-turbo 16K 2021-09 性价比高、速度快 一般对话、简单任务
GPT-3.5-turbo-16k 16K 2021-09 更长上下文 中等长度文档 中低

选择建议:

开发测试阶段:
  ├─ 使用 GPT-3.5-turbo(成本低、速度快)
  └─ 验证基本功能和流程

生产环境:
  ├─ 简单任务:GPT-3.5-turbo(客服FAQ、简单对话)
  ├─ 复杂任务:GPT-4(代码生成、复杂推理)
  └─ 长文档处理:GPT-4-turbo(文档分析、长对话)

三、Spring AI 集成 OpenAI

3.1 项目依赖配置

完整的 pom.xml 配置:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.0</version>
        <relativePath/>
    </parent>
    
    <groupId>com.example</groupId>
    <artifactId>spring-ai-openai-demo</artifactId>
    <version>1.0.0</version>
    <name>Spring AI OpenAI Integration Demo</name>
    <description>Spring AI OpenAI 集成示例项目</description>
    
    <properties>
        <java.version>17</java.version>
        <spring-ai.version>0.8.1</spring-ai.version>
    </properties>
    
    <dependencies>
        <!-- Spring Boot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <!-- Spring AI OpenAI -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
        </dependency>
        
        <!-- Lombok(简化代码) -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        
        <!-- Spring Boot Test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    
    <!-- Spring Milestone 仓库 -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
</project>

3.2 配置文件设置

application.yml 完整配置:

spring:
  application:
    name: spring-ai-openai-demo
  
  # Spring AI OpenAI 配置
  ai:
    openai:
      # API 密钥(从环境变量读取,不要硬编码)
      api-key: ${OPENAI_API_KEY}
      
      # API 基础URL(可选,默认为 https://api.openai.com)
      base-url: https://api.openai.com
      
      # Chat 模型配置
      chat:
        options:
          # 模型名称
          model: gpt-3.5-turbo
          # 温度参数(0-2,越高越随机)
          temperature: 0.7
          # 最大生成token数
          max-tokens: 1000
          # Top P 采样参数
          top-p: 1.0
          # 频率惩罚(-2.0 到 2.0)
          frequency-penalty: 0.0
          # 存在惩罚(-2.0 到 2.0)
          presence-penalty: 0.0
      
      # Embedding 模型配置
      embedding:
        options:
          model: text-embedding-ada-002

# 服务器配置
server:
  port: 8080

# 日志配置
logging:
  level:
    root: INFO
    com.example: DEBUG
    org.springframework.ai: DEBUG

环境变量配置(.env 文件):

# OpenAI API 密钥
OPENAI_API_KEY=sk-your-api-key-here

# 可选:自定义 API 基础URL(用于代理)
# OPENAI_API_BASE_URL=https://your-proxy.com/v1

为什么使用环境变量?

安全性考虑:
  ├─ 不将密钥提交到代码仓库
  ├─ 不同环境使用不同密钥
  ├─ 便于密钥轮换
  └─ 符合安全最佳实践

配置方式:
  ├─ 开发环境:.env 文件或 IDE 环境变量
  ├─ 测试环境:CI/CD 系统环境变量
  └─ 生产环境:配置中心或 K8s Secret

3.3 基础集成代码

项目结构:

spring-ai-openai-demo/
├── src/main/java/com/example/springai/
│   ├── SpringAiOpenaiDemoApplication.java    # 启动类
│   ├── controller/
│   │   └── ChatController.java               # 控制器
│   ├── service/
│   │   ├── ChatService.java                  # 服务接口
│   │   └── impl/
│   │       └── ChatServiceImpl.java          # 服务实现
│   ├── config/
│   │   └── OpenAIConfig.java                 # 配置类
│   └── dto/
│       ├── ChatRequest.java                  # 请求DTO
│       └── ChatResponse.java                 # 响应DTO
├── src/main/resources/
│   ├── application.yml                       # 配置文件
│   └── logback-spring.xml                    # 日志配置
└── pom.xml                                   # Maven配置

1. 启动类:

package com.example.springai;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Spring AI OpenAI 集成示例应用
 * 
 * @author Your Name
 * @since 1.0.0
 */
@SpringBootApplication
public class SpringAiOpenaiDemoApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(SpringAiOpenaiDemoApplication.class, args);
    }
}

2. 数据传输对象(DTO):

package com.example.springai.dto;

import lombok.Data;

/**
 * 聊天请求DTO
 */
@Data
public class ChatRequest {
    
    /**
     * 用户消息
     */
    private String message;
    
    /**
     * 模型名称(可选)
     */
    private String model;
    
    /**
     * 温度参数(可选,0-2)
     */
    private Double temperature;
    
    /**
     * 最大token数(可选)
     */
    private Integer maxTokens;
}
package com.example.springai.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 聊天响应DTO
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ChatResponse {
    
    /**
     * AI 回复内容
     */
    private String content;
    
    /**
     * 使用的模型
     */
    private String model;
    
    /**
     * 消耗的 token 数
     */
    private Integer totalTokens;
    
    /**
     * 响应时间(毫秒)
     */
    private Long responseTime;
    
    /**
     * 是否成功
     */
    private Boolean success;
    
    /**
     * 错误信息(如果有)
     */
    private String errorMessage;
}

3. 服务接口:

package com.example.springai.service;

import com.example.springai.dto.ChatRequest;
import com.example.springai.dto.ChatResponse;

/**
 * 聊天服务接口
 * 
 * @author Your Name
 * @since 1.0.0
 */
public interface ChatService {
    
    /**
     * 简单对话
     * 
     * @param message 用户消息
     * @return AI 回复
     */
    String simpleChat(String message);
    
    /**
     * 高级对话(支持参数配置)
     * 
     * @param request 聊天请求
     * @return 聊天响应
     */
    ChatResponse advancedChat(ChatRequest request);
    
    /**
     * 流式对话
     * 
     * @param message 用户消息
     * @return 流式响应
     */
    reactor.core.publisher.Flux<String> streamChat(String message);
}

4. 服务实现类:

package com.example.springai.service.impl;

import com.example.springai.dto.ChatRequest;
import com.example.springai.dto.ChatResponse;
import com.example.springai.service.ChatService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse as AiChatResponse;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

/**
 * 聊天服务实现类
 * 项目场景:智能客服系统
 * 功能:处理用户咨询,提供智能回复
 * 
 * @author Your Name
 * @since 1.0.0
 */
@Slf4j
@Service
public class ChatServiceImpl implements ChatService {
    
    private final ChatClient chatClient;
    
    /**
     * 构造函数注入 ChatClient
     * Spring AI 会自动配置并注入 ChatClient Bean
     */
    public ChatServiceImpl(ChatClient chatClient) {
        this.chatClient = chatClient;
        log.info("ChatService 初始化完成");
    }
    
    /**
     * 简单对话实现
     * 适用场景:快速问答、简单咨询
     * 
     * @param message 用户消息
     * @return AI 回复
     */
    @Override
    public String simpleChat(String message) {
        log.info("收到简单对话请求: {}", message);
        
        try {
            // 1. 创建用户消息
            Message userMessage = new UserMessage(message);
            
            // 2. 创建提示词
            Prompt prompt = new Prompt(userMessage);
            
            // 3. 调用 OpenAI API
            AiChatResponse response = chatClient.call(prompt);
            
            // 4. 提取回复内容
            String content = response.getResult().getOutput().getContent();
            
            log.info("AI 回复: {}", content);
            return content;
            
        } catch (Exception e) {
            log.error("简单对话失败", e);
            return "抱歉,我现在无法回答您的问题,请稍后再试。";
        }
    }
    
    /**
     * 高级对话实现
     * 适用场景:需要自定义参数的复杂对话
     * 
     * @param request 聊天请求
     * @return 聊天响应
     */
    @Override
    public ChatResponse advancedChat(ChatRequest request) {
        log.info("收到高级对话请求: {}", request);
        
        long startTime = System.currentTimeMillis();
        
        try {
            // 1. 构建 OpenAI 选项
            OpenAiChatOptions.Builder optionsBuilder = OpenAiChatOptions.builder();
            
            // 设置模型(如果指定)
            if (request.getModel() != null) {
                optionsBuilder.withModel(request.getModel());
            }
            
            // 设置温度参数(如果指定)
            if (request.getTemperature() != null) {
                optionsBuilder.withTemperature(request.getTemperature());
            }
            
            // 设置最大token数(如果指定)
            if (request.getMaxTokens() != null) {
                optionsBuilder.withMaxTokens(request.getMaxTokens());
            }
            
            OpenAiChatOptions options = optionsBuilder.build();
            
            // 2. 创建提示词
            Message userMessage = new UserMessage(request.getMessage());
            Prompt prompt = new Prompt(userMessage, options);
            
            // 3. 调用 OpenAI API
            AiChatResponse aiResponse = chatClient.call(prompt);
            
            // 4. 计算响应时间
            long responseTime = System.currentTimeMillis() - startTime;
            
            // 5. 构建响应对象
            ChatResponse response = ChatResponse.builder()
                    .content(aiResponse.getResult().getOutput().getContent())
                    .model(aiResponse.getMetadata().getModel())
                    .totalTokens(aiResponse.getMetadata().getUsage().getTotalTokens())
                    .responseTime(responseTime)
                    .success(true)
                    .build();
            
            log.info("高级对话成功,耗时: {}ms, tokens: {}", 
                    responseTime, response.getTotalTokens());
            
            return response;
            
        } catch (Exception e) {
            log.error("高级对话失败", e);
            
            long responseTime = System.currentTimeMillis() - startTime;
            
            return ChatResponse.builder()
                    .success(false)
                    .errorMessage(e.getMessage())
                    .responseTime(responseTime)
                    .build();
        }
    }
    
    /**
     * 流式对话实现
     * 适用场景:需要实时显示生成过程的场景
     * 
     * @param message 用户消息
     * @return 流式响应
     */
    @Override
    public Flux<String> streamChat(String message) {
        log.info("收到流式对话请求: {}", message);
        
        try {
            // 1. 创建提示词
            Prompt prompt = new Prompt(new UserMessage(message));
            
            // 2. 调用流式API
            Flux<AiChatResponse> responseFlux = chatClient.stream(prompt);
            
            // 3. 提取内容流
            return responseFlux
                    .map(response -> response.getResult().getOutput().getContent())
                    .doOnNext(content -> log.debug("流式内容: {}", content))
                    .doOnComplete(() -> log.info("流式对话完成"))
                    .doOnError(error -> log.error("流式对话失败", error));
            
        } catch (Exception e) {
            log.error("流式对话启动失败", e);
            return Flux.error(e);
        }
    }
}

5. 控制器:

package com.example.springai.controller;

import com.example.springai.dto.ChatRequest;
import com.example.springai.dto.ChatResponse;
import com.example.springai.service.ChatService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;

/**
 * 聊天控制器
 * 提供 RESTful API 接口
 * 
 * @author Your Name
 * @since 1.0.0
 */
@Slf4j
@RestController
@RequestMapping("/api/chat")
public class ChatController {
    
    private final ChatService chatService;
    
    public ChatController(ChatService chatService) {
        this.chatService = chatService;
    }
    
    /**
     * 简单对话接口
     * 
     * GET /api/chat/simple?message=你好
     * 
     * @param message 用户消息
     * @return AI 回复
     */
    @GetMapping("/simple")
    public String simpleChat(@RequestParam String message) {
        log.info("简单对话请求: {}", message);
        return chatService.simpleChat(message);
    }
    
    /**
     * 高级对话接口
     * 
     * POST /api/chat/advanced
     * Content-Type: application/json
     * 
     * {
     *   "message": "解释一下什么是Spring AI",
     *   "model": "gpt-4",
     *   "temperature": 0.7,
     *   "maxTokens": 1000
     * }
     * 
     * @param request 聊天请求
     * @return 聊天响应
     */
    @PostMapping("/advanced")
    public ChatResponse advancedChat(@RequestBody ChatRequest request) {
        log.info("高级对话请求: {}", request);
        return chatService.advancedChat(request);
    }
    
    /**
     * 流式对话接口
     * 
     * GET /api/chat/stream?message=讲个故事
     * 
     * @param message 用户消息
     * @return 流式响应
     */
    @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> streamChat(@RequestParam String message) {
        log.info("流式对话请求: {}", message);
        return chatService.streamChat(message);
    }
    
    /**
     * 健康检查接口
     * 
     * GET /api/chat/health
     * 
     * @return 健康状态
     */
    @GetMapping("/health")
    public String health() {
        return "OK";
    }
}

3.4 测试集成

启动应用并测试:

# 1. 设置环境变量
export OPENAI_API_KEY=sk-your-api-key-here

# 2. 启动应用
mvn spring-boot:run

# 3. 测试简单对话
curl "http://localhost:8080/api/chat/simple?message=你好"

# 4. 测试高级对话
curl -X POST http://localhost:8080/api/chat/advanced \
  -H "Content-Type: application/json" \
  -d '{
    "message": "解释一下什么是Spring AI",
    "model": "gpt-3.5-turbo",
    "temperature": 0.7,
    "maxTokens": 500
  }'

# 5. 测试流式对话
curl "http://localhost:8080/api/chat/stream?message=讲个短故事"

预期输出:

# 简单对话响应
你好!我是AI助手,很高兴为您服务。有什么我可以帮助您的吗?

# 高级对话响应
{
  "content": "Spring AI 是 Spring 生态系统中的一个新框架...",
  "model": "gpt-3.5-turbo",
  "totalTokens": 245,
  "responseTime": 1523,
  "success": true,
  "errorMessage": null
}

# 流式对话响应(逐字输出)
从前
有一个
小村庄
...

四、实战应用场景

4.1 场景一:智能客服系统

业务需求:
构建一个电商平台的智能客服系统,能够:

  • 回答常见问题(订单查询、退换货政策等)
  • 理解用户意图并提供准确答案
  • 支持多轮对话
  • 记录对话历史

完整实现代码:

package com.example.springai.service.impl;

import com.example.springai.dto.ChatMessage;
import com.example.springai.dto.CustomerServiceRequest;
import com.example.springai.dto.CustomerServiceResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 智能客服服务
 * 项目场景:电商平台客服系统
 * 功能:处理用户咨询、订单查询、退换货等业务
 * 
 * @author Your Name
 * @since 1.0.0
 */
@Slf4j
@Service
public class CustomerServiceImpl {
    
    private final ChatClient chatClient;
    
    // 存储用户对话历史(实际项目中应使用 Redis 或数据库)
    private final Map<String, List<ChatMessage>> conversationHistory = 
            new ConcurrentHashMap<>();
    
    public CustomerServiceImpl(ChatClient chatClient) {
        this.chatClient = chatClient;
    }
    
    /**
     * 处理客服咨询
     * 
     * @param request 客服请求
     * @return 客服响应
     */
    public CustomerServiceResponse handleCustomerQuery(CustomerServiceRequest request) {
        log.info("处理客服咨询 - 用户ID: {}, 消息: {}", 
                request.getUserId(), request.getMessage());
        
        try {
            // 1. 获取或创建对话历史
            List<ChatMessage> history = conversationHistory.computeIfAbsent(
                    request.getUserId(), k -> new ArrayList<>());
            
            // 2. 构建系统提示词(定义客服角色和规则)
            String systemPrompt = buildSystemPrompt();
            
            // 3. 构建完整的对话上下文
            List<Message> messages = new ArrayList<>();
            messages.add(new SystemMessage(systemPrompt));
            
            // 添加历史对话(最近5轮)
            int historySize = Math.min(history.size(), 5);
            for (int i = history.size() - historySize; i < history.size(); i++) {
                ChatMessage msg = history.get(i);
                if ("user".equals(msg.getRole())) {
                    messages.add(new UserMessage(msg.getContent()));
                } else {
                    messages.add(new SystemMessage(msg.getContent()));
                }
            }
            
            // 添加当前用户消息
            messages.add(new UserMessage(request.getMessage()));
            
            // 4. 配置 OpenAI 选项
            OpenAiChatOptions options = OpenAiChatOptions.builder()
                    .withModel("gpt-3.5-turbo")
                    .withTemperature(0.7)
                    .withMaxTokens(500)
                    .build();
            
            // 5. 调用 OpenAI API
            Prompt prompt = new Prompt(messages, options);
            ChatResponse response = chatClient.call(prompt);
            
            String aiReply = response.getResult().getOutput().getContent();
            
            // 6. 保存对话历史
            history.add(new ChatMessage("user", request.getMessage()));
            history.add(new ChatMessage("assistant", aiReply));
            
            // 7. 构建响应
            return CustomerServiceResponse.builder()
                    .userId(request.getUserId())
                    .reply(aiReply)
                    .conversationId(request.getUserId())
                    .timestamp(System.currentTimeMillis())
                    .success(true)
                    .build();
            
        } catch (Exception e) {
            log.error("处理客服咨询失败", e);
            return CustomerServiceResponse.builder()
                    .userId(request.getUserId())
                    .reply("抱歉,系统繁忙,请稍后再试。")
                    .success(false)
                    .errorMessage(e.getMessage())
                    .build();
        }
    }
    
    /**
     * 构建系统提示词
     * 定义客服的角色、能力和规则
     */
    private String buildSystemPrompt() {
        return """
                你是一个专业的电商平台客服助手,名字叫"小智"。
                
                你的职责:
                1. 友好、耐心地回答用户问题
                2. 提供准确的订单、物流、退换货信息
                3. 解决用户的疑问和投诉
                4. 引导用户完成购物流程
                
                回答规则:
                1. 使用礼貌、专业的语言
                2. 回答要简洁明了,不超过200字
                3. 如果不确定答案,建议用户联系人工客服
                4. 对于订单查询,提示用户提供订单号
                5. 对于退换货,说明需要在7天内申请
                
                常见问题参考:
                - 订单查询:需要订单号,可在"我的订单"中查看
                - 物流查询:订单发货后可在订单详情查看物流信息
                - 退换货:7天无理由退换货,商品需保持完好
                - 支付问题:支持支付宝、微信、银行卡支付
                - 优惠券:在结算时自动抵扣,注意使用期限
                """;
    }
    
    /**
     * 清除用户对话历史
     * 
     * @param userId 用户ID
     */
    public void clearConversationHistory(String userId) {
        conversationHistory.remove(userId);
        log.info("清除用户对话历史: {}", userId);
    }
}

DTO 定义:

package com.example.springai.dto;

import lombok.Data;

/**
 * 客服请求DTO
 */
@Data
public class CustomerServiceRequest {
    private String userId;
    private String message;
    private String sessionId;
}

/**
 * 客服响应DTO
 */
@Data
@Builder
public class CustomerServiceResponse {
    private String userId;
    private String reply;
    private String conversationId;
    private Long timestamp;
    private Boolean success;
    private String errorMessage;
}

/**
 * 对话消息DTO
 */
@Data
@AllArgsConstructor
public class ChatMessage {
    private String role;      // user 或 assistant
    private String content;
}

控制器:

package com.example.springai.controller;

import com.example.springai.dto.CustomerServiceRequest;
import com.example.springai.dto.CustomerServiceResponse;
import com.example.springai.service.impl.CustomerServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

/**
 * 客服控制器
 */
@Slf4j
@RestController
@RequestMapping("/api/customer-service")
public class CustomerServiceController {
    
    private final CustomerServiceImpl customerService;
    
    public CustomerServiceController(CustomerServiceImpl customerService) {
        this.customerService = customerService;
    }
    
    @PostMapping("/query")
    public CustomerServiceResponse handleQuery(
            @RequestBody CustomerServiceRequest request) {
        return customerService.handleCustomerQuery(request);
    }
    
    @DeleteMapping("/history/{userId}")
    public void clearHistory(@PathVariable String userId) {
        customerService.clearConversationHistory(userId);
    }
}

测试示例:

# 第一轮对话
curl -X POST http://localhost:8080/api/customer-service/query \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "user123",
    "message": "我想查询订单"
  }'

# 响应
{
  "userId": "user123",
  "reply": "您好!我可以帮您查询订单。请提供您的订单号,订单号可以在"我的订单"页面找到,格式类似:202401010001。",
  "conversationId": "user123",
  "timestamp": 1704067200000,
  "success": true
}

# 第二轮对话(带上下文)
curl -X POST http://localhost:8080/api/customer-service/query \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "user123",
    "message": "订单号是202401010001"
  }'

# 响应
{
  "userId": "user123",
  "reply": "好的,我帮您查询订单202401010001。根据系统显示,您的订单已发货,预计3-5天送达。您可以在订单详情页面查看实时物流信息。",
  "conversationId": "user123",
  "timestamp": 1704067260000,
  "success": true
}

4.2 场景二:内容生成系统

业务需求:
为内容创作平台提供AI辅助功能:

  • 生成商品描述
  • 撰写营销文案
  • 优化SEO标题
  • 生成社交媒体内容

完整实现代码:

package com.example.springai.service.impl;

import com.example.springai.dto.ContentGenerationRequest;
import com.example.springai.dto.ContentGenerationResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 内容生成服务
 * 项目场景:内容创作平台
 * 功能:AI辅助内容生成
 * 
 * @author Your Name
 * @since 1.0.0
 */
@Slf4j
@Service
public class ContentGenerationService {
    
    private final ChatClient chatClient;
    
    public ContentGenerationService(ChatClient chatClient) {
        this.chatClient = chatClient;
    }
    
    /**
     * 生成商品描述
     * 
     * @param request 内容生成请求
     * @return 生成的内容
     */
    public ContentGenerationResponse generateProductDescription(
            ContentGenerationRequest request) {
        log.info("生成商品描述: {}", request.getProductName());
        
        try {
            // 1. 构建系统提示词
            String systemPrompt = """
                    你是一个专业的电商文案撰写专家。
                    你的任务是根据商品信息生成吸引人的商品描述。
                    
                    要求:
                    1. 突出商品的核心卖点和优势
                    2. 使用生动、具体的语言描述
                    3. 包含使用场景和用户收益
                    4. 字数控制在200-300字
                    5. 语言要专业但易懂
                    """;
            
            // 2. 构建用户提示词
            String userPrompt = String.format("""
                    请为以下商品生成描述:
                    
                    商品名称:%s
                    商品类别:%s
                    主要特点:%s
                    目标用户:%s
                    价格区间:%s
                    
                    请生成一段吸引人的商品描述。
                    """,
                    request.getProductName(),
                    request.getCategory(),
                    String.join("、", request.getFeatures()),
                    request.getTargetAudience(),
                    request.getPriceRange());
            
            // 3. 配置选项
            OpenAiChatOptions options = OpenAiChatOptions.builder()
                    .withModel("gpt-3.5-turbo")
                    .withTemperature(0.8)  // 较高的创造性
                    .withMaxTokens(500)
                    .build();
            
            // 4. 调用 API
            Prompt prompt = new Prompt(
                    List.of(new SystemMessage(systemPrompt), 
                           new UserMessage(userPrompt)),
                    options);
            
            ChatResponse response = chatClient.call(prompt);
            String content = response.getResult().getOutput().getContent();
            
            // 5. 构建响应
            return ContentGenerationResponse.builder()
                    .content(content)
                    .contentType("product_description")
                    .wordCount(content.length())
                    .success(true)
                    .build();
            
        } catch (Exception e) {
            log.error("生成商品描述失败", e);
            return ContentGenerationResponse.builder()
                    .success(false)
                    .errorMessage(e.getMessage())
                    .build();
        }
    }
    
    /**
     * 生成营销文案
     * 
     * @param request 内容生成请求
     * @return 生成的文案
     */
    public ContentGenerationResponse generateMarketingCopy(
            ContentGenerationRequest request) {
        log.info("生成营销文案: {}", request.getCampaignName());
        
        try {
            String systemPrompt = """
                    你是一个资深的营销文案策划师。
                    你擅长创作有感染力、能激发购买欲望的营销文案。
                    
                    要求:
                    1. 标题要吸引眼球,激发好奇心
                    2. 正文要突出产品价值和用户收益
                    3. 使用情感化的语言建立连接
                    4. 包含明确的行动号召(CTA)
                    5. 整体字数控制在150-200字
                    """;
            
            String userPrompt = String.format("""
                    请为以下营销活动创作文案:
                    
                    活动名称:%s
                    活动主题:%s
                    目标用户:%s
                    核心卖点:%s
                    优惠信息:%s
                    
                    请生成包含标题和正文的营销文案。
                    """,
                    request.getCampaignName(),
                    request.getTheme(),
                    request.getTargetAudience(),
                    String.join("、", request.getSellingPoints()),
                    request.getPromotion());
            
            OpenAiChatOptions options = OpenAiChatOptions.builder()
                    .withModel("gpt-3.5-turbo")
                    .withTemperature(0.9)  // 更高的创造性
                    .withMaxTokens(400)
                    .build();
            
            Prompt prompt = new Prompt(
                    List.of(new SystemMessage(systemPrompt), 
                           new UserMessage(userPrompt)),
                    options);
            
            ChatResponse response = chatClient.call(prompt);
            String content = response.getResult().getOutput().getContent();
            
            return ContentGenerationResponse.builder()
                    .content(content)
                    .contentType("marketing_copy")
                    .wordCount(content.length())
                    .success(true)
                    .build();
            
        } catch (Exception e) {
            log.error("生成营销文案失败", e);
            return ContentGenerationResponse.builder()
                    .success(false)
                    .errorMessage(e.getMessage())
                    .build();
        }
    }
    
    /**
     * 优化SEO标题
     * 
     * @param originalTitle 原始标题
     * @param keywords 关键词列表
     * @return 优化后的标题
     */
    public List<String> optimizeSeoTitle(String originalTitle, List<String> keywords) {
        log.info("优化SEO标题: {}", originalTitle);
        
        try {
            String systemPrompt = """
                    你是一个SEO优化专家。
                    你的任务是优化标题,提高搜索引擎排名和点击率。
                    
                    要求:
                    1. 自然融入关键词
                    2. 标题长度控制在30-60字符
                    3. 吸引用户点击
                    4. 准确描述内容
                    5. 生成3个不同风格的标题供选择
                    """;
            
            String userPrompt = String.format("""
                    原始标题:%s
                    目标关键词:%s
                    
                    请生成3个优化后的SEO标题,每个标题单独一行。
                    """,
                    originalTitle,
                    String.join("、", keywords));
            
            OpenAiChatOptions options = OpenAiChatOptions.builder()
                    .withModel("gpt-3.5-turbo")
                    .withTemperature(0.7)
                    .withMaxTokens(300)
                    .build();
            
            Prompt prompt = new Prompt(
                    List.of(new SystemMessage(systemPrompt), 
                           new UserMessage(userPrompt)),
                    options);
            
            ChatResponse response = chatClient.call(prompt);
            String content = response.getResult().getOutput().getContent();
            
            // 分割成多个标题
            return List.of(content.split("\n"))
                    .stream()
                    .map(String::trim)
                    .filter(s -> !s.isEmpty())
                    .toList();
            
        } catch (Exception e) {
            log.error("优化SEO标题失败", e);
            return List.of(originalTitle);
        }
    }
}

DTO 定义:

package com.example.springai.dto;

import lombok.Data;
import lombok.Builder;
import java.util.List;

/**
 * 内容生成请求DTO
 */
@Data
public class ContentGenerationRequest {
    // 商品描述相关
    private String productName;
    private String category;
    private List<String> features;
    private String targetAudience;
    private String priceRange;
    
    // 营销文案相关
    private String campaignName;
    private String theme;
    private List<String> sellingPoints;
    private String promotion;
}

/**
 * 内容生成响应DTO
 */
@Data
@Builder
public class ContentGenerationResponse {
    private String content;
    private String contentType;
    private Integer wordCount;
    private Boolean success;
    private String errorMessage;
}

测试示例:

# 生成商品描述
curl -X POST http://localhost:8080/api/content/product-description \
  -H "Content-Type: application/json" \
  -d '{
    "productName": "智能运动手表",
    "category": "智能穿戴",
    "features": ["心率监测", "GPS定位", "50米防水", "7天续航"],
    "targetAudience": "运动爱好者",
    "priceRange": "1000-2000元"
  }'

# 响应示例
{
  "content": "这款智能运动手表是运动爱好者的理想伴侣。配备专业级心率监测功能,实时追踪您的运动状态...",
  "contentType": "product_description",
  "wordCount": 256,
  "success": true
}

4.3 场景三:代码助手

业务需求:
为开发团队提供AI代码助手:

  • 代码审查和优化建议
  • Bug分析和修复建议
  • 代码注释生成
  • 单元测试生成

完整实现代码:

package com.example.springai.service.impl;

import com.example.springai.dto.CodeReviewRequest;
import com.example.springai.dto.CodeReviewResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 代码助手服务
 * 项目场景:开发团队协作平台
 * 功能:代码审查、优化建议、Bug分析
 * 
 * @author Your Name
 * @since 1.0.0
 */
@Slf4j
@Service
public class CodeAssistantService {
    
    private final ChatClient chatClient;
    
    public CodeAssistantService(ChatClient chatClient) {
        this.chatClient = chatClient;
    }
    
    /**
     * 代码审查
     * 
     * @param request 代码审查请求
     * @return 审查结果
     */
    public CodeReviewResponse reviewCode(CodeReviewRequest request) {
        log.info("开始代码审查 - 语言: {}", request.getLanguage());
        
        try {
            // 1. 构建系统提示词
            String systemPrompt = """
                    你是一个资深的代码审查专家,精通多种编程语言和最佳实践。
                    
                    审查重点:
                    1. 代码质量:可读性、可维护性、复杂度
                    2. 性能问题:算法效率、资源使用
                    3. 安全隐患:SQL注入、XSS、敏感信息泄露
                    4. 最佳实践:设计模式、编码规范
                    5. 潜在Bug:空指针、边界条件、并发问题
                    
                    输出格式:
                    1. 总体评价(1-2句话)
                    2. 发现的问题(按严重程度排序)
                    3. 优化建议(具体可行)
                    4. 改进后的代码示例(如果需要)
                    """;
            
            // 2. 构建用户提示词
            String userPrompt = String.format("""
                    请审查以下 %s 代码:
                    
                    ```%s
                    %s
                    ```
                    
                    代码说明:%s
                    
                    请提供详细的审查意见。
                    """,
                    request.getLanguage(),
                    request.getLanguage(),
                    request.getCode(),
                    request.getDescription());
            
            // 3. 配置选项(使用 GPT-4 获得更好的代码理解能力)
            OpenAiChatOptions options = OpenAiChatOptions.builder()
                    .withModel("gpt-4")
                    .withTemperature(0.3)  // 较低的温度,更准确
                    .withMaxTokens(2000)
                    .build();
            
            // 4. 调用 API
            Prompt prompt = new Prompt(
                    List.of(new SystemMessage(systemPrompt), 
                           new UserMessage(userPrompt)),
                    options);
            
            ChatResponse response = chatClient.call(prompt);
            String reviewResult = response.getResult().getOutput().getContent();
            
            // 5. 构建响应
            return CodeReviewResponse.builder()
                    .reviewResult(reviewResult)
                    .language(request.getLanguage())
                    .success(true)
                    .build();
            
        } catch (Exception e) {
            log.error("代码审查失败", e);
            return CodeReviewResponse.builder()
                    .success(false)
                    .errorMessage(e.getMessage())
                    .build();
        }
    }
    
    /**
     * Bug分析
     * 
     * @param errorMessage 错误信息
     * @param code 相关代码
     * @return 分析结果和修复建议
     */
    public String analyzeBug(String errorMessage, String code) {
        log.info("分析Bug: {}", errorMessage);
        
        try {
            String systemPrompt = """
                    你是一个经验丰富的调试专家。
                    你的任务是分析错误信息和代码,找出问题根源并提供修复方案。
                    
                    分析步骤:
                    1. 理解错误信息的含义
                    2. 定位问题代码位置
                    3. 分析问题产生的原因
                    4. 提供具体的修复方案
                    5. 给出修复后的代码示例
                    """;
            
            String userPrompt = String.format("""
                    错误信息:
                    %s
                    
                    相关代码:
                    ```java
                    %s
                    ```
                    
                    请分析这个Bug并提供修复方案。
                    """,
                    errorMessage,
                    code);
            
            OpenAiChatOptions options = OpenAiChatOptions.builder()
                    .withModel("gpt-4")
                    .withTemperature(0.2)
                    .withMaxTokens(1500)
                    .build();
            
            Prompt prompt = new Prompt(
                    List.of(new SystemMessage(systemPrompt), 
                           new UserMessage(userPrompt)),
                    options);
            
            ChatResponse response = chatClient.call(prompt);
            return response.getResult().getOutput().getContent();
            
        } catch (Exception e) {
            log.error("Bug分析失败", e);
            return "分析失败:" + e.getMessage();
        }
    }
    
    /**
     * 生成代码注释
     * 
     * @param code 代码
     * @param language 编程语言
     * @return 带注释的代码
     */
    public String generateComments(String code, String language) {
        log.info("生成代码注释 - 语言: {}", language);
        
        try {
            String systemPrompt = """
                    你是一个代码文档专家。
                    你的任务是为代码添加清晰、准确的注释。
                    
                    注释要求:
                    1. 类和方法要有完整的文档注释
                    2. 复杂逻辑要有行内注释说明
                    3. 注释要简洁明了,不要废话
                    4. 使用标准的文档注释格式
                    5. 保持原有代码不变,只添加注释
                    """;
            
            String userPrompt = String.format("""
                    请为以下 %s 代码添加注释:
                    
                    ```%s
                    %s
                    ```
                    
                    返回完整的带注释的代码。
                    """,
                    language,
                    language,
                    code);
            
            OpenAiChatOptions options = OpenAiChatOptions.builder()
                    .withModel("gpt-3.5-turbo")
                    .withTemperature(0.3)
                    .withMaxTokens(2000)
                    .build();
            
            Prompt prompt = new Prompt(
                    List.of(new SystemMessage(systemPrompt), 
                           new UserMessage(userPrompt)),
                    options);
            
            ChatResponse response = chatClient.call(prompt);
            return response.getResult().getOutput().getContent();
            
        } catch (Exception e) {
            log.error("生成注释失败", e);
            return code;
        }
    }
    
    /**
     * 生成单元测试
     * 
     * @param code 要测试的代码
     * @param language 编程语言
     * @return 单元测试代码
     */
    public String generateUnitTest(String code, String language) {
        log.info("生成单元测试 - 语言: {}", language);
        
        try {
            String systemPrompt = """
                    你是一个测试工程师,擅长编写高质量的单元测试。
                    
                    测试要求:
                    1. 覆盖正常情况和边界情况
                    2. 测试异常处理逻辑
                    3. 使用合适的测试框架(JUnit、Mockito等)
                    4. 测试方法命名清晰,表达测试意图
                    5. 包含必要的断言和验证
                    """;
            
            String userPrompt = String.format("""
                    请为以下 %s 代码生成单元测试:
                    
                    ```%s
                    %s
                    ```
                    
                    返回完整的测试类代码。
                    """,
                    language,
                    language,
                    code);
            
            OpenAiChatOptions options = OpenAiChatOptions.builder()
                    .withModel("gpt-4")
                    .withTemperature(0.3)
                    .withMaxTokens(2000)
                    .build();
            
            Prompt prompt = new Prompt(
                    List.of(new SystemMessage(systemPrompt), 
                           new UserMessage(userPrompt)),
                    options);
            
            ChatResponse response = chatClient.call(prompt);
            return response.getResult().getOutput().getContent();
            
        } catch (Exception e) {
            log.error("生成单元测试失败", e);
            return "// 生成失败:" + e.getMessage();
        }
    }
}

DTO 定义:

package com.example.springai.dto;

import lombok.Data;
import lombok.Builder;

/**
 * 代码审查请求DTO
 */
@Data
public class CodeReviewRequest {
    private String code;
    private String language;
    private String description;
}

/**
 * 代码审查响应DTO
 */
@Data
@Builder
public class CodeReviewResponse {
    private String reviewResult;
    private String language;
    private Boolean success;
    private String errorMessage;
}

测试示例:

# 代码审查
curl -X POST http://localhost:8080/api/code-assistant/review \
  -H "Content-Type: application/json" \
  -d '{
    "code": "public String getUserName(User user) { return user.getName(); }",
    "language": "java",
    "description": "获取用户名称的方法"
  }'

# Bug分析
curl -X POST http://localhost:8080/api/code-assistant/analyze-bug \
  -H "Content-Type: application/json" \
  -d '{
    "errorMessage": "NullPointerException at line 15",
    "code": "String name = user.getName().toUpperCase();"
  }'

五、高级配置与优化

5.1 动态模型切换

在实际项目中,我们可能需要根据不同场景动态切换模型。

配置类:

package com.example.springai.config;

import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * OpenAI 配置类
 * 支持多模型配置和动态切换
 * 
 * @author Your Name
 * @since 1.0.0
 */
@Configuration
public class OpenAIConfig {
    
    @Value("${spring.ai.openai.api-key}")
    private String apiKey;
    
    @Value("${spring.ai.openai.base-url:https://api.openai.com}")
    private String baseUrl;
    
    /**
     * 配置 OpenAI API 客户端
     */
    @Bean
    public OpenAiApi openAiApi() {
        return new OpenAiApi(baseUrl, apiKey);
    }
    
    /**
     * 配置默认的 ChatClient(使用 GPT-3.5-turbo)
     */
    @Bean
    public OpenAiChatClient defaultChatClient(OpenAiApi openAiApi) {
        OpenAiChatOptions options = OpenAiChatOptions.builder()
                .withModel("gpt-3.5-turbo")
                .withTemperature(0.7)
                .withMaxTokens(1000)
                .build();
        
        return new OpenAiChatClient(openAiApi, options);
    }
    
    /**
     * 配置高级 ChatClient(使用 GPT-4)
     */
    @Bean("gpt4ChatClient")
    public OpenAiChatClient gpt4ChatClient(OpenAiApi openAiApi) {
        OpenAiChatOptions options = OpenAiChatOptions.builder()
                .withModel("gpt-4")
                .withTemperature(0.7)
                .withMaxTokens(2000)
                .build();
        
        return new OpenAiChatClient(openAiApi, options);
    }
    
    /**
     * 配置快速 ChatClient(使用 GPT-3.5-turbo,更低延迟)
     */
    @Bean("fastChatClient")
    public OpenAiChatClient fastChatClient(OpenAiApi openAiApi) {
        OpenAiChatOptions options = OpenAiChatOptions.builder()
                .withModel("gpt-3.5-turbo")
                .withTemperature(0.5)
                .withMaxTokens(500)
                .build();
        
        return new OpenAiChatClient(openAiApi, options);
    }
}

模型选择服务:

package com.example.springai.service;

import org.springframework.ai.chat.ChatClient;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

/**
 * 模型选择服务
 * 根据任务类型选择合适的模型
 * 
 * @author Your Name
 * @since 1.0.0
 */
@Service
public class ModelSelectorService {
    
    private final ChatClient defaultClient;
    private final ChatClient gpt4Client;
    private final ChatClient fastClient;
    
    public ModelSelectorService(
            ChatClient defaultClient,
            @Qualifier("gpt4ChatClient") ChatClient gpt4Client,
            @Qualifier("fastChatClient") ChatClient fastClient) {
        this.defaultClient = defaultClient;
        this.gpt4Client = gpt4Client;
        this.fastClient = fastClient;
    }
    
    /**
     * 根据任务类型选择模型
     * 
     * @param taskType 任务类型
     * @return 对应的 ChatClient
     */
    public ChatClient selectModel(TaskType taskType) {
        return switch (taskType) {
            case SIMPLE_QA -> fastClient;           // 简单问答用快速模型
            case CODE_REVIEW -> gpt4Client;         // 代码审查用GPT-4
            case CONTENT_GENERATION -> defaultClient; // 内容生成用默认模型
            case COMPLEX_REASONING -> gpt4Client;   // 复杂推理用GPT-4
            default -> defaultClient;
        };
    }
    
    /**
     * 任务类型枚举
     */
    public enum TaskType {
        SIMPLE_QA,           // 简单问答
        CODE_REVIEW,         // 代码审查
        CONTENT_GENERATION,  // 内容生成
        COMPLEX_REASONING    // 复杂推理
    }
}

5.2 请求重试机制

为了提高系统的可靠性,我们需要实现请求重试机制。

package com.example.springai.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

/**
 * 带重试机制的 Chat 服务
 * 
 * @author Your Name
 * @since 1.0.0
 */
@Slf4j
@Service
public class RetryableChatService {
    
    private final ChatClient chatClient;
    
    public RetryableChatService(ChatClient chatClient) {
        this.chatClient = chatClient;
    }
    
    /**
     * 带重试的 API 调用
     * 
     * @param prompt 提示词
     * @return 响应
     */
    @Retryable(
            value = {Exception.class},
            maxAttempts = 3,
            backoff = @Backoff(delay = 1000, multiplier = 2)
    )
    public ChatResponse callWithRetry(Prompt prompt) {
        log.info("调用 OpenAI API(支持重试)");
        
        try {
            return chatClient.call(prompt);
        } catch (Exception e) {
            log.warn("API 调用失败,准备重试: {}", e.getMessage());
            throw e;
        }
    }
}

启用重试配置:

package com.example.springai.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.retry.annotation.EnableRetry;

/**
 * 重试配置
 */
@Configuration
@EnableRetry
public class RetryConfig {
}

pom.xml 添加依赖:

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
</dependency>

5.3 响应缓存

为了降低成本和提高响应速度,我们可以缓存相同请求的响应。

package com.example.springai.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

/**
 * 带缓存的 Chat 服务
 * 
 * @author Your Name
 * @since 1.0.0
 */
@Slf4j
@Service
public class CachedChatService {
    
    private final ChatClient chatClient;
    
    public CachedChatService(ChatClient chatClient) {
        this.chatClient = chatClient;
    }
    
    /**
     * 带缓存的简单对话
     * 相同的问题会直接返回缓存结果
     * 
     * @param message 用户消息
     * @return AI 回复
     */
    @Cacheable(value = "chatResponses", key = "#message")
    public String chatWithCache(String message) {
        log.info("调用 OpenAI API(未命中缓存): {}", message);
        
        Prompt prompt = new Prompt(message);
        ChatResponse response = chatClient.call(prompt);
        
        return response.getResult().getOutput().getContent();
    }
}

缓存配置:

package com.example.springai.config;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 缓存配置
 */
@Configuration
@EnableCaching
public class CacheConfig {
    
    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager("chatResponses");
    }
}

使用 Redis 缓存(生产环境推荐):

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
# application.yml
spring:
  redis:
    host: localhost
    port: 6379
    password: ${REDIS_PASSWORD}
  cache:
    type: redis
    redis:
      time-to-live: 3600000  # 缓存1小时
package com.example.springai.config;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

/**
 * Redis 缓存配置
 */
@Configuration
@EnableCaching
public class RedisCacheConfig {
    
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofHours(1))  // 缓存1小时
                .serializeKeysWith(
                        RedisSerializationContext.SerializationPair.fromSerializer(
                                new StringRedisSerializer()))
                .serializeValuesWith(
                        RedisSerializationContext.SerializationPair.fromSerializer(
                                new GenericJackson2JsonRedisSerializer()));
        
        return RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(config)
                .build();
    }
}

5.4 Token 使用监控

监控 Token 使用情况对于成本控制至关重要。

package com.example.springai.service;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.stereotype.Service;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Token 使用监控服务
 * 
 * @author Your Name
 * @since 1.0.0
 */
@Slf4j
@Service
public class TokenMonitorService {
    
    private final ChatClient chatClient;
    private final TokenUsageStats stats = new TokenUsageStats();
    
    public TokenMonitorService(ChatClient chatClient) {
        this.chatClient = chatClient;
    }
    
    /**
     * 带监控的 API 调用
     * 
     * @param prompt 提示词
     * @return 响应
     */
    public ChatResponse callWithMonitoring(Prompt prompt) {
        long startTime = System.currentTimeMillis();
        
        try {
            ChatResponse response = chatClient.call(prompt);
            
            // 记录 Token 使用情况
            int promptTokens = response.getMetadata().getUsage().getPromptTokens();
            int completionTokens = response.getMetadata().getUsage().getCompletionTokens();
            int totalTokens = response.getMetadata().getUsage().getTotalTokens();
            
            stats.addRequest(promptTokens, completionTokens, totalTokens);
            
            long duration = System.currentTimeMillis() - startTime;
            
            log.info("API调用完成 - Prompt Tokens: {}, Completion Tokens: {}, " +
                    "Total Tokens: {}, 耗时: {}ms",
                    promptTokens, completionTokens, totalTokens, duration);
            
            return response;
            
        } catch (Exception e) {
            stats.incrementFailures();
            log.error("API调用失败", e);
            throw e;
        }
    }
    
    /**
     * 获取使用统计
     * 
     * @return 统计信息
     */
    public TokenUsageStats getStats() {
        return stats;
    }
    
    /**
     * 重置统计
     */
    public void resetStats() {
        stats.reset();
        log.info("Token使用统计已重置");
    }
    
    /**
     * Token 使用统计
     */
    @Data
    public static class TokenUsageStats {
        private final AtomicInteger totalRequests = new AtomicInteger(0);
        private final AtomicInteger failedRequests = new AtomicInteger(0);
        private final AtomicLong totalPromptTokens = new AtomicLong(0);
        private final AtomicLong totalCompletionTokens = new AtomicLong(0);
        private final AtomicLong totalTokens = new AtomicLong(0);
        
        public void addRequest(int promptTokens, int completionTokens, int total) {
            totalRequests.incrementAndGet();
            totalPromptTokens.addAndGet(promptTokens);
            totalCompletionTokens.addAndGet(completionTokens);
            totalTokens.addAndGet(total);
        }
        
        public void incrementFailures() {
            failedRequests.incrementAndGet();
        }
        
        public void reset() {
            totalRequests.set(0);
            failedRequests.set(0);
            totalPromptTokens.set(0);
            totalCompletionTokens.set(0);
            totalTokens.set(0);
        }
        
        /**
         * 计算预估成本(基于 GPT-3.5-turbo 定价)
         * 输入:$0.0015 / 1K tokens
         * 输出:$0.002 / 1K tokens
         */
        public double getEstimatedCost() {
            double promptCost = (totalPromptTokens.get() / 1000.0) * 0.0015;
            double completionCost = (totalCompletionTokens.get() / 1000.0) * 0.002;
            return promptCost + completionCost;
        }
        
        @Override
        public String toString() {
            return String.format(
                    "总请求数: %d, 失败数: %d, 总Tokens: %d, " +
                    "Prompt Tokens: %d, Completion Tokens: %d, 预估成本: $%.4f",
                    totalRequests.get(),
                    failedRequests.get(),
                    totalTokens.get(),
                    totalPromptTokens.get(),
                    totalCompletionTokens.get(),
                    getEstimatedCost()
            );
        }
    }
}

监控端点:

package com.example.springai.controller;

import com.example.springai.service.TokenMonitorService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

/**
 * 监控控制器
 */
@Slf4j
@RestController
@RequestMapping("/api/monitor")
public class MonitorController {
    
    private final TokenMonitorService monitorService;
    
    public MonitorController(TokenMonitorService monitorService) {
        this.monitorService = monitorService;
    }
    
    /**
     * 获取 Token 使用统计
     */
    @GetMapping("/token-usage")
    public TokenMonitorService.TokenUsageStats getTokenUsage() {
        return monitorService.getStats();
    }
    
    /**
     * 重置统计
     */
    @PostMapping("/reset-stats")
    public String resetStats() {
        monitorService.resetStats();
        return "统计已重置";
    }
}

六、成本优化策略

6.1 Token 计算与优化

Token 计算规则:

Token 计算:
  ├─ 英文:约 4 个字符 = 1 token
  ├─ 中文:约 1.5-2 个字符 = 1 token
  ├─ 代码:约 3-4 个字符 = 1 token
  └─ 特殊字符:通常 1 个字符 = 1 token

成本计算(GPT-3.5-turbo):
  ├─ 输入:$0.0015 / 1K tokens
  ├─ 输出:$0.002 / 1K tokens
  └─ 示例:1000次对话,平均500 tokens = $0.75-$1.00

成本计算(GPT-4):
  ├─ 输入:$0.03 / 1K tokens
  ├─ 输出:$0.06 / 1K tokens
  └─ 示例:1000次对话,平均500 tokens = $15-$30

优化策略:

package com.example.springai.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * Token 优化服务
 * 
 * @author Your Name
 * @since 1.0.0
 */
@Slf4j
@Service
public class TokenOptimizationService {
    
    /**
     * 优化提示词,减少 Token 使用
     * 
     * @param prompt 原始提示词
     * @return 优化后的提示词
     */
    public String optimizePrompt(String prompt) {
        // 1. 移除多余的空格和换行
        String optimized = prompt.replaceAll("\\s+", " ").trim();
        
        // 2. 简化重复的说明
        optimized = optimized.replaceAll("请你|麻烦你|能否", "");
        
        // 3. 使用简洁的表达
        optimized = optimized.replace("非常感谢", "谢谢");
        optimized = optimized.replace("尽可能", "尽量");
        
        log.debug("提示词优化 - 原始长度: {}, 优化后长度: {}", 
                prompt.length(), optimized.length());
        
        return optimized;
    }
    
    /**
     * 截断对话历史,保留最近的N轮对话
     * 
     * @param history 完整历史
     * @param maxRounds 最大轮数
     * @return 截断后的历史
     */
    public <T> List<T> truncateHistory(List<T> history, int maxRounds) {
        if (history.size() <= maxRounds * 2) {
            return history;
        }
        
        // 保留最近的 N 轮对话(每轮包含用户消息和AI回复)
        int startIndex = history.size() - (maxRounds * 2);
        List<T> truncated = history.subList(startIndex, history.size());
        
        log.debug("对话历史截断 - 原始: {} 条, 保留: {} 条", 
                history.size(), truncated.size());
        
        return truncated;
    }
    
    /**
     * 估算文本的 Token 数量
     * 
     * @param text 文本
     * @return 估算的 Token 数
     */
    public int estimateTokens(String text) {
        // 简单估算:中文按2字符/token,英文按4字符/token
        int chineseChars = text.replaceAll("[^\\u4e00-\\u9fa5]", "").length();
        int otherChars = text.length() - chineseChars;
        
        int tokens = (chineseChars / 2) + (otherChars / 4);
        
        log.debug("Token估算 - 文本长度: {}, 估算Tokens: {}", text.length(), tokens);
        
        return tokens;
    }
}

6.2 成本控制最佳实践

1. 选择合适的模型

/**
 * 根据任务复杂度选择模型
 */
public String selectModelByComplexity(String task) {
    // 简单任务:FAQ、简单对话
    if (isSimpleTask(task)) {
        return "gpt-3.5-turbo";  // 成本低
    }
    
    // 中等任务:内容生成、翻译
    if (isMediumTask(task)) {
        return "gpt-3.5-turbo";  // 性价比高
    }
    
    // 复杂任务:代码生成、复杂推理
    if (isComplexTask(task)) {
        return "gpt-4";  // 质量高
    }
    
    return "gpt-3.5-turbo";  // 默认
}

2. 实施缓存策略

缓存策略:
  ├─ 常见问题缓存(FAQ)
  ├─ 相似问题合并
  ├─ 结果复用
  └─ 设置合理的过期时间

预期效果:
  ├─ 缓存命中率 30-50%
  ├─ 成本降低 30-50%
  └─ 响应速度提升 80-90%

3. 限流和配额管理

package com.example.springai.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 配额管理服务
 * 
 * @author Your Name
 * @since 1.0.0
 */
@Slf4j
@Service
public class QuotaManagementService {
    
    // 用户每日配额(Token数)
    private static final int DAILY_QUOTA = 100000;
    
    // 用户使用记录
    private final Map<String, AtomicInteger> userUsage = new ConcurrentHashMap<>();
    
    /**
     * 检查用户配额
     * 
     * @param userId 用户ID
     * @param estimatedTokens 预估Token数
     * @return 是否允许请求
     */
    public boolean checkQuota(String userId, int estimatedTokens) {
        AtomicInteger usage = userUsage.computeIfAbsent(
                userId, k -> new AtomicInteger(0));
        
        int currentUsage = usage.get();
        
        if (currentUsage + estimatedTokens > DAILY_QUOTA) {
            log.warn("用户 {} 超出每日配额 - 当前: {}, 配额: {}", 
                    userId, currentUsage, DAILY_QUOTA);
            return false;
        }
        
        return true;
    }
    
    /**
     * 记录使用量
     * 
     * @param userId 用户ID
     * @param tokens 使用的Token数
     */
    public void recordUsage(String userId, int tokens) {
        AtomicInteger usage = userUsage.computeIfAbsent(
                userId, k -> new AtomicInteger(0));
        
        usage.addAndGet(tokens);
        
        log.info("用户 {} Token使用记录 - 本次: {}, 累计: {}", 
                userId, tokens, usage.get());
    }
    
    /**
     * 重置用户配额(每日定时任务)
     */
    public void resetDailyQuota() {
        userUsage.clear();
        log.info("每日配额已重置");
    }
}

七、常见问题与解决方案

7.1 API 密钥相关问题

Q1: API 密钥无效或过期

错误信息:
Incorrect API key provided or API key has been revoked

解决方案:
1. 检查密钥是否正确复制(注意空格)
2. 确认密钥未被删除或撤销
3. 在 OpenAI 平台重新生成密钥
4. 检查环境变量是否正确设置

代码示例:

// 验证 API 密钥
@Component
public class ApiKeyValidator {
    
    @Value("${spring.ai.openai.api-key}")
    private String apiKey;
    
    @PostConstruct
    public void validateApiKey() {
        if (apiKey == null || apiKey.isBlank()) {
            throw new IllegalStateException("OpenAI API密钥未配置");
        }
        
        if (!apiKey.startsWith("sk-")) {
            throw new IllegalStateException("OpenAI API密钥格式不正确");
        }
        
        log.info("API密钥验证通过");
    }
}

Q2: 配额不足

错误信息:
You exceeded your current quota, please check your plan and billing details

解决方案:
1. 登录 OpenAI 平台检查账户余额
2. 充值账户或升级套餐
3. 检查是否有未支付的账单
4. 实施配额管理和限流策略

7.2 网络连接问题

Q3: 连接超时

错误信息:
Connection timeout / Read timeout

解决方案:
1. 检查网络连接
2. 配置代理(如果需要)
3. 增加超时时间
4. 实施重试机制

配置超时时间:

spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      # 配置超时时间(毫秒)
      connect-timeout: 30000
      read-timeout: 60000

配置代理:

@Configuration
public class ProxyConfig {
    
    @Bean
    public RestTemplate restTemplate() {
        SimpleClientHttpRequestFactory factory = 
                new SimpleClientHttpRequestFactory();
        
        // 配置代理
        Proxy proxy = new Proxy(
                Proxy.Type.HTTP,
                new InetSocketAddress("proxy.example.com", 8080)
        );
        factory.setProxy(proxy);
        
        // 配置超时
        factory.setConnectTimeout(30000);
        factory.setReadTimeout(60000);
        
        return new RestTemplate(factory);
    }
}

7.3 响应质量问题

Q4: 响应不准确或不相关

问题:AI 回复偏离主题或不准确

解决方案:
1. 优化提示词,提供更清晰的上下文
2. 使用 System Message 定义角色和规则
3. 调整 temperature 参数(降低随机性)
4. 提供示例(Few-shot Learning)
5. 考虑使用 GPT-4 获得更好的理解能力

示例:优化提示词

// ❌ 不好的提示词
String badPrompt = "翻译这个";

// ✅ 好的提示词
String goodPrompt = """
        请将以下英文翻译成中文:
        
        原文:%s
        
        要求:
        1. 保持原文的语气和风格
        2. 使用地道的中文表达
        3. 专业术语保持准确
        """.formatted(englishText);

Q5: 响应被截断

问题:AI 回复不完整,突然结束

原因:超过 max_tokens 限制

解决方案:
1. 增加 max_tokens 参数
2. 分段处理长文本
3. 使用流式响应
// 配置更大的 max_tokens
OpenAiChatOptions options = OpenAiChatOptions.builder()
        .withModel("gpt-3.5-turbo")
        .withMaxTokens(2000)  // 增加到 2000
        .build();

7.4 性能问题

Q6: 响应速度慢

问题:API 调用耗时过长

解决方案:
1. 使用流式响应提升用户体验
2. 实施缓存策略
3. 选择更快的模型(gpt-3.5-turbo)
4. 减少提示词长度
5. 使用异步调用

异步调用示例:

@Service
public class AsyncChatService {
    
    private final ChatClient chatClient;
    
    @Async
    public CompletableFuture<String> chatAsync(String message) {
        Prompt prompt = new Prompt(message);
        ChatResponse response = chatClient.call(prompt);
        return CompletableFuture.completedFuture(
                response.getResult().getOutput().getContent());
    }
}

启用异步:

@Configuration
@EnableAsync
public class AsyncConfig {
    
    @Bean
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("async-chat-");
        executor.initialize();
        return executor;
    }
}

八、最佳实践

8.1 提示词工程最佳实践

1. 清晰的角色定义

String systemPrompt = """
        你是一个专业的Java开发工程师,拥有10年以上的开发经验。
        你擅长Spring Boot、微服务架构和性能优化。
        你的回答要专业、准确、简洁。
        """;

2. 结构化的输出格式

String prompt = """
        请分析以下代码的问题,并按以下格式输出:
        
        ## 问题列表
        1. [问题描述]
        2. [问题描述]
        
        ## 优化建议
        1. [建议内容]
        2. [建议内容]
        
        ## 改进后的代码
        ```java
        [代码]
        ```
        """;

3. Few-shot Learning

String prompt = """
        请将商品名称转换为SEO友好的URL。
        
        示例:
        输入:iPhone 15 Pro Max 256GB 深空黑
        输出:iphone-15-pro-max-256gb-deep-space-black
        
        输入:小米13 Ultra 12GB+256GB 黑色
        输出:xiaomi-13-ultra-12gb-256gb-black
        
        现在请转换:%s
        """.formatted(productName);

8.2 错误处理最佳实践

1. 统一异常处理

package com.example.springai.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 全局异常处理器
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    /**
     * 处理 OpenAI API 异常
     */
    @ExceptionHandler(OpenAiApiException.class)
    public ResponseEntity<ErrorResponse> handleOpenAiException(
            OpenAiApiException e) {
        log.error("OpenAI API 异常", e);
        
        ErrorResponse response = ErrorResponse.builder()
                .code("OPENAI_API_ERROR")
                .message("AI服务暂时不可用,请稍后再试")
                .details(e.getMessage())
                .build();
        
        return ResponseEntity
                .status(HttpStatus.SERVICE_UNAVAILABLE)
                .body(response);
    }
    
    /**
     * 处理配额超限异常
     */
    @ExceptionHandler(QuotaExceededException.class)
    public ResponseEntity<ErrorResponse> handleQuotaException(
            QuotaExceededException e) {
        log.warn("配额超限", e);
        
        ErrorResponse response = ErrorResponse.builder()
                .code("QUOTA_EXCEEDED")
                .message("您的使用配额已用完,请明天再试")
                .details(e.getMessage())
                .build();
        
        return ResponseEntity
                .status(HttpStatus.TOO_MANY_REQUESTS)
                .body(response);
    }
}

@Data
@Builder
class ErrorResponse {
    private String code;
    private String message;
    private String details;
}

2. 优雅降级

@Service
public class ResilientChatService {
    
    private final ChatClient chatClient;
    private final String fallbackResponse = 
            "抱歉,AI服务暂时不可用。您可以:\n" +
            "1. 稍后再试\n" +
            "2. 联系人工客服\n" +
            "3. 查看帮助文档";
    
    public String chatWithFallback(String message) {
        try {
            return chatClient.call(new Prompt(message))
                    .getResult()
                    .getOutput()
                    .getContent();
        } catch (Exception e) {
            log.error("AI调用失败,返回降级响应", e);
            return fallbackResponse;
        }
    }
}

8.3 安全最佳实践

1. 输入验证和清理

@Service
public class InputValidationService {
    
    private static final int MAX_INPUT_LENGTH = 4000;
    private static final Pattern SENSITIVE_PATTERN = 
            Pattern.compile("(password|token|secret|key)\\s*[:=]\\s*\\S+", 
                    Pattern.CASE_INSENSITIVE);
    
    /**
     * 验证和清理用户输入
     */
    public String validateAndClean(String input) {
        // 1. 检查长度
        if (input == null || input.isBlank()) {
            throw new IllegalArgumentException("输入不能为空");
        }
        
        if (input.length() > MAX_INPUT_LENGTH) {
            throw new IllegalArgumentException(
                    "输入过长,最多" + MAX_INPUT_LENGTH + "字符");
        }
        
        // 2. 移除敏感信息
        String cleaned = SENSITIVE_PATTERN.matcher(input)
                .replaceAll("[REDACTED]");
        
        // 3. 移除特殊字符
        cleaned = cleaned.replaceAll("[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F]", "");
        
        return cleaned;
    }
}

2. 输出过滤

@Service
public class OutputFilterService {
    
    /**
     * 过滤AI响应中的敏感内容
     */
    public String filterOutput(String output) {
        // 1. 移除可能的API密钥
        output = output.replaceAll("sk-[a-zA-Z0-9]{48}", "[API_KEY_REDACTED]");
        
        // 2. 移除邮箱地址(可选)
        // output = output.replaceAll("\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b", "[EMAIL_REDACTED]");
        
        // 3. 移除电话号码(可选)
        // output = output.replaceAll("\\d{3}-\\d{4}-\\d{4}", "[PHONE_REDACTED]");
        
        return output;
    }
}

3. 速率限制

@Service
public class RateLimitService {
    
    private final Map<String, RateLimiter> limiters = new ConcurrentHashMap<>();
    
    /**
     * 检查速率限制
     * 
     * @param userId 用户ID
     * @return 是否允许请求
     */
    public boolean checkRateLimit(String userId) {
        RateLimiter limiter = limiters.computeIfAbsent(
                userId, 
                k -> RateLimiter.create(10.0)  // 每秒10个请求
        );
        
        return limiter.tryAcquire();
    }
}

8.4 监控和日志最佳实践

1. 结构化日志

@Slf4j
@Service
public class StructuredLoggingService {
    
    public void logApiCall(String userId, String model, 
                          int tokens, long duration) {
        // 使用结构化日志格式
        log.info("API调用 - userId={}, model={}, tokens={}, duration={}ms",
                userId, model, tokens, duration);
    }
    
    public void logError(String userId, String operation, Exception e) {
        log.error("操作失败 - userId={}, operation={}, error={}",
                userId, operation, e.getMessage(), e);
    }
}

2. 指标收集

@Service
public class MetricsService {
    
    private final MeterRegistry meterRegistry;
    
    public MetricsService(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }
    
    public void recordApiCall(String model, boolean success, long duration) {
        // 记录API调用次数
        meterRegistry.counter("openai.api.calls",
                "model", model,
                "success", String.valueOf(success))
                .increment();
        
        // 记录响应时间
        meterRegistry.timer("openai.api.duration",
                "model", model)
                .record(duration, TimeUnit.MILLISECONDS);
    }
    
    public void recordTokenUsage(String model, int tokens) {
        // 记录Token使用量
        meterRegistry.counter("openai.tokens.used",
                "model", model)
                .increment(tokens);
    }
}

九、练习题

基础练习

练习1:简单集成
创建一个 Spring Boot 项目,集成 OpenAI API,实现一个简单的问答接口。

要求:

  • 配置 OpenAI API 密钥
  • 创建 REST API 接口
  • 实现简单对话功能
  • 添加错误处理

练习2:参数配置
扩展练习1,支持动态配置模型参数。

要求:

  • 支持设置 temperature
  • 支持设置 max_tokens
  • 支持选择不同的模型
  • 返回 Token 使用情况

进阶练习

练习3:多轮对话
实现一个支持上下文的多轮对话系统。

要求:

  • 保存对话历史
  • 支持上下文理解
  • 实现对话清除功能
  • 限制历史长度(最近5轮)

练习4:流式响应
实现流式响应功能,提升用户体验。

要求:

  • 使用 Server-Sent Events (SSE)
  • 实时返回生成的内容
  • 处理流式错误
  • 前端实时显示

练习5:缓存优化
实现响应缓存,降低成本。

要求:

  • 使用 Redis 缓存
  • 设置合理的过期时间
  • 实现缓存命中率统计
  • 支持缓存清除

综合练习

练习6:智能客服系统
开发一个完整的智能客服系统。

要求:

  • 支持多轮对话
  • 实现意图识别
  • 集成知识库
  • 提供管理后台
  • 统计对话数据

练习7:内容生成平台
开发一个AI内容生成平台。

要求:

  • 支持多种内容类型(文章、标题、摘要)
  • 实现模板管理
  • 支持批量生成
  • 提供内容评分
  • 导出功能

练习8:代码助手
开发一个代码审查和优化助手。

要求:

  • 支持多种编程语言
  • 实现代码审查
  • 生成优化建议
  • 自动生成注释
  • 生成单元测试

十、学习检查清单

基础知识

  • 理解 OpenAI API 的基本概念
  • 掌握 API 密钥的获取和管理
  • 了解不同模型的特点和适用场景
  • 理解 Token 的计算方式
  • 掌握基本的 API 调用方法

集成开发

  • 能够配置 Spring AI OpenAI 依赖
  • 能够正确配置 application.yml
  • 能够创建基本的 ChatClient
  • 能够实现简单对话功能
  • 能够处理 API 调用异常

高级功能

  • 能够实现多轮对话
  • 能够使用流式响应
  • 能够动态切换模型
  • 能够配置重试机制
  • 能够实现响应缓存

实战应用

  • 能够开发智能客服系统
  • 能够实现内容生成功能
  • 能够开发代码助手
  • 能够集成到实际项目
  • 能够处理生产环境问题

优化和监控

  • 能够优化 Token 使用
  • 能够实施成本控制
  • 能够监控 API 使用情况
  • 能够实现配额管理
  • 能够分析和优化性能

安全和最佳实践

  • 能够安全管理 API 密钥
  • 能够实现输入验证
  • 能够实现输出过滤
  • 能够实施速率限制
  • 能够遵循最佳实践

十一、扩展阅读

官方文档

  1. OpenAI API 文档

    • https://platform.openai.com/docs/api-reference
    • 完整的 API 参考文档
  2. Spring AI 文档

    • https://docs.spring.io/spring-ai/reference/
    • Spring AI 官方文档
  3. OpenAI 最佳实践

    • https://platform.openai.com/docs/guides/best-practices
    • 官方最佳实践指南

技术博客

  1. OpenAI 博客

    • https://openai.com/blog
    • 最新功能和案例分享
  2. Spring 官方博客

    • https://spring.io/blog
    • Spring AI 相关文章

开源项目

  1. Spring AI Examples

    • https://github.com/spring-projects/spring-ai-examples
    • 官方示例项目
  2. ChatGPT 集成案例

    • GitHub 搜索 “spring-ai openai”
    • 社区优秀项目

学习资源

  1. 视频教程

    • YouTube: “Spring AI Tutorial”
    • B站: “Spring AI 教程”
  2. 在线课程

    • Udemy: Spring AI 相关课程
    • Coursera: AI 应用开发

社区资源

  1. Stack Overflow

    • 标签: spring-ai, openai-api
    • 问题讨论和解答
  2. GitHub Discussions

    • Spring AI 项目讨论区
    • 功能请求和问题反馈
  3. Discord/Slack

    • Spring 社区频道
    • OpenAI 开发者社区

十二、总结

核心要点回顾

1. OpenAI 集成基础

  • OpenAI 提供强大的 AI 能力
  • Spring AI 简化了集成过程
  • 正确配置是成功的关键

2. 实战应用场景

  • 智能客服:提升服务效率
  • 内容生成:提高创作效率
  • 代码助手:辅助开发工作

3. 成本优化策略

  • 选择合适的模型
  • 实施缓存策略
  • 优化 Token 使用
  • 配额管理和限流

4. 最佳实践

  • 安全管理 API 密钥
  • 实现错误处理和重试
  • 监控和日志记录
  • 输入验证和输出过滤

下一步学习建议

短期目标(1-2周)

  1. 完成所有基础练习
  2. 搭建本地开发环境
  3. 实现简单的应用场景
  4. 熟悉常见问题的解决方法

中期目标(1个月)

  1. 完成进阶练习
  2. 开发一个完整的项目
  3. 掌握性能优化技巧
  4. 学习成本控制策略

长期目标(3个月)

  1. 完成综合练习
  2. 在生产环境部署应用
  3. 积累实战经验
  4. 探索更多应用场景

常见误区

误区1:过度依赖 AI

  • AI 是辅助工具,不是万能的
  • 需要人工审核和优化
  • 关键业务逻辑不能完全依赖 AI

误区2:忽视成本控制

  • Token 使用会快速累积
  • 需要实施配额管理
  • 选择合适的模型很重要

误区3:不重视安全

  • API 密钥需要妥善保管
  • 用户输入需要验证
  • 输出内容需要过滤

误区4:缺少错误处理

  • API 调用可能失败
  • 需要实现重试机制
  • 要有降级方案

成功案例分享

案例1:电商客服系统

  • 场景:处理大量重复咨询
  • 方案:AI 客服 + 人工兜底
  • 效果:响应速度提升 80%,人工成本降低 60%

案例2:内容创作平台

  • 场景:批量生成商品描述
  • 方案:模板 + AI 生成 + 人工审核
  • 效果:创作效率提升 10倍,质量稳定

案例3:代码审查工具

  • 场景:提升代码质量
  • 方案:AI 自动审查 + 人工复核
  • 效果:发现问题数量提升 40%,审查时间减少 50%

持续学习资源

每日学习

  • 关注 OpenAI 官方博客
  • 阅读 Spring AI 更新日志
  • 参与社区讨论

每周实践

  • 尝试新的应用场景
  • 优化现有代码
  • 分享学习心得

每月总结

  • 回顾学习进度
  • 整理最佳实践
  • 规划下月目标

恭喜你完成了 OpenAI 模型集成的学习!

现在你已经掌握了:

  • ✅ OpenAI API 的基本使用
  • ✅ Spring AI 的集成方法
  • ✅ 实战应用场景的开发
  • ✅ 成本优化和性能调优
  • ✅ 安全和最佳实践

继续学习下一章节:Azure OpenAI 集成,探索企业级 AI 解决方案!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐