Spring AI¶
为什么要学¶
Spring AI 将 AI 能力带入 Java Spring 生态系统,让数百万 Java 开发者能用熟悉的方式构建 AI 应用:
- Spring 原生:遵循 Spring 设计哲学,依赖注入、自动配置
- 模型抽象:统一 API 屏蔽不同 AI 提供商差异
- RAG 支持:内置向量存储、文档处理、检索能力
- 工具调用:声明式方法即可成为 AI 工具
- 可观测性:与 Spring Boot Actuator/Micrometer 集成
- 企业就绪:继承 Spring Boot 的生产级特性
如果你是 Java/Spring 开发者,Spring AI 是最自然的 AI 集成方式。
核心概念¶
白话解释¶
Spring AI 就像给 Spring Boot 装了一个"AI 模块": - ChatClient:和 AI 对话的客户端(类比 RestTemplate/WebClient) - Embedding:把文本转成向量(用于搜索) - VectorStore:存储和查询向量的数据库 - Advisor:AOP风格的拦截器,在AI调用前后处理逻辑
核心概念对照表¶
| 概念 | 说明 | Spring类比 |
|---|---|---|
| ChatModel | AI对话模型接口 | JdbcTemplate |
| ChatClient | 高级AI客户端(链式调用) | WebClient |
| Prompt | 发给AI的请求 | HttpRequest |
| Message | 对话中的一条消息 | 请求/响应体 |
| Advisor | 拦截AI调用的中间件 | Spring AOP |
| Tool/Function | AI可调用的Java方法 | @RestController |
| VectorStore | 向量数据库抽象 | JpaRepository |
| DocumentReader | 文档读取器 | 文件解析器 |
| EmbeddingModel | 文本向量化模型 | 序列化器 |
安装配置¶
Maven 依赖¶
<!-- Spring AI BOM -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- OpenAI -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<!-- 向量存储(PgVector) -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pgvector-store-spring-boot-starter</artifactId>
</dependency>
Gradle¶
implementation 'org.springframework.ai:spring-ai-openai-spring-boot-starter'
implementation 'org.springframework.ai:spring-ai-pgvector-store-spring-boot-starter'
application.yml¶
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: gpt-4o-mini
temperature: 0.7
vectorstore:
pgvector:
dimensions: 1536
快速上手¶
基础对话¶
@RestController
@RequestMapping("/api/ai")
public class AiController {
private final ChatClient chatClient;
public AiController(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder.build();
}
@GetMapping("/chat")
public String chat(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
@GetMapping("/chat/stream")
public Flux<String> chatStream(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.stream()
.content();
}
}
带系统提示¶
@GetMapping("/assistant")
public String assistant(@RequestParam String question) {
return chatClient.prompt()
.system("你是一位Java专家,用中文回答,提供代码示例")
.user(question)
.call()
.content();
}
结构化输出¶
// 定义返回结构
public record MovieRecommendation(
String title,
int year,
String genre,
String reason,
double rating
) {}
@GetMapping("/recommend")
public MovieRecommendation recommend(@RequestParam String genre) {
return chatClient.prompt()
.user("推荐一部" + genre + "电影")
.call()
.entity(MovieRecommendation.class);
}
// 列表输出
@GetMapping("/recommend-list")
public List<MovieRecommendation> recommendList(@RequestParam String genre) {
return chatClient.prompt()
.user("推荐3部" + genre + "电影")
.call()
.entity(new ParameterizedTypeReference<List<MovieRecommendation>>() {});
}
进阶用法¶
1. 工具调用(Function Calling)¶
@Service
public class WeatherService {
@Tool(description = "获取指定城市的当前天气")
public String getWeather(@ToolParam(description = "城市名") String city) {
// 实际调用天气API
return city + ": 25°C, 晴天";
}
@Tool(description = "获取天气预报")
public String getForecast(
@ToolParam(description = "城市名") String city,
@ToolParam(description = "预报天数") int days) {
return city + "未来" + days + "天: 晴转多云";
}
}
@RestController
public class WeatherController {
private final ChatClient chatClient;
private final WeatherService weatherService;
@GetMapping("/weather-chat")
public String weatherChat(@RequestParam String question) {
return chatClient.prompt()
.user(question)
.tools(weatherService) // 注册工具
.call()
.content();
}
}
// 用户: "北京今天天气怎么样?" → AI自动调用getWeather("北京")
2. RAG 实现¶
@Configuration
public class RagConfig {
@Bean
public VectorStore vectorStore(EmbeddingModel embeddingModel, JdbcTemplate jdbcTemplate) {
return new PgVectorStore(jdbcTemplate, embeddingModel);
}
}
@Service
public class DocumentService {
private final VectorStore vectorStore;
// 文档导入
public void ingestDocuments(List<Resource> resources) {
// 读取文档
var reader = new TikaDocumentReader(resources);
var documents = reader.get();
// 拆分
var splitter = new TokenTextSplitter();
var chunks = splitter.apply(documents);
// 存入向量库
vectorStore.add(chunks);
}
}
@RestController
public class RagController {
private final ChatClient chatClient;
private final VectorStore vectorStore;
@GetMapping("/rag")
public String ragQuery(@RequestParam String question) {
return chatClient.prompt()
.user(question)
.advisors(new QuestionAnswerAdvisor(vectorStore)) // RAG Advisor
.call()
.content();
}
}
3. Advisor(中间件模式)¶
// 日志Advisor
public class LoggingAdvisor implements CallAroundAdvisor {
@Override
public AdvisedResponse aroundCall(AdvisedRequest request, CallAroundAdvisorChain chain) {
log.info("AI请求: {}", request.userText());
AdvisedResponse response = chain.nextAroundCall(request);
log.info("AI回复: {}", response.response().getResult().getOutput().getContent());
return response;
}
}
// 记忆Advisor(对话历史)
@Bean
public ChatClient chatClient(ChatClient.Builder builder) {
return builder
.defaultAdvisors(
new MessageChatMemoryAdvisor(new InMemoryChatMemory()),
new LoggingAdvisor()
)
.build();
}
4. 多模型支持¶
// 配置多个AI服务
@Bean
@Qualifier("openai")
public ChatModel openaiModel() {
return new OpenAiChatModel(new OpenAiApi(openaiKey));
}
@Bean
@Qualifier("ollama")
public ChatModel ollamaModel() {
return new OllamaChatModel(new OllamaApi("http://localhost:11434"));
}
// 按需选择
@GetMapping("/chat")
public String chat(@RequestParam String model, @RequestParam String msg) {
ChatModel chatModel = "local".equals(model) ? ollamaModel : openaiModel;
return ChatClient.create(chatModel).prompt().user(msg).call().content();
}
5. 图片理解(多模态)¶
@GetMapping("/analyze-image")
public String analyzeImage(@RequestParam String imageUrl) {
return chatClient.prompt()
.user(u -> u.text("描述这张图片的内容")
.media(MimeTypeUtils.IMAGE_PNG, new URL(imageUrl)))
.call()
.content();
}
6. Embedding 和语义搜索¶
@Service
public class SemanticSearchService {
private final EmbeddingModel embeddingModel;
private final VectorStore vectorStore;
public List<Document> search(String query, int topK) {
return vectorStore.similaritySearch(
SearchRequest.query(query)
.withTopK(topK)
.withSimilarityThreshold(0.7)
);
}
}
7. 对话记忆¶
@Bean
public ChatClient memoryChatClient(ChatClient.Builder builder) {
return builder
.defaultAdvisors(
new MessageChatMemoryAdvisor(
new InMemoryChatMemory(),
"default",
10 // 保留最近10条消息
)
)
.build();
}
@GetMapping("/conversation")
public String conversation(
@RequestParam String message,
@RequestParam String sessionId) {
return chatClient.prompt()
.user(message)
.advisors(a -> a.param("chat_memory_conversation_id", sessionId))
.call()
.content();
}
常见问题¶
Q1: 支持哪些 AI 模型?¶
| 提供商 | 模型 | Starter |
|---|---|---|
| OpenAI | GPT-4o/4o-mini | spring-ai-openai |
| Azure | Azure OpenAI | spring-ai-azure-openai |
| Anthropic | Claude | spring-ai-anthropic |
| Ollama | 本地模型 | spring-ai-ollama |
| Gemini | spring-ai-vertex-ai-gemini | |
| AWS | Bedrock | spring-ai-bedrock |
Q2: VectorStore 选择?¶
| 存储 | Starter | 适用 |
|---|---|---|
| PgVector | spring-ai-pgvector-store | 已有PostgreSQL |
| ChromaDB | spring-ai-chroma-store | 快速原型 |
| Milvus | spring-ai-milvus-store | 大规模 |
| Redis | spring-ai-redis-store | 已有Redis |
| Pinecone | spring-ai-pinecone-store | 云托管 |
Q3: 如何处理 API 限流?¶
Spring AI 内置了重试机制,可通过配置调整:
Q4: 如何测试?¶
@SpringBootTest
class AiServiceTest {
@MockBean
private ChatModel chatModel;
@Test
void testChat() {
when(chatModel.call(any(Prompt.class)))
.thenReturn(new ChatResponse(List.of(
new Generation("mocked response")
)));
// 测试你的服务
}
}
参考资源¶
- Spring AI 文档 - 官方文档
- Spring AI GitHub - 源代码
- Spring AI 示例 - 代码示例
- Spring Blog - 官方博客
- Baeldung Spring AI - 教程