news 2026/8/6 17:51:06

Spring AI 实战:从入门到项目落地

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring AI 实战:从入门到项目落地

1. 引言

Spring AI 是 Spring 官方推出的 AI 应用开发框架,旨在为 Java 开发者提供一套统一、简洁的 API,用于对接 OpenAI、Azure OpenAI、Hugging Face、Ollama 等主流大语言模型。它借鉴了 Spring 生态一贯的「约定优于配置」理念,让开发者可以用熟悉的依赖注入、自动配置和模板模式快速构建 AI 应用。

本文将从环境搭建开始,逐步讲解 Spring AI 的核心概念、常用 API,并通过多个可运行的实战案例,带你完成从「Hello World」到「RAG 知识库问答」的完整落地。

2. 环境准备

2.1 技术栈要求

  • JDK:17 及以上(推荐 21)
  • 构建工具:Maven 3.8+ 或 Gradle 7.5+
  • Spring Boot:3.2.x 及以上
  • Spring AI:1.0.0-M6 及以上(本文以 1.0.0-M6 为例)
  • 模型服务:OpenAI API Key,或本地 Ollama 部署的开源模型

2.2 创建项目

推荐使用 Spring Initializr 创建项目,选择 Spring Boot 3.2.x,并添加以下依赖:

<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> <version>1.0.0-M6</version> </dependency>

如果使用 Maven,还需要在pom.xml中配置 Spring AI 的里程碑仓库:

<repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>

2.3 配置 API Key

application.yml中配置 OpenAI 的 API Key 和基础地址:

spring: ai: openai: api-key: ${OPENAI_API_KEY} base-url: https://api.openai.com chat: options: model: gpt-4o-mini temperature: 0.7

如果使用本地 Ollama,则配置如下:

spring: ai: ollama: base-url: http://localhost:11434 chat: options: model: qwen2.5:7b

3. 第一个 AI 应用:ChatClient 入门

3.1 核心概念

Spring AI 的核心抽象是ChatClient,它提供了流式(Fluent)API,用于构建和发送聊天请求。与传统的RestTemplate风格不同,ChatClient支持链式调用,代码可读性更强。

3.2 编写 Controller

下面创建一个简单的 REST 接口,接收用户问题并返回 AI 回答:

import org.springframework.ai.chat.client.ChatClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class ChatController { private final ChatClient chatClient; public ChatController(ChatClient.Builder builder) { this.chatClient = builder.build(); } @GetMapping("/chat") public String chat(@RequestParam String message) { return chatClient.prompt() .user(message) .call() .content(); } }

3.3 测试接口

启动应用后,访问以下地址即可测试:

curl "http://localhost:8080/chat?message=用一句话介绍Spring%20AI"

返回结果示例:

Spring AI 是 Spring 官方推出的 AI 应用开发框架,帮助 Java 开发者以统一、简洁的方式集成大语言模型能力。

4. 流式输出:打字机效果

在实际业务中,流式输出能显著提升用户体验。Spring AI 通过Flux支持响应式流式返回:

import org.springframework.ai.chat.client.ChatClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Flux; @RestController public class StreamChatController { private final ChatClient chatClient; public StreamChatController(ChatClient.Builder builder) { this.chatClient = builder.build(); } @GetMapping("/chat/stream") public Flux<String> streamChat(@RequestParam String message) { return chatClient.prompt() .user(message) .stream() .content(); } }

前端可以使用fetch配合ReadableStream实现打字机效果,也可以直接使用 SSE(Server-Sent Events)协议接收数据。

5. 结构化输出:让 AI 返回 JSON

5.1 定义实体类

很多时候我们需要 AI 返回结构化数据,而不是纯文本。Spring AI 提供了BeanOutputConverter来实现这一需求。首先定义一个实体类:

public record BookInfo(String title, String author, int year, String summary) {}

5.2 使用 BeanOutputConverter

import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.converter.BeanOutputConverter; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class StructuredOutputController { private final ChatClient chatClient; public StructuredOutputController(ChatClient.Builder builder) { this.chatClient = builder.build(); } @GetMapping("/book") public BookInfo getBookInfo(@RequestParam String name) { BeanOutputConverter<BookInfo> converter = new BeanOutputConverter<>(BookInfo.class); String json = chatClient.prompt() .user("请介绍书籍《" + name + "》的信息,包括书名、作者、出版年份和内容简介。" + converter.getFormat()) .call() .content(); return converter.convert(json); } }

这里的关键是converter.getFormat()会在提示词中追加 JSON Schema 约束,引导模型输出符合实体类结构的 JSON,再由converter.convert()完成反序列化。

6. 提示词模板:复用 Prompt

在实际项目中,提示词往往需要动态拼接。Spring AI 提供了PromptTemplate,支持占位符替换:

