环境搭建与第一个 AI 应用
环境搭建与第一个 AI 应用
学习目标
- 掌握 Spring AI 开发环境的完整搭建流程
- 理解不同 AI 模型的配置方法
- 能够独立创建完整的 AI 应用项目
- 掌握项目结构设计和代码组织
- 了解开发、测试、生产环境的配置差异
- 能够解决环境搭建中的常见问题
知识结构
一、项目场景引入
1.1 企业 AI 应用开发流程
典型场景:某公司开发智能客服系统
第一阶段:本地开发
- 开发人员在本地搭建环境
- 使用 Ollama 本地模型进行开发
- 快速迭代,无需担心 API 成本
第二阶段:测试验证
- 部署到测试环境
- 使用 OpenAI gpt-3.5-turbo 测试
- 验证功能和性能
第三阶段:生产上线
- 部署到生产环境
- 使用 Azure OpenAI gpt-4
- 保证稳定性和安全性
挑战:
1. 不同环境使用不同的 AI 模型
2. 配置管理复杂
3. 环境切换频繁
4. 需要统一的开发流程
传统方案的问题:
// 问题 1:硬编码环境配置
public class AIService {
private static final String API_KEY = "sk-xxx"; // 硬编码
private static final String MODEL = "gpt-3.5-turbo";
public String chat(String message) {
// 直接调用 API
}
}
// 问题 2:环境切换需要修改代码
if (environment.equals("dev")) {
// 使用本地模型
} else if (environment.equals("prod")) {
// 使用云端模型
}
// 问题 3:配置分散
// API Key 在代码中
// 模型参数在配置文件中
// 环境变量在系统中
1.2 Spring AI 的解决方案
统一的配置管理 + 环境隔离:
# application-dev.yml(开发环境)
spring:
ai:
ollama:
base-url: http://localhost:11434
chat:
options:
model: llama2
# application-test.yml(测试环境)
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: gpt-3.5-turbo
# application-prod.yml(生产环境)
spring:
ai:
azure:
openai:
api-key: ${AZURE_OPENAI_API_KEY}
endpoint: ${AZURE_OPENAI_ENDPOINT}
chat:
options:
deployment-name: gpt-4
代码无需修改:
@Service
public class ChatService {
private final ChatClient chatClient; // 统一接口
public ChatService(ChatClient chatClient) {
this.chatClient = chatClient;
}
public String chat(String message) {
return chatClient.call(message); // 简单调用
}
}
// 启动时指定环境
// java -jar app.jar --spring.profiles.active=dev
// java -jar app.jar --spring.profiles.active=test
// java -jar app.jar --spring.profiles.active=prod
1.3 为什么需要规范的环境搭建
好处:
-
开发效率高
- 统一的开发环境
- 快速上手
- 减少环境问题
-
配置管理简单
- 集中管理配置
- 环境隔离
- 安全性高
-
部署方便
- 一次构建,多环境部署
- 配置外部化
- 容器化支持
-
团队协作顺畅
- 统一的项目结构
- 标准的开发流程
- 易于维护
二、开发环境准备
2.1 JDK 安装与配置
要求: JDK 17 或更高版本
Windows 安装:
# 1. 下载 JDK
# 访问 https://www.oracle.com/java/technologies/downloads/
# 或使用 OpenJDK: https://adoptium.net/
# 2. 安装 JDK
# 双击安装包,按提示安装
# 3. 配置环境变量
# 系统属性 → 环境变量 → 新建
JAVA_HOME=C:\Program Files\Java\jdk-17
Path=%JAVA_HOME%\bin
# 4. 验证安装
java -version
javac -version
Linux/Mac 安装:
# 使用 SDKMAN(推荐)
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install java 17.0.9-tem
# 或使用包管理器
# Ubuntu/Debian
sudo apt update
sudo apt install openjdk-17-jdk
# Mac
brew install openjdk@17
# 验证安装
java -version
配置 JAVA_HOME:
# Linux/Mac
echo 'export JAVA_HOME=/path/to/jdk-17' >> ~/.bashrc
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
# 验证
echo $JAVA_HOME
2.2 Maven 安装与配置
Windows 安装:
# 1. 下载 Maven
# 访问 https://maven.apache.org/download.cgi
# 2. 解压到目录
# 例如:C:\Program Files\Apache\maven-3.9.5
# 3. 配置环境变量
MAVEN_HOME=C:\Program Files\Apache\maven-3.9.5
Path=%MAVEN_HOME%\bin
# 4. 验证安装
mvn -version
Linux/Mac 安装:
# 使用 SDKMAN
sdk install maven
# 或使用包管理器
# Ubuntu/Debian
sudo apt install maven
# Mac
brew install maven
# 验证安装
mvn -version
配置 Maven 镜像(加速下载):
编辑 ~/.m2/settings.xml(Windows: C:\Users\用户名\.m2\settings.xml):
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<mirrors>
<!-- 阿里云镜像 -->
<mirror>
<id>aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Aliyun Maven</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
<!-- Spring 仓库 -->
<mirror>
<id>spring-milestones</id>
<mirrorOf>spring-milestones</mirrorOf>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</mirror>
</mirrors>
<profiles>
<profile>
<id>jdk-17</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>17</jdk>
</activation>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.compilerVersion>17</maven.compiler.compilerVersion>
</properties>
</profile>
</profiles>
</settings>
2.3 IDE 安装与配置
IntelliJ IDEA(推荐):
1. 下载安装
- 访问 https://www.jetbrains.com/idea/download/
- 选择 Community(免费)或 Ultimate(付费)版本
- 下载并安装
2. 配置 JDK
- File → Project Structure → SDKs
- 添加 JDK 17
3. 配置 Maven
- File → Settings → Build, Execution, Deployment → Build Tools → Maven
- Maven home directory: 选择 Maven 安装目录
- User settings file: 选择 settings.xml
4. 安装插件
- Lombok Plugin
- Spring Assistant
- Rainbow Brackets
- GitToolBox
VS Code 配置:
1. 安装 VS Code
- 访问 https://code.visualstudio.com/
- 下载并安装
2. 安装扩展
- Extension Pack for Java
- Spring Boot Extension Pack
- Lombok Annotations Support
3. 配置 Java
- Ctrl+Shift+P → Java: Configure Java Runtime
- 选择 JDK 17
2.4 Git 安装与配置
安装 Git:
# Windows
# 下载 https://git-scm.com/download/win
# 双击安装
# Linux
sudo apt install git
# Mac
brew install git
# 验证
git --version
配置 Git:
# 配置用户信息
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"
# 配置编辑器
git config --global core.editor "code --wait"
# 配置别名
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
# 查看配置
git config --list
三、AI 服务准备
3.1 OpenAI 账号注册与 API Key 获取
注册流程:
1. 访问 OpenAI 官网
- https://platform.openai.com/
2. 注册账号
- 点击 "Sign up"
- 使用邮箱或 Google 账号注册
- 验证邮箱
3. 登录账号
- 输入邮箱和密码
- 完成二次验证(如果需要)
4. 创建 API Key
- 进入 API Keys 页面
- 点击 "Create new secret key"
- 输入 Key 名称(可选)
- 复制并保存 Key(只显示一次!)
5. 充值账户(如果需要)
- 进入 Billing 页面
- 添加支付方式
- 充值金额
API Key 管理最佳实践:
# 1. 使用环境变量存储
# Linux/Mac
export OPENAI_API_KEY="sk-your-api-key-here"
# Windows PowerShell
$env:OPENAI_API_KEY="sk-your-api-key-here"
# Windows CMD
set OPENAI_API_KEY=sk-your-api-key-here
# 2. 添加到 ~/.bashrc 或 ~/.zshrc(永久生效)
echo 'export OPENAI_API_KEY="sk-your-api-key-here"' >> ~/.bashrc
source ~/.bashrc
# 3. 使用 .env 文件(开发环境)
# 创建 .env 文件
OPENAI_API_KEY=sk-your-api-key-here
# 添加到 .gitignore
echo ".env" >> .gitignore
安全注意事项:
❌ 不要做的事:
1. 不要将 API Key 提交到 Git 仓库
2. 不要在代码中硬编码 API Key
3. 不要在公开场合分享 API Key
4. 不要使用弱密码保护账号
✅ 应该做的事:
1. 使用环境变量管理 API Key
2. 定期更换 API Key
3. 设置 API Key 的使用限制
4. 监控 API 使用情况
5. 启用账号二次验证
3.2 Azure OpenAI 服务配置
申请 Azure OpenAI 服务:
1. 注册 Azure 账号
- 访问 https://azure.microsoft.com/
- 注册账号(需要信用卡验证)
2. 申请 Azure OpenAI 访问权限
- 访问 https://aka.ms/oai/access
- 填写申请表单
- 等待审核(通常 1-2 个工作日)
3. 创建 Azure OpenAI 资源
- 登录 Azure Portal
- 创建资源 → AI + Machine Learning → Azure OpenAI
- 选择订阅和资源组
- 选择区域(建议选择离你最近的)
- 创建资源
4. 部署模型
- 进入 Azure OpenAI Studio
- 选择 Deployments
- 创建新部署
- 选择模型(如 gpt-35-turbo)
- 设置部署名称
5. 获取配置信息
- Endpoint: https://your-resource.openai.azure.com/
- API Key: 在 Keys and Endpoint 页面获取
- Deployment Name: 你创建的部署名称
配置示例:
spring:
ai:
azure:
openai:
api-key: ${AZURE_OPENAI_API_KEY}
endpoint: ${AZURE_OPENAI_ENDPOINT}
chat:
options:
deployment-name: gpt-35-turbo
temperature: 0.7
max-tokens: 1000
3.3 Ollama 本地模型安装
安装 Ollama:
# Linux
curl -fsSL https://ollama.com/install.sh | sh
# Mac
brew install ollama
# Windows
# 下载安装包:https://ollama.com/download/windows
# 双击安装
# 验证安装
ollama --version
启动 Ollama 服务:
# 启动服务
ollama serve
# 服务默认运行在 http://localhost:11434
下载模型:
# 下载 Llama 2(7B 参数)
ollama pull llama2
# 下载 Llama 2(13B 参数)
ollama pull llama2:13b
# 下载 Mistral
ollama pull mistral
# 下载 CodeLlama(代码专用)
ollama pull codellama
# 查看已下载的模型
ollama list
# 测试模型
ollama run llama2
>>> Hello!
常用模型对比:
| 模型 | 参数量 | 大小 | 用途 | 推荐配置 |
|---|---|---|---|---|
| llama2 | 7B | 3.8GB | 通用对话 | 8GB RAM |
| llama2:13b | 13B | 7.3GB | 高质量对话 | 16GB RAM |
| mistral | 7B | 4.1GB | 通用对话 | 8GB RAM |
| codellama | 7B | 3.8GB | 代码生成 | 8GB RAM |
| phi | 2.7B | 1.6GB | 轻量级 | 4GB RAM |
配置 Spring AI 使用 Ollama:
spring:
ai:
ollama:
base-url: http://localhost:11434
chat:
options:
model: llama2
temperature: 0.7
num-predict: 1000
3.4 网络配置(国内用户)
问题: 国内访问 OpenAI API 可能较慢或无法访问
解决方案:
方案 1:使用代理
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
base-url: https://api.openai.com # 或使用代理地址
# 配置 HTTP 代理
http:
proxy:
host: your-proxy-host
port: your-proxy-port
方案 2:使用国内 AI 服务
# 使用阿里云通义千问
spring:
ai:
dashscope:
api-key: ${DASHSCOPE_API_KEY}
chat:
options:
model: qwen-turbo
# 使用百度文心一言
spring:
ai:
qianfan:
api-key: ${QIANFAN_API_KEY}
secret-key: ${QIANFAN_SECRET_KEY}
方案 3:使用本地模型
# 使用 Ollama 本地模型(推荐)
spring:
ai:
ollama:
base-url: http://localhost:11434
chat:
options:
model: llama2
四、创建第一个 Spring AI 项目
4.1 使用 Spring Initializr 创建项目
在线创建(推荐):
1. 访问 https://start.spring.io/
2. 配置项目信息
Project: Maven
Language: Java
Spring Boot: 3.2.0 或更高
Project Metadata:
- Group: com.example
- Artifact: spring-ai-demo
- Name: spring-ai-demo
- Description: Spring AI Demo Project
- Package name: com.example.springai
- Packaging: Jar
- Java: 17
3. 添加依赖
- Spring Web
- Lombok(可选)
4. 点击 "Generate" 下载项目
5. 解压并导入 IDE
使用 IDEA 创建:
1. File → New → Project
2. 选择 Spring Initializr
3. 配置项目信息(同上)
4. 选择依赖
5. 点击 Create
使用命令行创建:
# 使用 Spring CLI
spring init \
--dependencies=web \
--build=maven \
--java-version=17 \
--boot-version=3.2.0 \
--group-id=com.example \
--artifact-id=spring-ai-demo \
--name=spring-ai-demo \
--package-name=com.example.springai \
spring-ai-demo
cd spring-ai-demo
4.2 添加 Spring AI 依赖
编辑 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
https://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-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-ai-demo</name>
<description>Spring AI Demo Project</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>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</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>
刷新依赖:
# 使用 Maven
mvn clean install
# 或在 IDEA 中
# 右键 pom.xml → Maven → Reload Project
4.3 项目结构设计
标准项目结构:
spring-ai-demo/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/springai/
│ │ │ ├── SpringAiDemoApplication.java # 启动类
│ │ │ ├── controller/ # 控制器层
│ │ │ │ ├── ChatController.java
│ │ │ │ └── HealthController.java
│ │ │ ├── service/ # 服务层
│ │ │ │ ├── ChatService.java
│ │ │ │ └── impl/
│ │ │ │ └── ChatServiceImpl.java
│ │ │ ├── dto/ # 数据传输对象
│ │ │ │ ├── ChatRequest.java
│ │ │ │ └── ChatResponse.java
│ │ │ ├── config/ # 配置类
│ │ │ │ ├── AIConfig.java
│ │ │ │ └── WebConfig.java
│ │ │ ├── exception/ # 异常处理
│ │ │ │ ├── AIException.java
│ │ │ │ └── GlobalExceptionHandler.java
│ │ │ └── util/ # 工具类
│ │ │ └── ResponseUtil.java
│ │ └── resources/
│ │ ├── application.yml # 主配置文件
│ │ ├── application-dev.yml # 开发环境配置
│ │ ├── application-test.yml # 测试环境配置
│ │ ├── application-prod.yml # 生产环境配置
│ │ ├── logback-spring.xml # 日志配置
│ │ └── static/ # 静态资源
│ └── test/
│ └── java/
│ └── com/example/springai/
│ ├── SpringAiDemoApplicationTests.java
│ ├── controller/
│ │ └── ChatControllerTest.java
│ └── service/
│ └── ChatServiceTest.java
├── .gitignore
├── pom.xml
└── README.md
创建目录结构:
# Linux/Mac
mkdir -p src/main/java/com/example/springai/{controller,service/impl,dto,config,exception,util}
mkdir -p src/main/resources/static
mkdir -p src/test/java/com/example/springai/{controller,service}
# Windows PowerShell
New-Item -ItemType Directory -Path "src/main/java/com/example/springai/controller"
New-Item -ItemType Directory -Path "src/main/java/com/example/springai/service/impl"
New-Item -ItemType Directory -Path "src/main/java/com/example/springai/dto"
New-Item -ItemType Directory -Path "src/main/java/com/example/springai/config"
New-Item -ItemType Directory -Path "src/main/java/com/example/springai/exception"
New-Item -ItemType Directory -Path "src/main/java/com/example/springai/util"
4.4 配置文件编写
主配置文件 application.yml:
spring:
application:
name: spring-ai-demo
# 激活的配置文件
profiles:
active: ${SPRING_PROFILES_ACTIVE:dev}
# 服务器配置
server:
port: 8080
servlet:
context-path: /api
# 日志配置
logging:
level:
root: INFO
com.example.springai: DEBUG
org.springframework.ai: DEBUG
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
开发环境配置 application-dev.yml:
spring:
ai:
ollama:
base-url: http://localhost:11434
chat:
options:
model: llama2
temperature: 0.7
num-predict: 1000
# 开发环境日志
logging:
level:
com.example.springai: DEBUG
测试环境配置 application-test.yml:
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: gpt-3.5-turbo
temperature: 0.7
max-tokens: 1000
# 测试环境日志
logging:
level:
com.example.springai: INFO
生产环境配置 application-prod.yml:
spring:
ai:
azure:
openai:
api-key: ${AZURE_OPENAI_API_KEY}
endpoint: ${AZURE_OPENAI_ENDPOINT}
chat:
options:
deployment-name: gpt-4
temperature: 0.5
max-tokens: 2000
# 生产环境日志
logging:
level:
root: WARN
com.example.springai: INFO
file:
name: logs/spring-ai-demo.log
max-size: 10MB
max-history: 30
五、编写第一个 AI 应用
5.1 创建 DTO 类
ChatRequest.java:
package com.example.springai.dto;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
/**
* 聊天请求对象
*/
@Data
public class ChatRequest {
/**
* 用户消息
*/
@NotBlank(message = "消息不能为空")
@Size(max = 2000, message = "消息长度不能超过2000字符")
private String message;
/**
* 对话ID(用于多轮对话)
*/
private String conversationId;
/**
* 用户ID
*/
private String userId;
}
ChatResponse.java:
package com.example.springai.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 聊天响应对象
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ChatResponse {
/**
* AI 回复
*/
private String reply;
/**
* 对话ID
*/
private String conversationId;
/**
* 响应时间(毫秒)
*/
private Long responseTime;
/**
* Token 使用情况
*/
private TokenUsage tokenUsage;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class TokenUsage {
private Long promptTokens;
private Long completionTokens;
private Long totalTokens;
}
}
Result.java(统一响应):
package com.example.springai.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 统一响应对象
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {
/**
* 状态码
*/
private Integer code;
/**
* 消息
*/
private String message;
/**
* 数据
*/
private T data;
/**
* 时间戳
*/
private Long timestamp;
/**
* 成功响应
*/
public static <T> Result<T> success(T data) {
return new Result<>(200, "success", data, System.currentTimeMillis());
}
/**
* 成功响应(无数据)
*/
public static <T> Result<T> success() {
return success(null);
}
/**
* 失败响应
*/
public static <T> Result<T> error(String message) {
return new Result<>(500, message, null, System.currentTimeMillis());
}
/**
* 失败响应(自定义状态码)
*/
public static <T> Result<T> error(Integer code, String message) {
return new Result<>(code, message, null, System.currentTimeMillis());
}
}
5.2 创建服务层
ChatService.java(接口):
package com.example.springai.service;
import com.example.springai.dto.ChatRequest;
import com.example.springai.dto.ChatResponse;
/**
* 聊天服务接口
*/
public interface ChatService {
/**
* 简单对话
*
* @param message 用户消息
* @return AI 回复
*/
String simpleChat(String message);
/**
* 标准对话
*
* @param request 聊天请求
* @return 聊天响应
*/
ChatResponse chat(ChatRequest request);
/**
* 流式对话
*
* @param message 用户消息
* @return 响应流
*/
reactor.core.publisher.Flux<String> streamChat(String message);
}
ChatServiceImpl.java(实现):
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.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import java.util.UUID;
/**
* 聊天服务实现
*/
@Slf4j
@Service
public class ChatServiceImpl implements ChatService {
private final ChatClient chatClient;
public ChatServiceImpl(ChatClient chatClient) {
this.chatClient = chatClient;
}
@Override
public String simpleChat(String message) {
log.info("收到简单对话请求: {}", message);
try {
String reply = chatClient.call(message);
log.info("AI 回复: {}", reply);
return reply;
} catch (Exception e) {
log.error("对话失败", e);
throw new RuntimeException("AI 服务暂时不可用", e);
}
}
@Override
public ChatResponse chat(ChatRequest request) {
log.info("收到对话请求: {}", request);
long startTime = System.currentTimeMillis();
try {
// 1. 创建 Prompt
Prompt prompt = new Prompt(new UserMessage(request.getMessage()));
// 2. 调用 AI
AIChatResponse aiResponse = chatClient.call(prompt);
// 3. 提取响应内容
String reply = aiResponse.getResult().getOutput().getContent();
// 4. 计算响应时间
long responseTime = System.currentTimeMillis() - startTime;
// 5. 提取 Token 使用情况
var usage = aiResponse.getMetadata().getUsage();
ChatResponse.TokenUsage tokenUsage = ChatResponse.TokenUsage.builder()
.promptTokens(usage.getPromptTokens())
.completionTokens(usage.getGenerationTokens())
.totalTokens(usage.getTotalTokens())
.build();
// 6. 构建响应
ChatResponse response = ChatResponse.builder()
.reply(reply)
.conversationId(request.getConversationId() != null ?
request.getConversationId() : UUID.randomUUID().toString())
.responseTime(responseTime)
.tokenUsage(tokenUsage)
.build();
log.info("对话成功 - 耗时: {}ms, Token: {}",
responseTime, tokenUsage.getTotalTokens());
return response;
} catch (Exception e) {
log.error("对话失败", e);
throw new RuntimeException("AI 服务暂时不可用", e);
}
}
@Override
public Flux<String> streamChat(String message) {
log.info("收到流式对话请求: {}", message);
try {
Prompt prompt = new Prompt(new UserMessage(message));
return chatClient.stream(prompt)
.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(new RuntimeException("AI 服务暂时不可用", e));
}
}
}
5.3 创建控制器层
ChatController.java:
package com.example.springai.controller;
import com.example.springai.dto.ChatRequest;
import com.example.springai.dto.ChatResponse;
import com.example.springai.dto.Result;
import com.example.springai.service.ChatService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
/**
* 聊天控制器
*/
@Slf4j
@RestController
@RequestMapping("/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 Result<String> simpleChat(@RequestParam String message) {
log.info("简单对话请求: {}", message);
String reply = chatService.simpleChat(message);
return Result.success(reply);
}
/**
* 标准对话接口
* POST /api/chat
* Body: {"message": "你好"}
*
* @param request 聊天请求
* @return 聊天响应
*/
@PostMapping
public Result<ChatResponse> chat(@Validated @RequestBody ChatRequest request) {
log.info("对话请求: {}", request);
ChatResponse response = chatService.chat(request);
return Result.success(response);
}
/**
* 流式对话接口
* 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);
}
}
HealthController.java:
package com.example.springai.controller;
import com.example.springai.dto.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* 健康检查控制器
*/
@RestController
@RequestMapping("/health")
public class HealthController {
/**
* 健康检查
* GET /api/health
*
* @return 健康状态
*/
@GetMapping
public Result<Map<String, Object>> health() {
Map<String, Object> health = new HashMap<>();
health.put("status", "UP");
health.put("service", "spring-ai-demo");
health.put("timestamp", System.currentTimeMillis());
return Result.success(health);
}
}
5.4 异常处理
AIException.java:
package com.example.springai.exception;
/**
* AI 服务异常
*/
public class AIException extends RuntimeException {
private Integer code;
public AIException(String message) {
super(message);
this.code = 500;
}
public AIException(Integer code, String message) {
super(message);
this.code = code;
}
public AIException(String message, Throwable cause) {
super(message, cause);
this.code = 500;
}
public Integer getCode() {
return code;
}
}
GlobalExceptionHandler.java:
package com.example.springai.exception;
import com.example.springai.dto.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 全局异常处理器
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理 AI 异常
*/
@ExceptionHandler(AIException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Result<Void> handleAIException(AIException e) {
log.error("AI 服务异常", e);
return Result.error(e.getCode(), e.getMessage());
}
/**
* 处理参数验证异常
*/
@ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Result<Void> handleValidationException(Exception e) {
log.error("参数验证失败", e);
String message = "参数验证失败";
if (e instanceof MethodArgumentNotValidException) {
var error = ((MethodArgumentNotValidException) e)
.getBindingResult().getFieldError();
if (error != null) {
message = error.getDefaultMessage();
}
}
return Result.error(400, message);
}
/**
* 处理通用异常
*/
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Result<Void> handleException(Exception e) {
log.error("系统异常", e);
return Result.error("系统异常,请稍后重试");
}
}
5.5 启动类
SpringAiDemoApplication.java:
package com.example.springai;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Spring AI 演示应用
*
* @author Your Name
* @since 1.0.0
*/
@SpringBootApplication
public class SpringAiDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringAiDemoApplication.class, args);
System.out.println("""
========================================
Spring AI Demo Application Started!
========================================
API Base URL: http://localhost:8080/api
Health Check: http://localhost:8080/api/health
Simple Chat: http://localhost:8080/api/chat/simple?message=你好
========================================
""");
}
}
六、运行和测试
6.1 启动应用
方式 1:使用 Maven
# 开发环境
mvn spring-boot:run
# 指定环境
mvn spring-boot:run -Dspring-boot.run.profiles=dev
# 或
mvn spring-boot:run -Dspring-boot.run.arguments="--spring.profiles.active=dev"
方式 2:使用 IDEA
1. 右键 SpringAiDemoApplication
2. 选择 Run 'SpringAiDemoApplication'
或
1. 点击 Run → Edit Configurations
2. 添加 Environment Variables: SPRING_PROFILES_ACTIVE=dev
3. 点击 Run
方式 3:打包后运行
# 打包
mvn clean package
# 运行
java -jar target/spring-ai-demo-0.0.1-SNAPSHOT.jar
# 指定环境
java -jar target/spring-ai-demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev
6.2 测试接口
使用 curl 测试:
# 1. 健康检查
curl http://localhost:8080/api/health
# 2. 简单对话(GET)
curl "http://localhost:8080/api/chat/simple?message=你好"
# 3. 标准对话(POST)
curl -X POST http://localhost:8080/api/chat \
-H "Content-Type: application/json" \
-d '{
"message": "介绍一下 Spring AI",
"userId": "user123"
}'
# 4. 流式对话
curl -N http://localhost:8080/api/chat/stream?message=写一首诗
使用 Postman 测试:
1. 创建 Collection: Spring AI Demo
2. 添加请求:健康检查
- Method: GET
- URL: http://localhost:8080/api/health
3. 添加请求:简单对话
- Method: GET
- URL: http://localhost:8080/api/chat/simple
- Params: message=你好
4. 添加请求:标准对话
- Method: POST
- URL: http://localhost:8080/api/chat
- Headers: Content-Type: application/json
- Body (raw JSON):
{
"message": "介绍一下 Spring AI",
"userId": "user123"
}
5. 添加请求:流式对话
- Method: GET
- URL: http://localhost:8080/api/chat/stream
- Params: message=写一首诗
预期响应:
// 健康检查
{
"code": 200,
"message": "success",
"data": {
"status": "UP",
"service": "spring-ai-demo",
"timestamp": 1704067200000
},
"timestamp": 1704067200000
}
// 简单对话
{
"code": 200,
"message": "success",
"data": "你好!我是 AI 助手,有什么可以帮助你的吗?",
"timestamp": 1704067200000
}
// 标准对话
{
"code": 200,
"message": "success",
"data": {
"reply": "Spring AI 是 Spring 生态系统中用于构建 AI 应用的框架...",
"conversationId": "550e8400-e29b-41d4-a716-446655440000",
"responseTime": 1523,
"tokenUsage": {
"promptTokens": 15,
"completionTokens": 150,
"totalTokens": 165
}
},
"timestamp": 1704067200000
}
6.3 查看日志
控制台日志:
2024-01-01 10:00:00 [main] INFO c.e.s.SpringAiDemoApplication - Starting SpringAiDemoApplication
2024-01-01 10:00:01 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080
2024-01-01 10:00:01 [main] INFO c.e.s.SpringAiDemoApplication - Started SpringAiDemoApplication in 2.5 seconds
2024-01-01 10:00:10 [http-nio-8080-exec-1] INFO c.e.s.c.ChatController - 对话请求: ChatRequest(message=你好, conversationId=null, userId=user123)
2024-01-01 10:00:10 [http-nio-8080-exec-1] INFO c.e.s.s.i.ChatServiceImpl - 收到对话请求: ChatRequest(message=你好, conversationId=null, userId=user123)
2024-01-01 10:00:11 [http-nio-8080-exec-1] INFO c.e.s.s.i.ChatServiceImpl - 对话成功 - 耗时: 1523ms, Token: 165
日志文件(生产环境):
# 查看日志
tail -f logs/spring-ai-demo.log
# 搜索错误
grep "ERROR" logs/spring-ai-demo.log
# 查看最近100行
tail -n 100 logs/spring-ai-demo.log
七、常见问题
Q1: 启动时报错 “Failed to configure a DataSource”
原因: Spring Boot 自动配置了数据源,但没有配置数据库
解决方案:
// 方案 1:排除数据源自动配置
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class SpringAiDemoApplication {
// ...
}
// 方案 2:添加数据库配置(如果需要)
spring:
datasource:
url: jdbc:mysql://localhost:3306/demo
username: root
password: password
Q2: 调用 AI 时报错 “401 Unauthorized”
原因: API Key 配置错误或未配置
解决方案:
# 1. 检查环境变量
echo $OPENAI_API_KEY
# 2. 重新设置环境变量
export OPENAI_API_KEY="sk-your-api-key-here"
# 3. 重启应用
Q3: 响应很慢或超时
原因: 网络问题或模型响应慢
解决方案:
# 1. 增加超时时间
spring:
ai:
openai:
chat:
options:
timeout: 60s
# 2. 使用本地模型(开发环境)
spring:
ai:
ollama:
base-url: http://localhost:11434
# 3. 使用代理
http:
proxy:
host: your-proxy-host
port: your-proxy-port
Q4: 如何调试 AI 请求和响应?
解决方案:
# 1. 开启 DEBUG 日志
logging:
level:
org.springframework.ai: DEBUG
# 2. 添加请求拦截器
@Component
public class AIRequestInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(
HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution) throws IOException {
log.debug("AI Request: {} {}", request.getMethod(), request.getURI());
log.debug("Request Body: {}", new String(body));
ClientHttpResponse response = execution.execute(request, body);
log.debug("AI Response: {}", response.getStatusCode());
return response;
}
}
Q5: 如何切换不同的 AI 模型?
解决方案:
# 方案 1:修改配置文件
spring:
ai:
openai:
chat:
options:
model: gpt-4 # 改为 gpt-4
# 方案 2:运行时指定
java -jar app.jar --spring.ai.openai.chat.options.model=gpt-4
# 方案 3:代码中指定
OpenAiChatOptions options = OpenAiChatOptions.builder()
.withModel("gpt-4")
.build();
Prompt prompt = new Prompt(message, options);
八、练习题
基础练习
练习 1: 添加用户认证功能
练习 2: 实现对话历史记录
练习 3: 添加 Token 使用统计
进阶练习
练习 4: 实现多轮对话
练习 5: 添加缓存机制
练习 6: 实现流式响应的前端展示
综合练习
练习 7: 构建完整的智能客服系统
九、学习检查清单
- 完成开发环境搭建
- 成功创建 Spring AI 项目
- 理解项目结构设计
- 能够编写基础的 AI 应用
- 掌握配置文件管理
- 能够测试和调试应用
- 了解常见问题的解决方法
十、扩展阅读
总结
恭喜你完成了环境搭建和第一个 AI 应用的开发!现在你已经掌握了 Spring AI 开发的基础技能,可以继续学习更高级的功能了。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)