
Spring AI实战指南:在Java项目中集成大语言模型
前言
作为Java开发者,在AI浪潮中我们常常面临一个尴尬的问题:Python生态的AI工具链极其丰富,而Java似乎被边缘化了。但实际上,Spring团队推出的Spring AI正在改变这一局面。
本文基于我在实际项目中的使用经验,分享如何在Spring Boot应用中集成大语言模型,包括踩过的坑和最佳实践。
一、Spring AI是什么
Spring AI是Spring官方推出的AI应用开发框架,目标是让Java开发者能够以Spring的方式使用AI能力。
1.1 核心定位
ini
Spring AI = Spring的简洁性 + AI的强大能力
它解决了Java开发者在AI集成中的几个痛点:
- 统一API:不同厂商的模型(OpenAI、Claude、通义等)使用相同的调用方式
- 与Spring生态无缝集成:自动配置、依赖注入、AOP等特性全部可用
- 类型安全:告别Python的动态类型,享受Java的编译期检查
- 企业级特性:内置重试、熔断、监控等企业级能力
1.2 版本说明
目前Spring AI最新稳定版是1.1.0,基于Spring Boot 3.3+,需要JDK 17+。
二、环境准备
2.1 创建项目
使用Spring Initializr创建项目,选择以下依赖:
xml
<dependencies>
<!-- Spring AI核心 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<!-- 如果使用阿里通义 -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter</artifactId>
<version>1.0.0-M3</version>
</dependency>
</dependencies>
<!-- 添加Spring AI的Maven仓库 -->
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
2.2 配置API密钥
yaml
# application.yml
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
base-url: https://api.openai.com/v1
chat:
options:
model: gpt-4o
temperature: 0.7
如果使用阿里通义:
yaml
spring:
ai:
alibaba:
api-key: ${ALI_API_KEY}
chat:
options:
model: qwen-plus
三、基础使用:ChatClient
3.1 最简单的对话
java
@Service
public class ChatService {
private final ChatClient chatClient;
public ChatService(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder.build();
}
public String chat(String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
}
3.2 带系统提示的对话
java
public String chatWithSystemPrompt(String message) {
return chatClient.prompt()
.system("你是一个专业的Java技术顾问,回答要简洁准确。")
.user(message)
.call()
.content();
}
3.3 流式输出(SSE)
对于长文本回复,流式输出能提升用户体验:
java
public Flux<String> chatStream(String message) {
return chatClient.prompt()
.user(message)
.stream()
.content();
}
Controller层配合SSE:
java
@RestController
@RequestMapping("/api/chat")
public class ChatController {
private final ChatService chatService;
@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> stream(@RequestParam String message) {
return chatService.chatStream(message);
}
}
四、结构化输出:从字符串到对象
实际开发中,我们往往需要AI返回结构化数据,而不是纯文本。
4.1 定义输出结构
java
public record CodeReviewResult(
int score,
List<String> issues,
List<String> suggestions,
String summary
) {}
4.2 调用并解析
java
public CodeReviewResult reviewCode(String code) {
String prompt = """
请对以下Java代码进行审查,按JSON格式返回结果:
代码:
```java
%s
```
返回格式:
{
"score": 分数(1-100),
"issues": ["问题1", "问题2"],
"suggestions": ["建议1", "建议2"],
"summary": "总体评价"
}
""".formatted(code);
String response = chatClient.prompt()
.user(prompt)
.call()
.content();
// 提取JSON并解析
String json = extractJson(response);
return new ObjectMapper().readValue(json, CodeReviewResult.class);
}
4.3 更优雅的Bean输出
Spring AI 1.1支持直接输出Bean:
java
public CodeReviewResult reviewCodeV2(String code) {
return chatClient.prompt()
.user("请审查以下代码:" + code)
.call()
.entity(CodeReviewResult.class);
}
五、RAG:让AI读懂你的数据
RAG(检索增强生成)是生产环境最常用的AI应用模式。
5.1 核心流程
rust
用户提问 -> 向量检索 -> 获取相关文档 -> 构建Prompt -> AI生成答案
5.2 添加向量存储依赖
xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-milvus-store-spring-boot-starter</artifactId>
</dependency>
5.3 文档加载与存储
java
@Service
public class DocumentService {
private final VectorStore vectorStore;
public DocumentService(VectorStore vectorStore) {
this.vectorStore = vectorStore;
}
public void addDocuments(List<String> texts) {
List<Document> documents = texts.stream()
.map(text -> new Document(text))
.toList();
vectorStore.add(documents);
}
}
5.4 RAG问答实现
java
@Service
public class RagService {
private final ChatClient chatClient;
private final VectorStore vectorStore;
public RagService(ChatClient chatClient, VectorStore vectorStore) {
this.chatClient = chatClient;
this.vectorStore = vectorStore;
}
public String answer(String question) {
// 1. 检索相关文档
List<Document> relevantDocs = vectorStore.similaritySearch(
SearchRequest.builder()
.query(question)
.topK(5)
.build()
);
// 2. 构建上下文
String context = relevantDocs.stream()
.map(Document::getText)
.collect(Collectors.joining("\n\n"));
// 3. 构建Prompt
String prompt = """
基于以下上下文回答问题。如果上下文中没有相关信息,请明确说明。
上下文:
%s
问题:%s
""".formatted(context, question);
// 4. 调用AI
return chatClient.prompt()
.user(prompt)
.call()
.content();
}
}
六、Function Calling:AI调用Java方法
这是Spring AI最强大的特性之一:让AI能够调用你的业务方法。
6.1 定义工具方法
java
@Component
public class WeatherService {
@Tool(description = "获取指定城市的天气信息")
public String getWeather(@ToolParam(description = "城市名称,如北京") String city) {
// 实际调用天气API
return "北京今天晴,25°C";
}
}
6.2 注册工具并调用
java
@Service
public class AgentService {
private final ChatClient chatClient;
private final WeatherService weatherService;
public AgentService(ChatClient.Builder builder, WeatherService weatherService) {
this.chatClient = builder
.defaultTools(weatherService)
.build();
this.weatherService = weatherService;
}
public String chat(String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
}
当用户问"北京今天天气怎么样"时,AI会自动调用getWeather方法获取数据。
七、踩坑记录与解决方案
7.1 API调用超时
问题:大模型响应慢,默认超时时间不够。
解决:
java
@Bean
public ChatClient chatClient(ChatClient.Builder builder) {
return builder
.defaultClientRequest(request -> request
.timeout(Duration.ofSeconds(60))
)
.build();
}
7.2 中文乱码
问题:返回的中文显示乱码。
解决:确保请求头设置正确:
yaml
spring:
ai:
alibaba:
api-key: ${ALI_API_KEY}
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
7.3 Token计算不准确
问题:超出模型上下文限制。
解决:手动估算并截断:
java
private String truncate(String text, int maxTokens) {
// 粗略估算:中文1字≈1.5token
int estimatedTokens = (int) (text.length() * 1.5);
if (estimatedTokens > maxTokens) {
int maxChars = (int) (maxTokens / 1.5);
return text.substring(0, maxChars);
}
return text;
}
7.4 向量维度不匹配
问题:Milvus报错维度不一致。
解决:确保嵌入模型和向量库配置一致:
yaml
spring:
ai:
vectorstore:
milvus:
client:
host: localhost
port: 19530
collection-name: document_store
embedding-dimension: 1536 # 与模型输出维度一致
八、生产环境最佳实践
8.1 配置管理
使用Spring Cloud Config或环境变量管理API密钥,不要硬编码:
java
@Configuration
@ConfigurationProperties(prefix = "spring.ai.alibaba")
public class AiProperties {
private String apiKey;
private String baseUrl;
// getter/setter
}
8.2 错误处理
java
@Service
public class RobustChatService {
private final ChatClient chatClient;
@Retryable(value = {AiApiException.class}, maxAttempts = 3)
public String chatWithRetry(String message) {
try {
return chatClient.prompt()
.user(message)
.call()
.content();
} catch (Exception e) {
log.error("AI调用失败", e);
return "服务暂时不可用,请稍后重试";
}
}
}
8.3 成本监控
java
@Component
public class TokenMetrics {
private final MeterRegistry meterRegistry;
public void record(int inputTokens, int outputTokens) {
meterRegistry.counter("ai.tokens.input").increment(inputTokens);
meterRegistry.counter("ai.tokens.output").increment(outputTokens);
}
}
九、完整示例项目
9.1 项目结构
css
spring-ai-demo/
├── src/main/java/com/example/demo/
│ ├── DemoApplication.java
│ ├── config/
│ │ └── AiConfig.java
│ ├── controller/
│ │ └── ChatController.java
│ ├── service/
│ │ ├── ChatService.java
│ │ └── RagService.java
│ └── model/
│ └── ChatRequest.java
└── src/main/resources/
└── application.yml
9.2 可运行的完整代码
java
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@RestController
@RequestMapping("/api")
public class ChatController {
private final ChatService chatService;
public ChatController(ChatService chatService) {
this.chatService = chatService;
}
@PostMapping("/chat")
public ResponseEntity<String> chat(@RequestBody ChatRequest request) {
String response = chatService.chat(request.message());
return ResponseEntity.ok(response);
}
}
@Service
public class ChatService {
private final ChatClient chatClient;
public ChatService(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder.build();
}
public String chat(String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
}
public record ChatRequest(String message) {}
十、总结
Spring AI让Java开发者能够以熟悉的方式接入AI能力。核心要点:
- ChatClient是核心API,支持链式调用和流式输出
- RAG是生产环境最常用的模式,需要配合向量数据库
- Function Calling让AI能够调用业务方法,实现真正的智能代理
- 注意错误处理和成本控制,生产环境必须考虑这些
后续可以深入学习的方向:
- Spring AI与LangChain4j的对比
- 多模态AI(图像、语音)集成
- AI Agent的自主决策能力
参考链接:
- Spring AI官方文档:docs.spring.io/spring-ai/r...
- Spring AI Alibaba:github.com/alibaba/spr...
- 示例代码仓库:github.com/example/spr...