import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.prompt.PromptTemplate; 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 public class PromptTemplateController { private final ChatClient chatClient; public PromptTemplateController(ChatClient.Builder builder) { this.chatClient = builder.build(); } @GetMapping("/translate") public String translate(@RequestParam String text, @RequestParam String targetLang) { PromptTemplate template = new PromptTemplate( "你是一位专业翻译。请将以下内容翻译成{targetLang},只输出翻译结果:\n{text}"); return chatClient.prompt(template.create(Map.of( "text", text, "targetLang", targetLang ))).call().content(); } }

7. 实战案例:RAG 知识库问答

7.1 什么是 RAG

RAG(Retrieval-Augmented Generation,检索增强生成)是一种将外部知识库与大语言模型结合的技术。它先根据用户问题检索相关文档片段,再将这些片段作为上下文注入提示词,让模型基于真实资料回答,从而减少幻觉、提升准确性。

7.2 添加向量数据库依赖

本文使用 Redis 作为向量数据库,需要添加以下依赖:

<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-redis-store-spring-boot-starter</artifactId> <version>1.0.0-M6</version> </dependency>

7.3 配置向量数据库

spring: data: redis: host: localhost port: 6379 ai: openai: api-key: ${OPENAI_API_KEY} embedding: options: model: text-embedding-3-small

7.4 文档加载与向量化

