一、核心价值
-
统一调用范式:ChatClient 抽象层屏蔽不同大模型的调用差异,一套代码适配所有模型
-
灵活的提示词工程:Prompt 组件支持模板化、参数化构建提示词,降低硬编码维护成本
-
标准化响应处理:Response 统一封装返回结果,简化多模型响应格式的适配逻辑
-
可扩展的交互能力:支持同步/异步/流式调用,满足不同业务场景的性能需求
二、前置准备
1. 环境要求
-
JDK 8+、Spring Boot 3.2+、Spring AI 1.0.0.RELEASE
-
任意大模型 API Key(以 OpenAI GPT-4o 为例)
-
Maven/Gradle 构建工具
2. 依赖配置(Maven)
<!– Spring AI 核心依赖 –> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> <version>1.0.0.RELEASE</version> </dependency> <!– Web 依赖(用于接口测试) –> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
3. 基础配置(application.yml)
spring: ai: openai: api-key: ${OPENAI_API_KEY} # 替换为实际API Key base-url: https://api.openai.com/v1 model: gpt-4o temperature: 0.7 # 生成随机性,0-1之间
三、核心 API 深度解析
1. ChatClient:统一的模型调用入口
核心设计
ChatClient 是 Spring AI 最核心的抽象接口,定义了大模型交互的标准化方法,所有模型(OpenAI/通义千问/文心一言)都实现该接口,核心特性:
-
屏蔽不同模型的 API 调用细节
-
支持同步、异步、流式三种调用模式
-
内置请求参数(temperature、topP 等)适配
核心方法
|
方法签名 |
功能说明 |
使用场景 |
|
ChatResponse call(Prompt prompt) |
同步调用,阻塞等待结果 |
简单问答、短文本生成 |
|
CompletableFuture<ChatResponse> callAsync(Prompt prompt) |
异步调用,非阻塞 |
高并发场景、批量处理 |
|
Flux<ChatResponse> stream(Prompt prompt) |
流式调用,逐段返回结果 |
长文本生成、实时交互 |
基础使用示例
import org.springframework.ai.chat.ChatClient; import org.springframework.ai.chat.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/ai/client") public class ChatClientDemoController { // 自动注入OpenAI实现的ChatClient(Spring AI自动装配) @Autowired private ChatClient chatClient; // 同步调用示例 @GetMapping("/sync") public String syncCall(@RequestParam String question) { // 构建Prompt(下文详解) Prompt prompt = new Prompt(question); // 同步调用获取响应 ChatResponse response = chatClient.call(prompt); // 提取回答内容 return response.getResult().getOutput().getContent(); } // 异步调用示例 @GetMapping("/async") public CompletableFuture<String> asyncCall(@RequestParam String question) { Prompt prompt = new Prompt(question); return chatClient.callAsync(prompt) .thenApply(response -> response.getResult().getOutput().getContent()); } // 流式调用示例(返回SSE流) @GetMapping(value = "/stream", produces = "text/event-stream") public Flux<String> streamCall(@RequestParam String question) { Prompt prompt = new Prompt(question); return chatClient.stream(prompt) .map(response -> response.getResult().getOutput().getContent()); } }
2. Prompt:标准化的提示词构建
核心设计
Prompt 是 Spring AI 对“提示词”的标准化封装,核心能力:
-
支持纯文本、模板化、多轮对话三种构建方式
-
可附加模型参数(temperature、topP 等),覆盖单次调用的个性化配置
-
内置 PromptTemplate 实现参数化提示词,避免硬编码
核心组件
|
组件 |
作用 |
示例 |
|
Prompt |
核心封装类,包含提示词内容+调用参数 |
new Prompt(message, parameters) |
|
PromptTemplate |
模板化构建,支持变量替换 |
PromptTemplate.create("生成{language}的{type}代码") |
|
Message |
消息单元,支持用户/系统/助手角色 |
new UserMessage("问题")/new SystemMessage("指令") |
进阶使用示例
import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.chat.prompt.PromptTemplate; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.messages.SystemMessage; import org.springframework.ai.openai.OpenAiChatOptions; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.List; import java.util.Map; @RestController @RequestMapping("/ai/prompt") public class PromptDemoController { @Autowired private ChatClient chatClient; // 1. 多角色消息(系统指令+用户问题) @GetMapping("/multi-role") public String multiRolePrompt(@RequestParam String task) { // 系统消息:定义模型行为 SystemMessage systemMessage = new SystemMessage("你是资深Java工程师,仅输出代码和简要注释,不解释其他内容"); // 用户消息:具体需求 UserMessage userMessage = new UserMessage(task); // 构建Prompt Prompt prompt = new Prompt(List.of(systemMessage, userMessage)); // 调用模型 return chatClient.call(prompt).getResult().getOutput().getContent(); } // 2. 模板化Prompt(参数化替换) @GetMapping("/template") public String templatePrompt( @RequestParam String language, @RequestParam String functionName) { // 定义模板 String template = """ 生成{language}语言的{functionName}函数,要求: 1. 符合行业最佳实践 2. 包含参数校验 3. 输出完整代码和注释 """; // 构建模板并绑定参数 PromptTemplate promptTemplate = PromptTemplate.create(template); Map<String, Object> params = new HashMap<>(); params.put("language", language); params.put("functionName", functionName); // 生成Prompt Prompt prompt = promptTemplate.create(params); // 调用模型 return chatClient.call(prompt).getResult().getOutput().getContent(); } // 3. 自定义调用参数(覆盖全局配置) @GetMapping("/custom-params") public String customParamsPrompt(@RequestParam String question) { // 自定义参数:调低随机性,设置最大Token OpenAiChatOptions options = OpenAiChatOptions.builder() .temperature(0.1) // 趋近确定性输出 .maxTokens(1000) // 限制返回长度 .build(); // 构建Prompt并附加参数 Prompt prompt = new Prompt(question, options); // 调用模型 return chatClient.call(prompt).getResult().getOutput().getContent(); } }
3. ChatResponse:标准化的响应处理
核心设计
ChatResponse 是模型返回结果的统一封装,核心特性:
-
屏蔽不同模型的响应格式差异(OpenAI/通义千问等返回结构统一)
-
支持提取核心内容、元数据(Token消耗、模型名称等)、多轮对话ID
-
流式响应逐段封装,便于实时处理
核心属性与方法
|
属性/方法 |
作用 |
示例 |
|
getResult() |
获取核心结果对象 |
response.getResult() |
|
getOutput().getContent() |
提取回答文本 |
response.getResult().getOutput().getContent() |
|
getMetadata() |
获取元数据(Token、耗时等) |
response.getMetadata().get("token_usage") |
|
getId() |
获取对话ID(用于多轮对话) |
response.getId() |
完整解析示例
import org.springframework.ai.chat.ChatResponse; import org.springframework.ai.chat.metadata.ChatGenerationMetadata; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.openai.metadata.OpenAiChatResponseMetadata; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.Map; @RestController @RequestMapping("/ai/response") public class ResponseDemoController { @Autowired private ChatClient chatClient; @GetMapping("/parse") public Map<String, Object> parseResponse(@RequestParam String question) { Prompt prompt = new Prompt(question); ChatResponse response = chatClient.call(prompt); // 1. 核心回答内容 String content = response.getResult().getOutput().getContent(); // 2. 元数据解析(以OpenAI为例) ChatGenerationMetadata metadata = response.getResult().getMetadata(); OpenAiChatResponseMetadata openAiMetadata = (OpenAiChatResponseMetadata) metadata; // Token消耗 int promptTokens = openAiMetadata.getTokenUsage().getPromptTokens(); int completionTokens = openAiMetadata.getTokenUsage().getCompletionTokens(); // 模型名称 String modelName = openAiMetadata.getModel(); // 响应ID String responseId = response.getId(); // 封装返回结果 return Map.of( "content", content, "prompt_tokens", promptTokens, "completion_tokens", completionTokens, "model_name", modelName, "response_id", responseId ); } }
四、常见问题及解决方案
|
错误类型 |
报错信息 |
解决方案 |
|
Prompt 构建异常 |
"Message list cannot be empty" |
确保 Prompt 至少包含一条有效 Message(UserMessage/SystemMessage) |
|
响应解析失败 |
"ClassCastException: xxx cannot be cast to OpenAiChatResponseMetadata" |
按模型类型强转元数据,或使用通用 Metadata 接口 |
|
流式响应无输出 |
"Flux stream is empty" |
检查请求头是否为 text/event-stream,或模型是否支持流式输出 |
|
自定义参数不生效 |
"Temperature setting ignored" |
确认参数类与模型匹配(如 OpenAiChatOptions 仅适用于 OpenAI) |
五、进阶扩展
1. 自定义 ChatClient 包装类(统一异常处理)
import org.springframework.ai.chat.ChatClient; import org.springframework.ai.chat.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.stereotype.Component; @Component public class CustomChatClient { private final ChatClient delegate; public CustomChatClient(ChatClient chatClient) { this.delegate = chatClient; } // 包装调用逻辑,统一异常处理 public String safeCall(Prompt prompt) { try { ChatResponse response = delegate.call(prompt); return response.getResult().getOutput().getContent(); } catch (Exception e) { // 统一异常处理+降级逻辑 return "模型调用失败:" + e.getMessage() + ",建议稍后重试"; } } }
2. Prompt 模板复用(全局模板管理)
import org.springframework.ai.chat.prompt.PromptTemplate; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @Configuration public class PromptTemplateConfig { // 全局Prompt模板缓存 @Bean public Map<String, PromptTemplate> promptTemplateCache() { Map<String, PromptTemplate> cache = new ConcurrentHashMap<>(); // 预加载常用模板 cache.put("java-code", PromptTemplate.create("生成符合{standard}标准的Java{type}代码,包含完整注释")); cache.put("sql-optimize", PromptTemplate.create("优化以下SQL:{sql},说明优化思路和执行计划")); return cache; } }
3. 响应结果封装(统一返回格式)
// 自定义响应DTO public record AiResponseDTO( String content, // 核心回答 Integer promptTokens, // 输入Token Integer compTokens, // 输出Token String model, // 调用模型 Long responseTime // 响应耗时 ) {} // 封装工具方法 public AiResponseDTO wrapResponse(ChatResponse response, long startTime) { OpenAiChatResponseMetadata metadata = (OpenAiChatResponseMetadata) response.getResult().getMetadata(); return new AiResponseDTO( response.getResult().getOutput().getContent(), metadata.getTokenUsage().getPromptTokens(), metadata.getTokenUsage().getCompletionTokens(), metadata.getModel(), System.currentTimeMillis() – startTime ); }
总结
ChatClient 是核心调用入口,通过抽象层实现多模型统一调用,支持同步/异步/流式三种模式,适配不同业务场景;
Prompt 组件支持多角色消息、模板化构建,是实现精准提示词工程的核心,可附加自定义调用参数覆盖全局配置;
ChatResponse 标准化封装响应结果,不仅能提取核心回答,还可解析Token消耗、模型名称等元数据,便于监控和成本核算。



