1. Spring AI 框架概述
Spring AI是Spring生态系统中面向AI工程的应用框架,其设计目标是将Spring的核心原则(如可移植性、模块化设计)引入AI领域。这个框架本质上解决了企业数据/API与AI模型之间的连接难题,让开发者能够以熟悉的Spring方式构建AI应用。
我在实际项目中使用Spring AI时发现,它最显著的优势在于统一了不同AI供应商的API调用方式。无论是OpenAI、Anthropic还是本地部署的Ollama模型,开发者都可以通过相同的接口进行交互。这种设计极大降低了技术栈切换的成本,特别是在需要同时对接多个AI服务的场景下。
重要提示:Spring 2.0版本引入了对Alibaba模型的支持,这意味着开发者现在可以直接调用通义千问等国产大模型,这对需要符合数据合规要求的项目尤为重要。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与基础配置
2.1 项目初始化
使用Spring Initializr创建项目时,需要添加以下核心依赖(以Gradle为例):
groovy复制dependencies {
implementation 'org.springframework.ai:spring-ai-openai-spring-boot-starter'
// 如需使用Alibaba模型
implementation 'org.springframework.ai:spring-ai-alibaba-spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web'
}
2.2 密钥配置
在application.properties中配置API密钥:
properties复制# OpenAI配置
spring.ai.openai.api-key=your-openai-key
# Alibaba配置
spring.ai.alibaba.api-key=your-alibaba-key
spring.ai.alibaba.endpoint=https://dashscope.aliyuncs.com
这里有个实际项目中的经验:建议将密钥存储在环境变量中而非直接写在配置文件里。可以通过${env.API_KEY}的方式引用,避免密钥泄露风险。
3. 核心功能实现
3.1 基础对话功能
创建ChatClient实例进行对话:
java复制@RestController
public class AIController {
private final ChatClient chatClient;
public AIController(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
@GetMapping("/chat")
public String chat(@RequestParam String message) {
return chatClient.prompt()
.user(userSpec -> userSpec.text(message))
.call()
.content();
}
}
实测中发现,默认的temperature参数(0.7)可能不适合所有场景。对于需要确定性输出的任务(如代码生成),建议调整为0.2-0.3:
java复制chatClient.prompt()
.options(OpenAiChatOptions.builder()
.withTemperature(0.3)
.build())
.user(u -> u.text(message))
.call();
3.2 流式响应实现
对于需要实时显示响应的场景(如聊天应用),可以使用流式API:
java复制@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> streamChat(@RequestParam String message) {
return chatClient.prompt()
.user(u -> u.text(message))
.stream()
.map(ChatResponse::getResults)
.flatMapIterable(list -> list)
.map(content -> content.getOutput().getContent());
}
踩坑记录:在SSE(Server-Sent Events)实现中,务必在客户端添加重连逻辑。网络不稳定时,Spring的默认超时设置可能导致连接中断。
4. 高级功能实践
4.1 结构化输出映射
Spring AI支持将AI输出自动映射到POJO:
java复制public class Joke {
private String setup;
private String punchline;
// getters/setters
}
@Bean
public CommandLineRunner structuredDemo(ChatClient chatClient) {
return args -> {
Joke joke = chatClient.prompt()
.user(u -> u.text("Tell me a joke about programmers"))
.call()
.entity(Joke.class);
System.out.println(joke.getSetup());
System.out.println(joke.getPunchline());
};
}
4.2 RAG混合检索实现
结合DeepSeek实现检索增强生成(RAG):
java复制@Bean
public VectorStore vectorStore(EmbeddingClient embeddingClient) {
return new SimpleVectorStore(embeddingClient);
}
@Bean
public CommandLineRunner ragDemo(
ChatClient chatClient,
VectorStore vectorStore,
EmbeddingClient embeddingClient) {
return args -> {
// 文档嵌入处理
vectorStore.add(List.of(
new Document("Spring AI支持多种大模型接入",
Map.of("source", "official-docs")),
new Document("DeepSeek提供高效的文本嵌入能力",
Map.of("source", "deepseek-docs"))
));
// 检索增强查询
String query = "Spring AI能接入哪些模型?";
List<Document> similarDocs = vectorStore.similaritySearch(query);
String response = chatClient.prompt()
.system(s -> s.text("基于以下上下文回答问题:" + similarDocs))
.user(u -> u.text(query))
.call()
.content();
System.out.println(response);
};
}
5. 生产环境注意事项
5.1 性能优化
- 连接池配置:默认的HTTP客户端可能不适合高并发场景,建议自定义:
java复制@Bean
public WebClient.Builder webClientBuilder() {
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(
HttpClient.create()
.responseTimeout(Duration.ofSeconds(30))
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
));
}
- 批量处理:当需要处理大量文本时(如批量生成嵌入),使用并行流:
java复制List<String> texts = // 获取文本列表
List<Embedding> embeddings = texts.parallelStream()
.map(embeddingClient::embed)
.toList();
5.2 监控与可观测性
Spring AI内置了Micrometer指标,可通过以下配置启用:
properties复制management.endpoints.web.exposure.include=health,info,metrics
management.metrics.export.prometheus.enabled=true
关键监控指标包括:
spring.ai.chat.completions:对话调用次数与耗时spring.ai.embeddings:嵌入操作指标spring.ai.errors:错误统计
6. 常见问题排查
6.1 流式响应中断
现象:SSE连接随机断开
解决方案:
- 检查服务器超时设置:
properties复制server.connection-timeout=60s
- 客户端添加重试逻辑:
javascript复制const eventSource = new EventSource('/stream');
eventSource.onerror = () => {
setTimeout(() => {
// 重新建立连接
}, 1000);
};
6.2 中文输出异常
现象:中文响应出现乱码或截断
解决方案:
- 确保服务端编码设置:
java复制@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
StringHttpMessageConverter converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
converters.add(0, converter);
}
}
- 对于Alibaba模型,明确指定语言参数:
java复制chatClient.prompt()
.options(AlibabaChatOptions.builder()
.withParameters(Map.of("result_format", "text"))
.build());
7. 项目进阶方向
7.1 自定义函数调用
Spring AI 2.0支持模型调用本地方法:
java复制@Bean
public FunctionCallback weatherFunction() {
return FunctionCallback.builder("getWeather")
.withDescription("Get the weather for a location")
.withFunction(location -> {
// 实现天气查询逻辑
return "Sunny, 25°C";
})
.build();
}
@Bean
public CommandLineRunner functionDemo(
ChatClient chatClient,
List<FunctionCallback> toolCallbacks) {
return args -> {
String response = chatClient.prompt()
.user(u -> u.text("What's the weather in Beijing?"))
.call()
.content();
System.out.println(response);
};
}
7.2 多模态处理
处理图像生成请求:
java复制@Bean
public CommandLineRunner imageGenDemo(ImageClient imageClient) {
return args -> {
ImageResponse response = imageClient.call(
new ImagePrompt("A cat coding on a laptop",
ImageOptions.builder()
.withHeight(1024)
.withWidth(1024)
.build()));
response.getResults().forEach(result -> {
System.out.println("Image URL: " + result.getOutput().getUrl());
});
};
}
在实际项目中,Spring AI的表现远超我的预期。特别是在需要快速切换不同AI供应商的场景下,其统一API设计节省了大量开发时间。一个实用的技巧是:对于生产环境,建议封装一个自定义的ChatClient装饰器,加入重试、降级等容错机制,这能显著提升系统稳定性。
