Spring AI基础
一、Spring AI基础
1.1、非Spring AI案例
1.1.1、导入如下依赖
<!-- 阿里 FastJSON2(解析AI返回的JSON,必须) --> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>2.0.32</version> </dependency> <!--Hutool 工具包(可选,但强烈推荐,简化HTTP请求) --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.31</version> </dependency>1.1.2、编写Java代码
使用hutool中提供工具类,实现对接智谱大模型
public class ZhipuAIConnection { // 定义智谱AI的API密钥,需要替换为实际的密钥 private static final String API_KEY = "你的智谱API_KEY"; // 定义智谱AI的API接口地址(GLM-4模型) private static final String URL = "https://open.bigmodel.cn/api/paas/v4/chat/completions"; public static void main(String[] args) { // 创建Scanner对象,用于从控制台读取用户输入 Scanner scan = new Scanner(System.in); // 读取用户输入的问题或消息 String message = scan.nextLine(); // 构建请求体,这是一个Map结构,将转换为JSON格式 Map<String, Object> body = new HashMap<>(); // 指定使用的AI模型为"glm-4" body.put("model", "glm-4"); // 构建消息列表,包含用户输入的内容 // List.of()创建不可变列表,Map.of()创建不可变映射 body.put("messages", List.of(Map.of("role", "user", "content", message))); // 使用HttpRequest发送POST请求到智谱AI接口 String resp = HttpRequest.post(URL) // 设置请求头:指定内容类型为JSON格式 .header("Content-Type", "application/json") // 设置请求头:添加授权信息,Bearer Token格式 .header("Authorization", "Bearer " + API_KEY) // 将请求体Map转换为JSON字符串 .body(JSON.toJSONString(body)) // 执行HTTP请求 .execute() // 获取响应体的字符串内容 .body(); // 解析返回的JSON响应 JSONObject json = JSON.parseObject(resp); // 从JSON响应中提取AI生成的回复内容 // 解析路径:choices -> 第一个元素 -> message -> content String result = json.getJSONArray("choices") .getJSONObject(0) .getJSONObject("message") .getString("content"); // 将AI的回复输出到控制台 System.out.println(result); } }总结:
- 代码冗余巨大,同样功能 Spring AI 只需 3 行
- 硬编码(API_KEY、URL 写死在代码里)
- 无任何异常处理
- 不支持多模型切换(智谱 ↔ 通义 ↔ OpenAI)
1.2、Spring AI相关理论
1.2.1、Spring AI是什么?
Spring AI 是 Spring 官方推出、面向 Java/Spring 生态的「企业级大模型集成框架」,用来把各种 AI 模型(智谱、通义、OpenAI 等)无缝接入 Spring 应用。
所以,它不是造大模型,而是让 Spring 项目轻松安全地调用大模型,定位类似 Python 的 LangChain,但完全 Java 原生、Spring 原生。
1.2.2、Spring AI 核心特点
1.统一 API,一套代码跑遍所有大模型(模型无关)
- 智谱、通义千问、OpenAI、Claude、本地 Ollama →同一个 ChatClient 接口
- 换模型只改配置,不改 Java 代码
- 可以解决你上面那段代码的「硬编码、换模型要重写」问题
2.Spring 生态原生
- 完美集成Spring Boot / Spring Cloud / 自动配置 / Starter
- 用@Autowired、yml 配置、依赖注入,和平时写 Spring 代码一模一样
- 直接能用AOP、事务、日志、监控、连接池、重试等企业能力
3.极简代码,告别手动拼接 HTTP
- 上述案例中的几十行代码,Spring AI3 行搞定:
chatClient.prompt().user("你好").call().content();- 自动:请求头、JSON 序列化、鉴权、异常处理、响应解析
4.内置完整异常与重试机制(生产可用)
- 超时、限流、鉴权失败、网络波动 →框架自动处理Spring
- 自带AiException、重试、超时、连接池,不用自己写容错Spring
5.支持 Function Calling(函数调用)
- 大模型可以直接调用你本地 Java 方法(查数据库、调接口、查天气)
- 只需@Tool 注解,自动注册、自动调用、自动回传结果
6.支持流式输出(打字机效果)
- 原生 SSE 很难写,Spring AI一行代码实现逐字返回
chatClient.prompt().stream().chatResponse()二、Spring AI入门案例
2.1、搭建整合案例
2.1.1、使用技术栈
JDK17+、SpringBoot .3.3.10、智谱AI GLM系列模型(glm-4、glm-4-flash)
2.1.2、导入项目依赖
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.10</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.wn</groupId> <artifactId>boot-ai-zhipu</artifactId> <version>0.0.1-SNAPSHOT</version> <name>boot-ai-zhipu</name> <description>boot-ai-zhipu</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-zhipuai</artifactId> <version>1.1.6</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies>2.1.3、配置应用环境
需通过环境变量读取,禁止在代码、配置文件中明文硬编码,防止密钥泄露。
2.1.4、application.yml配置文件
spring: ai: zhipuai: # 智谱AI的API密钥,通过系统环境变量ZHIPUAI_API_KEY动态注入,避免硬编码泄露密钥 api-key: ${ZHIPU_API_KEY} # 智谱AI聊天服务的配置选项 chat: options: model: glm-4 # 指定调用的智谱大模型版本,此处为glm-4,可根据需求更换为glm-3等其他支持的模型2.1.5、新建聊天控制器
控制器类中,同时实现同步和流式响应案例
/** * 智谱AI(GLM大模型)对话控制器 * 基于 Spring AI 自动配置,提供【同步调用】与【流式响应】两种标准AI接口 */ @RestController @RequestMapping("/ai") public class ZhipuAiController { /** * Spring AI 核心聊天模型接口 * 自动注入智谱GLM的具体实现,屏蔽底层HTTP调用、鉴权、JSON解析细节 * 支持:同步调用、流式调用、函数调用、上下文管理等核心能力 */ @Autowired private ChatModel chatModel; /** * 【同步阻塞式】AI对话接口 * 特点:等待大模型完整生成所有内容后,一次性返回全部结果 * 适用场景:简单问答、指令执行、非前端交互、后台任务 * * @param msg 用户提问内容(默认值:你好!) * @return 大模型生成的完整文本结果 */ @GetMapping("call") public String call(@RequestParam(value = "msg", defaultValue = "你好!") String msg) { // 同步调用AI模型,阻塞等待完整响应,返回生成的文本内容 return chatModel.call(msg); } /** * 【流式非阻塞】AI对话接口(SSE服务器推送) * 特点:大模型逐字返回内容,前端实时接收(打字机效果) * 适用场景:AI聊天机器人、长文本生成、前端交互体验优化 * produces = MediaType.TEXT_EVENT_STREAM_VALUE:声明响应为SSE流式事件流 * * @param msg 用户提问内容(默认值:你好!) * @param response 设置响应编码,防止中文乱码 * @return Flux<String> 响应式流式流,逐段返回AI生成内容 */ @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> stream( @RequestParam(value = "msg", defaultValue = "你好!") String msg, HttpServletResponse response ) { // 设置响应字符编码,确保中文内容正常显示 response.setContentType("text/html;charset=utf-8"); // 流式调用AI模型,返回Flux响应式流,实现实时逐字输出 return chatModel.stream(msg); } }2.2、SSE协议
2.2.1、SSE是什么?
SSE = Server-Sent Events 服务器推送事件
通俗翻译:浏览器 / 客户端只发起一次请求,服务器可以源源不断主动给客户端发消息,直到断开连接。
传统 HTTP:一问一答,客户端问一次、服务器答一次,完事。SSE:一次请求,服务器无限主动推送。
2.2.2、SSE 核心特点
- 基于标准 HTTP 协议
不用额外端口、不用特殊配置、防火墙不拦截。
- 单向通信
只能:服务器 向 客户端 推送消息,客户端不能通过这个通道给服务器发消息。单向!单向!
- 长连接
一次请求建立连接,一直保持,服务器持续推送数据。
- 自动重连
网络断了、页面刷新,浏览器自动帮你重连服务器,不用前端写重连逻辑。
- 数据格式简单
固定格式:data: 内容\n\n只传文本、字符串、JSON,不传二进制。
2.2.3、为什么AI流式回答都用SSE?
- AI 是一字一字逐步生成的,不是一次性生成完
- 需要生成一个字、立刻推给前端一个字
- 普通 HTTP 要等全部生成完才返回,体验极差
- SSE 天生适合服务端持续流式推送
2.2.4、SSE 和 WebSocket 最核心区别
| 特性 | SSE | WebSocket |
|---|---|---|
| 协议 | 基于普通 HTTP | 独立 WS 协议 |
| 通信方向 | 单向服务端推给客户端 | 双向双方互相发消息 |
| 复杂度 | 极低,几行代码搞定 | 复杂,需握手、心跳、重连 |
| 浏览器支持 | 原生支持,自动重连 | 需自己封装 |
| 适用场景 | AI 流式输出、公告、日志、实时通知 | 聊天室、实时对战、双向聊天 |
2.2.5、SSE 适用场景
- AI 大模型流式对话(打字机效果)
- 系统公告、实时通知
- 日志实时打印、后台任务进度推送
- 股票实时行情、简单数据推送
- 大屏实时数据展示
注:只要是「服务端主动持续给前端发消息」优先用 SSE。
2.2.6、总结
- SSE 是基于 HTTP 的服务器单向推送协议。
- 一次请求,长久连接,服务器主动持续发消息。
- 适合AI 流式输出、通知、进度推送。
- 单向用 SSE,双向聊天用 WebSocket。
- 天生简单、浏览器原生支持、自动重连、开发成本极低。
