1. Spring AI入门指南:从零开始构建智能应用
Spring AI是Spring生态系统中的新兴成员,它为企业级Java应用提供了便捷的AI集成能力。作为一位长期使用Spring框架的开发者,我发现Spring AI真正实现了"AI平民化"——让没有机器学习背景的Java开发者也能快速构建智能应用。本文将带你从零开始探索Spring AI的核心功能。
提示:Spring AI目前仍处于快速迭代阶段,本文基于Spring AI 1.0版本编写,部分API可能会在后续版本中调整。
1.1 环境准备与项目初始化
首先确保你的开发环境满足以下要求:
- JDK 17或更高版本
- Maven 3.6+或Gradle 7.x
- IDE(推荐IntelliJ IDEA或VS Code)
使用Spring Initializr创建项目时,除了选择基础的"Spring Web"依赖外,还需要添加:
xml复制<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
根据你要集成的AI服务,选择对应的starter:
- OpenAI:
spring-ai-openai-spring-boot-starter - Azure OpenAI:
spring-ai-azure-openai-spring-boot-starter - HuggingFace:
spring-ai-huggingface-spring-boot-starter
1.2 配置API密钥
在application.properties中配置你的AI服务凭证:
properties复制# OpenAI配置示例
spring.ai.openai.api-key=你的API_KEY
spring.ai.openai.chat.options.model=gpt-3.5-turbo
# Azure OpenAI配置示例
spring.ai.azure.openai.api-key=你的API_KEY
spring.ai.azure.openai.endpoint=你的终结点URL
spring.ai.azure.openai.chat.options.deployment-name=部署名称
安全提示:永远不要将API密钥直接提交到代码仓库。考虑使用环境变量或密钥管理服务。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Spring AI核心功能实战
2.1 聊天API集成
Spring AI最强大的功能之一是简化了与大型语言模型(LLM)的交互。创建一个简单的聊天服务:
java复制@RestController
@RequestMapping("/api/chat")
public class ChatController {
private final ChatClient chatClient;
public ChatController(ChatClient chatClient) {
this.chatClient = chatClient;
}
@GetMapping("/prompt")
public String generate(@RequestParam String message) {
return chatClient.call(message);
}
}
进阶用法:使用PromptTemplate构建结构化提示:
java复制PromptTemplate promptTemplate = new PromptTemplate("""
你是一位专业的{role},请用{style}风格回答以下问题:
问题:{question}
""");
Map<String, Object> params = Map.of(
"role", "Java架构师",
"style", "简洁专业",
"question", "如何设计高并发系统"
);
Prompt prompt = promptTemplate.create(params);
String response = chatClient.call(prompt.getContents());
2.2 嵌入(Embedding)功能
嵌入是将文本转换为向量表示的过程,常用于语义搜索和推荐系统:
java复制@RestController
@RequestMapping("/api/embedding")
public class EmbeddingController {
private final EmbeddingClient embeddingClient;
public EmbeddingController(EmbeddingClient embeddingClient) {
this.embeddingClient = embeddingClient;
}
@GetMapping("/vector")
public List<Double> getEmbedding(@RequestParam String text) {
EmbeddingResponse response = embeddingClient.embedForResponse(List.of(text));
return response.getResults().get(0).getOutput();
}
}
2.3 图像生成API
集成DALL-E等图像生成模型:
java复制@RestController
@RequestMapping("/api/images")
public class ImageController {
private final ImageClient imageClient;
public ImageController(ImageClient imageClient) {
this.imageClient = imageClient;
}
@PostMapping("/generate")
public ResponseEntity<byte[]> generateImage(@RequestBody ImagePrompt prompt) {
ImageResponse response = imageClient.call(
new ImagePrompt(prompt.getText(),
ImageOptionsBuilder.builder()
.withModel("dall-e-3")
.build())
);
return ResponseEntity.ok()
.contentType(MediaType.IMAGE_PNG)
.body(response.getResult().getOutput().getBytes());
}
}
3. 高级特性与最佳实践
3.1 流式响应处理
对于长文本生成,使用流式响应可以显著提升用户体验:
java复制@GetMapping("/stream")
public SseEmitter streamChat(@RequestParam String message) {
SseEmitter emitter = new SseEmitter();
chatClient.stream(new Prompt(message))
.subscribe(
chunk -> {
try {
emitter.send(chunk.getContents());
} catch (IOException e) {
throw new RuntimeException(e);
}
},
emitter::completeWithError,
emitter::complete
);
return emitter;
}
3.2 函数调用(Function Calling)
利用函数调用实现结构化数据提取:
java复制@Bean
public FunctionCallback weatherFunction() {
return new FunctionCallback("getCurrentWeather", """
Get the current weather in a given location
""", args -> {
String location = args.get("location");
// 调用真实天气API
return Map.of("temperature", "25", "unit", "celsius");
});
}
// 在Controller中
ChatResponse response = chatClient.call(
new Prompt("北京现在的天气怎么样?",
OpenAiChatOptions.builder()
.withFunction("getCurrentWeather")
.build())
);
3.3 性能优化技巧
- 批量处理:对于嵌入和批量文本处理,尽量使用批量API
java复制List<String> texts = List.of("文本1", "文本2", "文本3");
EmbeddingResponse response = embeddingClient.embedForResponse(texts);
- 缓存策略:对频繁查询的嵌入结果实现缓存
java复制@Cacheable("embeddings")
public List<Double> getCachedEmbedding(String text) {
return embeddingClient.embed(text);
}
- 超时配置:根据场景调整超时设置
properties复制spring.ai.openai.chat.options.timeout=60s
4. 常见问题排查
4.1 认证失败问题
- 症状:401 Unauthorized错误
- 检查点:
- API密钥是否正确
- 对于Azure OpenAI,检查终结点URL格式
- 确保账户有足够配额
4.2 模型不可用
- 症状:404 Not Found或模型不支持特定功能
- 解决方案:
- 检查application.properties中配置的模型名称
- 确认你的API订阅包含该模型
- 对于Azure OpenAI,检查部署名称是否匹配
4.3 性能问题
- 症状:响应缓慢或超时
- 优化建议:
- 减少max_tokens参数值
- 对于简单任务,使用更小的模型
- 实现客户端缓存
4.4 内容过滤问题
- 症状:返回内容被截断或包含意外过滤信息
- 处理方法:
- 调整content_filter设置
- 在提示中明确内容要求
- 实现后处理过滤逻辑
5. 生产环境注意事项
- 速率限制:所有AI服务都有API调用限制,实现适当的退避机制
java复制@Retryable(value = RateLimitException.class,
maxAttempts = 3,
backoff = @Backoff(delay = 1000))
public ChatResponse callWithRetry(Prompt prompt) {
return chatClient.call(prompt);
}
- 成本控制:监控token使用量,设置预算警报
java复制// 获取每次调用的token使用情况
ChatResponse response = chatClient.call(prompt);
Usage usage = response.getMetadata().getUsage();
-
数据隐私:敏感数据应进行匿名化处理或使用本地模型
-
模型版本管理:在配置中固定模型版本,避免自动升级带来的兼容性问题
Spring AI为Java开发者打开了AI应用开发的大门。从我个人的使用经验来看,最佳实践是:从简单原型开始,逐步迭代;充分理解不同模型的特性;建立完善的监控和回退机制。随着Spring AI生态的成熟,相信会有更多令人兴奋的功能出现。
