Spring AI入门教程(一):简介与ChatClient API详解
一、引言:什么是Spring AI
随着生成式人工智能的爆发,Python 生态中出现了 LangChain、LlamaIndex 等优秀框架,但 Java 开发者却缺乏类似的原生支持。Spring AI 的出现填补了这一空白。
Spring AI 是 Spring 社区推出的一个旨在简化 AI 应用程序开发的框架。它借鉴了 Python 项目的思想,但并非简单移植,而是为 Java 开发者量身打造了一套与 AI 模型交互的标准化 API。其核心理念是:将企业数据和 API 与 AI 模型无缝连接,帮助开发者用熟悉的 Spring 范式快速构建 AI 应用,避免陷入复杂的底层实现。
Spring AI 支持主流的大语言模型(如 OpenAI、DeepSeek、智谱AI 等),并提供了模型抽象、提示模板、检索增强生成(RAG)、工具调用(Tool Calling)等一系列高级功能的封装。
二、快速认知:几个核心概念
在深入代码之前,让我们先快速了解几个 Spring AI 中的重要概念:
- 模型(Model):指各类 AI 算法,如文本生成、图像生成、嵌入向量等。Spring AI 当前重点支持语言、图像、音频三种输入输出类型。
- 提示(Prompt):与模型交互的输入。不同于简单字符串,Spring AI 支持多角色(系统、用户、助手)的提示结构。
- 提示模板(Prompt Template):利用模板引擎(如 StringTemplate)动态填充提示中的变量,类似 Spring MVC 中的视图。
- 嵌入(Embedding):将文本转换为浮点数向量,用于衡量语义相似度,是实现 RAG 的基础。
- Token:模型计费和上下文限制的基本单位。1 个 token 约等于 0.75 个英文单词。
- 结构化输出(Structured Output):将模型生成的字符串解析为 Java 对象(如 JSON → POJO)。
- RAG(检索增强生成):将私有数据分段存入向量数据库,并检索相关片段补充到提示中,使模型能回答训练数据之外的问题。
- 工具调用(Tool Calling):允许模型调用外部 API(如查询天气、发送邮件),扩展模型能力。
对于入门而言,你只需先理解 模型、提示、结构化输出 即可,其余概念将在后续教程中展开。
三、快速开始:搭建第一个 Spring AI 项目
3.1 创建 Maven 项目并添加依赖
使用 Spring Boot 3.x,并引入 Spring AI 的 BOM 及对应的模型 starter(以 DeepSeek 和智谱AI 为例)。
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.5.14</version> <!-- 请使用你实际可用的版本 -->
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>spring-ai-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>17</java.version>
<spring-ai.version>1.1.6</spring-ai.version>
</properties>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Lombok(可选) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Spring AI DeepSeek Starter -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-deepseek</artifactId>
</dependency>
<!-- Spring AI 智谱AI Starter -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-zhipuai</artifactId>
</dependency>
<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>
</project>
注意 :实际使用时,请将
spring-ai.version替换为官方最新版本。
3.2 配置文件 application.yaml
配置多个模型(DeepSeek 和智谱AI),注意 API Key 建议使用环境变量,切勿硬编码到代码中。
yaml
spring:
application:
name: spring-ai-demo
ai:
chat:
client:
enabled: false # 本教程手动配置 ChatClient Bean,故禁用自动配置
deepseek:
base-url: https://api.deepseek.com
api-key: ${DEEPSEEK_API_KEY} # 从环境变量读取
chat:
enabled: true
options:
model: deepseek-chat
temperature: 0.7
zhipuai:
api-key: ${ZHIPU_API_KEY}
chat:
enabled: true
options:
model: glm-4-flash
temperature: 0.7
server:
port: 8188
3.3 配置 ChatClient Bean
ChatClient 是 Spring AI 的核心 API,它提供了流式构建器风格的方法。我们需要为每个模型创建独立的 ChatClient 实例。
java
package com.example.config;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.ai.zhipuai.ZhiPuAiChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ChatClientConfig {
@Bean
public ChatClient deepSeekChatClient(DeepSeekChatModel chatModel) {
return ChatClient.create(chatModel);
}
@Bean
public ChatClient zhiPuAiChatClient(ZhiPuAiChatModel chatModel) {
return ChatClient.create(chatModel);
}
}
至此,项目环境已准备就绪,下面正式进入 ChatClient API 的使用。
四、ChatClient API 详解与实战
ChatClient 采用了流畅的建造者模式,核心方法包括:
prompt():开始构建提示。user()/system():添加用户或系统角色消息。call():同步调用并获取ChatResponse或content()。stream():异步流式调用。entity():将模型输出直接映射为 Java 对象。metadata():为消息附加元数据。
下面通过一个 RestController 来展示各种用法。
4.1 基础对话:选择合适的模型
java
@RestController
@Slf4j
public class ChatController {
@Resource(name = "deepSeekChatClient")
private ChatClient deepSeekClient;
@Resource(name = "zhiPuAiChatClient")
private ChatClient zhiPuClient;
@RequestMapping("/chat")
public String chat(String question, String model) {
ChatClient client = "deepSeek".equals(model) ? deepSeekClient : zhiPuClient;
return client.prompt(question).call().content();
}
}
访问 http://localhost:8188/chat?question=你好&model=deepSeek 即可获得回答。
4.2 多客户端流程演示
有时我们需要同时使用不同的 API Key 或不同模型进行对比,可以手动创建 ChatClient 实例。
java
@Resource
private ZhiPuAiChatModel zhiPuAiChatModel; // 注入默认配置的模型
@RequestMapping("/multi-client")
public String multiClientDemo() {
// 创建第二个独立配置的智谱模型 (glm-4-plus)
ZhiPuAiApi api2 = ZhiPuAiApi.builder()
.apiKey("your-second-api-key")
.build();
ZhiPuAiChatModel model2 = new ZhiPuAiChatModel(api2,
ZhiPuAiChatOptions.builder().model("glm-4-plus").temperature(0.8).build());
ChatClient client2 = ChatClient.create(model2);
String response1 = zhiPuAiChatModel.call("介绍一下人工智能").getResult().getOutput().getText();
String response2 = client2.prompt("介绍一下人工智能").call().content();
return "Default Model: " + response1 + "\n\nCustom Model: " + response2;
}
4.3 返回结构化实体
AI 模型的原始输出是字符串,但我们可以通过 entity() 方法并提供一个 POJO 类,让 Spring AI 自动将输出解析为对象。这背后使用了精心构造的提示词和 JSON 转换器。
定义实体类:
java
public record ActorFilms(String actor, List<String> movies) {}
控制器方法:
java
@RequestMapping("/entity")
public ActorFilms getActorFilms(@RequestParam(defaultValue = "周星驰") String actorName) {
return zhiPuClient.prompt()
.user("请生成演员" + actorName + "的代表作电影列表,包含5部电影")
.call()
.entity(ActorFilms.class);
}
返回 List 泛型时需要使用 ParameterizedTypeReference:
java
@RequestMapping("/entity-list")
public List<ActorFilms> getActorList() {
return zhiPuClient.prompt()
.user("生成 Tom Hanks 和 Leonardo DiCaprio 的电影列表,每人5部")
.call()
.entity(new ParameterizedTypeReference<List<ActorFilms>>() {});
}
4.4 流式响应
对于长文本生成,流式输出能提升用户体验。返回类型需设置为 text/event-stream。
java
@RequestMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> streamResponse(@RequestParam(defaultValue = "讲一个故事") String question) {
return zhiPuClient.prompt(question).stream().content();
}
如果需要获取完整的 ChatResponse 对象(包含 token 使用量等元数据):
java
@RequestMapping(value = "/stream-response", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ChatResponse> streamChatResponse(@RequestParam(defaultValue = "讲一个笑话") String question) {
return zhiPuClient.prompt(question).stream().chatResponse();
}
4.5 使用元数据标记消息
metadata() 可以为系统或用户消息附加额外的键值对信息,便于追踪、调试或下游处理。
java
@RequestMapping("/metadata")
public String metadataDemo() {
return zhiPuClient.prompt()
.system(s -> s.text("你是一个技术客服")
.metadata("agentId", "agent-001")
.metadata("version", "2.0"))
.user(u -> u.text("Spring AI 如何配置多模型?")
.metadata("userId", "12345")
.metadata("sessionId", UUID.randomUUID().toString()))
.call()
.content();
}