import org.springframework.ai.document.Document; import org.springframework.ai.reader.TextReader; import org.springframework.ai.transformer.splitter.TokenTextSplitter; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.stereotype.Service; import java.util.List; @Service public class KnowledgeBaseService { private final VectorStore vectorStore; private final ResourceLoader resourceLoader; public KnowledgeBaseService(VectorStore vectorStore, ResourceLoader resourceLoader) { this.vectorStore = vectorStore; this.resourceLoader = resourceLoader; } public void loadDocument(String resourcePath) { Resource resource = resourceLoader.getResource(resourcePath); // 1. 读取文档 TextReader reader = new TextReader(resource); List<Document> documents = reader.get(); // 2. 切分文档 TokenTextSplitter splitter = new TokenTextSplitter(); List<Document> chunks = splitter.apply(documents); // 3. 向量化并存储 vectorStore.add(chunks); } }

7.5 实现问答接口

import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.document.Document; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.List; import java.util.stream.Collectors; @RestController public class RagController { private final ChatClient chatClient; private final VectorStore vectorStore; public RagController(ChatClient.Builder builder, VectorStore vectorStore) { this.chatClient = builder.build(); this.vectorStore = vectorStore; } @GetMapping("/rag") public String ask(@RequestParam String question) { // 1. 检索相关文档 List<Document> documents = vectorStore.similaritySearch( SearchRequest.query(question).withTopK(3)); // 2. 拼接上下文 String context = documents.stream() .map(Document::getText) .collect(Collectors.joining("\n\n")); // 3. 构造提示词并调用模型 return chatClient.prompt() .user("请基于以下资料回答问题。如果资料中没有相关信息,请如实说明。\n\n" + "资料:\n" + context + "\n\n问题:" + question) .call() .content(); } }

7.6 测试 RAG 流程

首先加载知识库文档:

curl -X POST "http://localhost:8080/kb/load?resourcePath=classpath:docs/spring-ai-guide.txt"

然后提问:

curl "http://localhost:8080/rag?question=Spring%20AI支持哪些向量数据库"

8. 函数调用:让 AI 执行工具

8.1 定义工具方法

函数调用(Function Calling)允许模型在回答过程中调用外部工具。下面实现一个查询天气的功能:

import org.springframework.ai.tool.annotation.Tool; import org.springframework.stereotype.Component; @Component public class WeatherTools { @Tool(description = "根据城市名称查询当前天气") public String getWeather(String city) { // 实际项目中可调用第三方天气 API return "城市:" + city + ",天气:晴,温度:26℃,湿度:45%"; } }

8.2 在 ChatClient 中注册工具

import org.springframework.ai.chat.client.ChatClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class FunctionCallingController { private final ChatClient chatClient; public FunctionCallingController(ChatClient.Builder builder, WeatherTools weatherTools) { this.chatClient = builder .defaultTools(weatherTools) .build(); } @GetMapping("/weather") public String askWeather(@RequestParam String question) { return chatClient.prompt() .user(question) .call() .content(); } }

当用户问「北京今天天气怎么样」时,模型会自动调用getWeather("北京")方法,并将返回结果组织成自然语言回答。

9. 多模态:图片理解

Spring AI 还支持多模态输入。以下示例演示如何让模型理解图片内容:

import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.model.Media; import org.springframework.core.io.ClassPathResource; import org.springframework.util.MimeTypeUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class VisionController { private final ChatClient chatClient; public VisionController(ChatClient.Builder builder) { this.chatClient = builder.build(); } @GetMapping("/vision") public String describeImage() { Media image = new Media( MimeTypeUtils.IMAGE_PNG, new ClassPathResource("sample.png").getInputStream()); UserMessage message = new UserMessage( "请描述这张图片的内容", List.of(image)); return chatClient.prompt(new Prompt(message)) .call() .content(); } }

10. 生产实践与注意事项

10.1 错误处理与重试

调用外部模型服务时,网络抖动、限流等问题不可避免。建议使用 Spring Retry 或 Resilience4j 增加重试和熔断机制:

import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Retryable; import org.springframework.stereotype.Service; @Service public class AiService { @Retryable( retryFor = {RuntimeException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000, multiplier = 2)) public String callWithRetry(String prompt) { // 调用 ChatClient return chatClient.prompt().user(prompt).call().content(); } }

10.2 成本控制

  • Token 限制:通过maxTokens限制单次输出长度。
  • 模型选择:简单任务使用小模型(如 gpt-4o-mini),复杂任务才使用大模型。
  • 缓存:对高频、结果稳定的请求做本地缓存。
  • 流式输出:优先使用流式接口,减少等待时间。

10.3 安全与合规

  • 敏感信息过滤:在发送请求前对用户输入做脱敏处理。
  • 输出审核:对模型输出进行内容安全检测。
  • API Key 管理:使用环境变量或配置中心管理密钥,切勿硬编码。
  • 日志脱敏:避免在日志中记录完整的用户输入和模型输出。

11. 总结

本文从零开始,系统讲解了 Spring AI 的核心用法:

  • 环境搭建:通过 Spring Initializr 快速创建项目并配置模型服务。
  • 基础对话:使用ChatClient实现同步和流式问答。
  • 结构化输出:通过BeanOutputConverter让 AI 返回 JSON。
  • 提示词模板:使用PromptTemplate复用和管理提示词。
  • RAG 实战:结合向量数据库实现知识库问答。
  • 函数调用:让模型自动调用外部工具。
  • 多模态:支持图片理解等能力。

Spring AI 仍在快速迭代中,建议持续关注官方文档和 Release Notes。下一步可以尝试将 Spring AI 集成到你的业务系统中,结合函数调用和 RAG 构建更智能的应用。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/6 17:50:55

影刀RPA初级认证考试指南:五大核心组件与典型场景实操

1. 从零开始&#xff1a;影刀RPA初级考试到底考什么&#xff1f;如果你刚接触影刀RPA&#xff0c;或者正打算考取初级认证&#xff0c;心里可能正犯嘀咕&#xff1a;这个“初级考试操作题”到底是个啥&#xff1f;是不是要写一堆复杂的代码&#xff1f;会不会很难&#xff1f;作…

作者头像 李华
网站建设 2026/8/6 17:50:05

Agent 的引用溯源机制:当模型输出自带来源标注

构建一个基于文档回答的 Agent 时&#xff0c;最让人头疼的问题不是 Agent 答不出来&#xff0c;而是它答出来的内容你没法验证。用户问"根据这份合同&#xff0c;违约金是多少"&#xff0c;Agent 返回了一个数字。用户信了。但你怎么知道它没看错条款&#xff1f;你…

作者头像 李华
网站建设 2026/8/6 17:49:00

实话难听,但持证PMP的第三年,我想给想报名的你提个醒……

刷社交平台&#xff0c;随处可见PMP“三个月拿证”“项目经理必备证书”的宣传。一边是全网种草&#xff0c;一边是很多人考完吐槽智商税。 很多职场人都在纠结&#xff1a;PMP到底值不值得考&#xff1f; 我持证3年、已完成续证&#xff0c;一直用PMP方法论落地项目。用真实体…

作者头像 李华
网站建设 2026/8/6 17:48:47

XOutput完整指南:三步将老手柄变身为Xbox控制器

XOutput完整指南&#xff1a;三步将老手柄变身为Xbox控制器 【免费下载链接】XOutput DirectInput to XInput wrapper 项目地址: https://gitcode.com/gh_mirrors/xo/XOutput 你是否曾因为心爱的老式游戏手柄无法在现代游戏中正常工作而感到沮丧&#xff1f;XOutput正是…

作者头像 李华
网站建设 2026/8/6 17:43:50

DevExpress WinForms数据编辑器组件,提供丰富的数据输入样式!(一)

DevExpress WinForms超过80个高影响力的WinForms编辑器和多用途控件&#xff0c;从屏蔽数据输入和内置数据验证到HTML格式化&#xff0c;DevExpress数据编辑库提供了无与伦比的数据编辑选项&#xff0c;包括用于独立数据编辑或用于容器控件(如Grid, TreeList和Ribbon)的单元格。…

作者头像 李华