跳到主要内容
Spring AI 框架入门与实战指南 | 极客日志
Java AI java 算法
Spring AI 框架入门与实战指南 Spring AI 是 Spring 生态下的 AI 工程框架,旨在简化大模型应用开发。内容涵盖框架简介、DeepSeek 集成、ChatClient 与 ChatModel 使用、函数调用机制、本地 Ollama 部署、阿里云 DashScope 对接以及 RAG 检索增强生成实战。通过多个子模块示例,展示图像生成、语音合成及综合招聘助手场景,帮助开发者快速掌握 Spring AI 的核心能力与落地实践。
人间过客 发布于 2026/3/22 更新于 2026/5/4 6 浏览Spring AI 框架入门与实战指南
在当今快速发展的技术时代,人工智能 (AI) 已成为各行各业的基础设施。作为主流的 Java 应用开发框架,Spring 社区紧跟潮流推出了 Spring AI 框架,旨在将 Spring 生态系统的设计原则(如可移植性和模块化)应用于 AI 领域。
1. Spring AI 简介
什么是 Spring AI
Spring AI 是一个 AI 工程领域的应用程序框架。它的核心目标是提供开发 AI 大模型应用所需的基本抽象模型,这些抽象拥有多种实现方式,使得开发者可以用很少的代码改动就能实现组件的轻松替换。简言之,它提供了一个友好的 API 和开发 AI 应用的抽象,旨在简化 AI 大模型应用的开发工作。
目前 Spring AI 推出了预览版 (PRE)、快照版 (SNAPSHOT) 以及正式版 (GA)。推荐使用 GA 版本,因为它最为稳定;SNAPSHOT 版本会持续更新;PRE 版本主要供测试人员查找 Bug。
主要功能
多模型支持 :对主流 AI 大模型供应商提供了支持,比如 OpenAI、DeepSeek、Microsoft、Ollama、Amazon、Google HuggingFace 等。
多模态能力 :支持聊天、文本到图像、文本到声音等 AI 大模型类型。
向量数据库集成 :支持主流的 Embedding Models 和向量数据库,如 Azure Vector Search、Chroma、Milvus、Neo4j、Redis、PineCone、PostgreSQL/PGVector 等。
对象映射 :把 AI 大模型输出映射到简单的 Java 对象(POJOs)上。
函数调用 :支持了函数调用 (Function Calling) 功能。
数据工程 :为数据工程提供 ETL(数据抽取、转换和加载)框架。
自动配置 :支持 Spring Boot 自动配置和快速启动,便于运行 AI 模型和管理向量库。
2. 快速入门
准备工作
DeepSeek 简介
DeepSeek 是一款由深度求索开发的 AI 人工智能大模型,基于深度学习和多模态数据融合技术,采用先进的 Transformer 架构。其推出的'深度思考'模式在极低成本下实现了与国际顶尖模型相媲美的性能表现,中文理解与输出能力尤为出色。
特点:
成本 :致力于降低 AI 应用的推理和训练成本。
性能 :使用强化学习技术训练,推理过程中包含大量反思与验证,处理复杂数据和任务能力强。
功能 :擅长数学、编程和复杂逻辑推理,支持多模态信息处理。
对于 Java 应用来说,我们可以借助 Spring AI 集成 DeepSeek,非常简单方便。
创建 API KEY
进入 DeepSeek 官网,点击右上角的 API 开放平台,注册登录后即可创建 API Key。接口文档地址为 https://api-docs.deepseek.com/zh-cn/。
Spring AI 的 openai starter 本质上是通过 RestTemplate 发请求。
创建 SpringBoot 工程
在 IDEA 中创建一个 SpringBoot 项目(作为父模块),再创建一个子模块。注意 Spring AI 对于 SpringBoot 和 JDK 的版本要求,建议使用 JDK 17 及以上。
引入依赖
在父模块的 pom.xml 中添加如下公共依赖:
<properties >
< > 17
17
1.0.0-M5
org.springframework.boot
spring-boot-starter-web
org.springframework.ai
spring-ai-openai-spring-boot-starter
org.springframework.boot
spring-boot-starter-test
test
org.projectlombok
lombok
1.18.30
org.springframework.ai
spring-ai-bom
${spring-ai.version}
pom
import
maven.compiler.source
</maven.compiler.source >
<maven.compiler.target >
</maven.compiler.target >
<spring-ai.version >
</spring-ai.version >
</properties >
<dependencies >
<dependency >
<groupId >
</groupId >
<artifactId >
</artifactId >
</dependency >
<dependency >
<groupId >
</groupId >
<artifactId >
</artifactId >
</dependency >
<dependency >
<groupId >
</groupId >
<artifactId >
</artifactId >
<scope >
</scope >
</dependency >
<dependency >
<groupId >
</groupId >
<artifactId >
</artifactId >
<version >
</version >
</dependency >
</dependencies >
<dependencyManagement >
<dependencies >
<dependency >
<groupId >
</groupId >
<artifactId >
</artifactId >
<version >
</version >
<type >
</type >
<scope >
</scope >
</dependency >
</dependencies >
</dependencyManagement >
配置文件 在子模块的 application.properties 中添加配置内容:
server.port=8899
spring.application.name=spring-ai-deepseek-demo
# DeepSeek 的 Api key
spring.ai.openai.api-key=sk-****************
spring.ai.openai.base-url=https://api.deepseek.com
spring.ai.openai.chat.options.model=deepseek-chat
spring.ai.openai.chat.options.temperature=0.7
其中,temperature 参数用于控制生成文本的多样性。值越高,生成的文本越多样化但也可能更随机;值越低,生成的文本越接近确定性结果,更加一致和可预测。
启动类 @SpringBootApplication
public class SpringAiHelloApplication {
public static void main (String[] args) {
SpringApplication.run(SpringAiHelloApplication.class, args);
}
}
Controller 编写一个简单的 Controller 来调用模型:
package com.atguigu.ai.controller;
import jakarta.annotation.Resource;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ChatDeepSeekController {
@Resource
private OpenAiChatModel chatModel;
@GetMapping("/ai/generate")
public String generate (@RequestParam(value = "message", defaultValue = "hello") String message) {
String response = this .chatModel.call(message);
System.out.println("response: " + response);
return response;
}
}
测试 进行接口测试,输入 localhost:8899/ai/generate?message=尚硅谷,等待片刻即可看到返回结果。
3. Spring AI 的聊天模型
概述 Spring AI 的聊天模型 API 为开发者提供了一条便捷通道,能够将强大的 AI 驱动的聊天完成功能无缝集成到各类应用中。借助预先训练的语言模型,它能够依据用户输入生成自然流畅、类人化的回复。这一 API 不仅工作机制高效,而且设计理念极为先进,旨在实现简单易用与高度可移植性。
ChatClient 接口 **ChatClient 是一个接口,它定义了一个与聊天服务交互的客户端。**主要用于创建聊天客户端对象,设置请求规范,以及发起聊天请求。
在下面的示例执行之前,建议创建一个名为 springai_chat 的子模块,并将上面的 application.properties 配置文件拷贝一份,并修改端口号为 8890。
实现简单的对话 需求 :用户输入设置用户消息的内容,通过 SpringBoot AI 封装的方法向 AI 模型发送请求,以字符串形式返回 AI 模型的响应。
package com.atguigu.ai.controller;
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 chatClientBuilder) {
this .chatClient = chatClientBuilder.build();
}
@GetMapping("/chat")
public String chat (@RequestParam(value = "message", defaultValue = "你是谁") String message) {
return this .chatClient.prompt()
.user(message)
.call()
.content();
}
}
总结 :ChatClient 接口提供了构建和配置聊天客户端对象的灵活性。用户可以通过 ChatClient.Builder 来定制客户端的行为,然后使用 prompt() 和 call() 方法发起聊天请求。
实现角色预设 package com.atguigu.ai.config;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AIConfig {
@Bean
public ChatClient chatClient (ChatClient.Builder builder) {
return builder.defaultSystem("你是一名资深的 Java 开发专家,精通 Java 开发,名字叫 AI 助手。" ).build();
}
}
package com.atguigu.ai.controller;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/ai")
public class ChatAIController {
@Resource
private ChatClient chatClient;
@GetMapping("/chat")
public String chat (@RequestParam(value = "message") String message) {
return chatClient.prompt().user(message).call().content();
}
}
实现流式响应
非流式输出 call :等待大模型把回答结果全部生成后输出给用户。
流式输出 stream :逐个字符输出,一方面符合大模型生成方式的本质,另一方面当模型推理效率不是很高时,流式输出比起全部生成后再输出大大提高用户体验。
@GetMapping(value = "/chat/stream", produces = "text/html;charset=UTF-8")
public Flux<String> chatStream (@RequestParam(value = "message") String message) {
return chatClient.prompt().user(message).stream().content();
}
在浏览器中输入对应地址,响应结果会以流式输出的方式展示。
ChatModel 接口
概述 ChatModel 接口作为核心,定义了与 AI 模型交互的基本方法。它继承自 Model<Prompt, ChatResponse>,提供了两个重载的 call 方法。带有 String 参数的 call() 方法简化了实际的使用,避免了更复杂的 Prompt 和 ChatResponse 类的复杂性。但在实际应用程序中,更常见的是使用 ChatResponse call() 方法,该方法采用 Prompt 实例并返回 ChatResponse。
实现简单对话 package com.atguigu.ai.controller;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/model")
public class ChatModelController {
@Resource
private ChatModel chatModel;
@GetMapping("/chatModel01")
public String chatModel01 (@RequestParam("message") String message) {
return chatModel.call(message);
}
@GetMapping("/chatModel02")
public String chatModel02 (@RequestParam("message") String message) {
ChatResponse call = chatModel.call(new Prompt (
message,
OpenAiChatOptions.builder()
.model("deepseek-chat" )
.temperature(0.8 )
.build()));
return call.getResult().getOutput().getContent();
}
}
提示词 提示词是引导大模型生成特定输出的输入,设计和措辞会极大地影响模型的响应结果。Prompt 提示词是与模型交互的一种输入数据组织方式,本质上是一种复合结构的输入,在 prompt 我们是可以包含多组不同角色(System、User、Assistant 等)的信息。
Spring AI 提供了 Prompt Template 提示词模板管理抽象,开发者可以预先定义好模板,并在运行时替换模板中的关键词。
@GetMapping("/prompt")
public String prompt (@RequestParam("name") String name, @RequestParam("voice") String voice) {
String userText = "给我推荐北京的至少三种美食" ;
UserMessage userMessage = new UserMessage (userText);
String systemText = "你是一个美食咨询助手,可以帮助人们查询美食信息。你的名字是{name},你应该用你的名字和{voice}的饮食习惯回复用户的请求。" ;
SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate (systemText);
Message systemMessage = systemPromptTemplate.createMessage(Map.of("name" , name, "voice" , voice));
Prompt prompt = new Prompt (List.of(userMessage, systemMessage));
List<Generation> results = chatModel.call(prompt).getResults();
return results.stream().map(x -> x.getOutput().getContent()).collect(Collectors.joining("" ));
}
4. Spring AI 的函数调用
概述 Spring AI 的函数调用 (Function Calling) 功能允许大语言模型在生成回答时触发预定义的外部函数,从而实现动态数据获取或业务逻辑操作(如查询数据库、调用 API 等)。Spring AI 帮我们规范了函数定义、注册等过程,并在发起模型请求之前自动将函数注入到 Prompt 中。
定义函数 :声明可供模型调用的函数(名称、描述、参数结构)。
模型交互 :将函数信息与用户输入一起发送给模型,模型决定是否需要调用函数。
执行函数 :解析模型的函数调用请求,执行对应的业务逻辑。
返回结果 :将函数执行结果返回给模型,生成最终回答。
函数调用实现
在下面的示例执行之前,建议创建一个名为 springai_function 的子模块,并将上面的 application.properties 配置文件拷贝一份,并修改端口号为 8891。
创建自定义的 Function 下面 CalculatorService 类自定义了加法和乘法运算的函数。
package com.atguigu.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Description;
import java.util.function.Function;
@Slf4j
@Configuration
public class CalculatorService {
public record AddOperation (int a, int b) {}
public record MulOperation (int m, int n) {}
@Bean
@Description("加法运算")
public Function<AddOperation, Integer> addOperation () {
return request -> {
log.info("执行加法运算:{} + {} = {}" , request.a, request.b, request.a + request.b);
return request.a + request.b;
};
}
@Bean
@Description("乘法运算")
public Function<MulOperation, Integer> mulOperation () {
return request -> {
log.info("执行乘法运算:{} * {} = {}" , request.m, request.n, request.m * request.n);
return request.m * request.n;
};
}
}
Spring AI 使自定义函数这个过程变得简单,只需定义一个返回 java.util.Function 并用 @Bean 标注的方法,并在调用 ChatModel 时将 bean 名称作为选项进行注册即可。
编写 Controller package com.atguigu.controller;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class FunctionController {
@Resource
private ChatModel chatModel;
@GetMapping(value = "/function", produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
public String ragJsonText (@RequestParam(value = "message") String message) {
return ChatClient.builder(chatModel).build()
.prompt()
.system("""
您是算术计算器的代理。您能够支持加法运算、乘法运算等操作。
当用户询问数学计算时,您必须调用相应的函数来处理。
支持的函数:
- addOperation: 加法运算,需要两个数字参数
- mulOperation: 乘法运算,需要两个数字参数
调用函数的条件:
1. 用户明确要求计算
2. 问题涉及加法或乘法
3. 能够从问题中提取出两个数字
请用中文回复,并在适当的时候调用函数。
""" )
.user(message)
.functions("addOperation" , "mulOperation" )
.call()
.content();
}
}
为了让模型知道并调用你的自定义函数,需要在 Prompt 请求中启用它,如上述代码,在 functions("addOperation", "mulOperation") 中告知 ChatClient 要使用这两个自定义函数。另外指定了 System Prompt,它要求 AI 模型被设定为一个算术计算器代理。
测试 在接口测试工具中输入 localhost:8891/function/message=2 加 3 等于多少,查看日志可以判断大模型是否真的调用了自定义的函数。
5. Spring AI 调用 Ollama
下载并安装 Ollama Ollama 是一个用于本地化部署和管理大型语言模型 (LLM) 的工具。它支持多种开源模型,并提供了简单的 API 接口,方便开发者调用。
拉取 DeepSeek 模型 根据自己的硬件配置选择合适的版本。例如,下载 1.5b 版本,执行命令:
ollama pull deepseek-r1:1.5b
启动 Ollama 服务测试 启动 Ollama 服务,默认会监听 http://localhost:11434。
ollama run deepseek-r1:1.5b
Spring AI 代码测试
创建子模块 springai_ollama <properties >
<maven.compiler.source > 17</maven.compiler.source >
<maven.compiler.target > 17</maven.compiler.target >
<spring-ai.version > 1.0.0-M5</spring-ai.version >
</properties >
<dependencies >
<dependency >
<groupId > org.springframework.ai</groupId >
<artifactId > spring-ai-ollama-spring-boot-starter</artifactId >
</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 >
<repositories >
<repository >
<id > spring-milestones</id >
<name > Spring Milestones</name >
<url > https://repo.spring.io/milestone</url >
<snapshots > <enabled > false</enabled > </snapshots >
</repository >
<repository >
<id > spring-snapshots</id >
<name > Spring Snapshots</name >
<url > https://repo.spring.io/snapshot</url >
<releases > <enabled > false</enabled > </releases >
</repository >
</repositories >
配置文件 server.port=8892
spring.application.name=spring-ai-deepseek-demo
spring.ai.ollama.base-url=http://localhost:11434
spring.ai.ollama.chat.options.model=deepseek-r1:1.5b
spring.ai.ollama.chat.options.temperature=0.7
Controller package com.atguigu.ai.ollama.controller;
import jakarta.annotation.Resource;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/ollama")
public class SpringAiOllamaController {
@Resource
private OllamaChatModel ollamaChatModel;
@GetMapping("/test")
public String generate (@RequestParam(value = "message", defaultValue = "hello") String message) {
String response = this .ollamaChatModel.call(message);
System.out.println("response: " + response);
return response;
}
}
6. Spring AI Alibaba
概述 随着生成式 AI 的快速发展,涌现出了包括 LangChain、LlamaIndex 等开发框架,但大部分框架只提供了 Python 语言的实现。Spring AI Alibaba 是阿里云通义系列模型及服务在 Java AI 应用开发领域的最佳实践,通过提供一种方便的 API 抽象,帮助 Java 开发者加速和简化 Java 智能体应用的开发。
快速入门
申请阿里云 API Key 访问阿里云百炼页面并登录账号,开通'百炼大模型推理'服务,获取 API Key。
引入依赖 创建一个名为 springai_alibaba 的子模块,引入如下依赖:
<properties >
<maven.compiler.source > 17</maven.compiler.source >
<maven.compiler.target > 17</maven.compiler.target >
<spring-ai.version > 1.0.0-M5</spring-ai.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 > com.alibaba.cloud.ai</groupId >
<artifactId > spring-ai-alibaba-starter</artifactId >
<version > 1.0.0-M5.1</version >
</dependency >
</dependencies >
<repositories >
<repository >
<id > spring-milestones</id >
<name > Spring Milestones</name >
<url > https://repo.spring.io/milestone</url >
<snapshots > <enabled > false</enabled > </snapshots >
</repository >
</repositories >
配置文件 server.port=8893
spring.application.name=spring-ai-deepseek-demo
spring.ai.dashscope.api-key=sk-*****cf
# 排除父模块中 Spring AI 的自动配置,否则当前子模块启动时会提示冲突
spring.autoconfigure.exclude=org.springframework.ai.autoconfigure.openai.OpenAiAutoConfiguration
Controller package com.atguigu.controller;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SpringAiAlibabaController {
private static final String DEFAULT_PROMPT = "你是一个博学的智能聊天助手,请根据用户提问回答!" ;
private ChatClient dashScopeChatClient;
public SpringAiAlibabaController (ChatClient.Builder chatClientBuilder) {
this .dashScopeChatClient = chatClientBuilder
.defaultSystem(DEFAULT_PROMPT)
.defaultAdvisors(new MessageChatMemoryAdvisor (new InMemoryChatMemory ()))
.defaultAdvisors(new SimpleLoggerAdvisor ())
.defaultOptions(DashScopeChatOptions.builder().withTopP(0.7 ).build())
.build();
}
@GetMapping("/simple/chat")
public String simpleChat (@RequestParam("query") String query) {
return dashScopeChatClient.prompt(query).call().content();
}
}
7. Spring AI 的其他模型
图像模型
Image Model API 概述 在 Spring AI 框架中,Image Model API 旨在为与专注于图像生成的各种 AI 模型进行交互提供一个简单且可移植的接口。它建立在 Spring AI 通用模型 API 之上,提供了特定于图像的抽象和实现。
实现生成图像 下面的示例使用 Spring Ai Alibaba 开源框架,spring-ai-alibaba-starter AutoConfiguration 默认初始化了 ImageModel 实例。
package com.atguigu.controller;
import com.alibaba.cloud.ai.dashscope.api.DashScopeImageApi;
import com.alibaba.cloud.ai.dashscope.image.DashScopeImageModel;
import com.alibaba.cloud.ai.dashscope.image.DashScopeImageOptions;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
@RestController
public class ImageModelController {
@Resource
private DashScopeImageModel imageModel;
@GetMapping("/generate-image")
public void getImage (@RequestParam(value = "msg", defaultValue = "生成一只小猫") String msg, HttpServletResponse res) {
ImageResponse response = imageModel.call(new ImagePrompt (
msg,
DashScopeImageOptions.builder()
.withModel(DashScopeImageApi.DEFAULT_IMAGE_MODEL)
.withN(1 )
.withHeight(1024 )
.withWidth(1024 )
.build()));
String imageUrl = response.getResult().getOutput().getUrl();
try {
URL url = URI.create(imageUrl).toURL();
InputStream in = url.openStream();
res.setHeader("Content-Type" , MediaType.IMAGE_PNG_VALUE);
res.getOutputStream().write(in.readAllBytes());
res.getOutputStream().flush();
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
语音模型
Text-to-Speech API 概述 在 Spring AI 框架中,Text-to-Speech API 提供了一个基于 OpenAI 的 TTS(Text-To-Speech,文本转语音)模型的语音端点,使用户能够朗读写好的博客文章、生成多种语言的语音音频或使用流媒体实现实时音频输出。
实现文本转语音 本示例基于 Spring AI Alibaba 框架。
package com.atguigu.controller;
import com.alibaba.cloud.ai.dashscope.audio.DashScopeSpeechSynthesisModel;
import com.alibaba.cloud.ai.dashscope.audio.DashScopeSpeechSynthesisOptions;
import com.alibaba.cloud.ai.dashscope.audio.synthesis.SpeechSynthesisPrompt;
import com.alibaba.cloud.ai.dashscope.audio.synthesis.SpeechSynthesisResponse;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
@RestController
public class AudioModelController {
@Resource
private DashScopeSpeechSynthesisModel speechSynthesisModel;
private static final String TEXT = "床前明月光,疑是地上霜。举头望明月,低头思故乡。" ;
private static final String FILE_PATH = "E:\\testData\\tts" ;
@GetMapping("/tts")
public void tts () throws IOException {
DashScopeSpeechSynthesisOptions options = DashScopeSpeechSynthesisOptions.builder()
.withSpeed(1.0 )
.withPitch(0.9 )
.withVolume(60 )
.build();
SpeechSynthesisResponse response = speechSynthesisModel.call(new SpeechSynthesisPrompt (TEXT, options));
File file = new File (FILE_PATH + "/output.mp3" );
try (FileOutputStream fos = new FileOutputStream (file)) {
ByteBuffer byteBuffer = response.getResult().getOutput().getAudio();
fos.write(byteBuffer.array());
} catch (IOException e) {
throw new IOException (e.getMessage());
}
}
}
8. Spring AI 实现 RAG
概述
向量化 向量数据库 (Vector Database) 是一种以数学向量的形式存储数据集合的数据库,通过一个数字列表来表示维度空间中的一个位置。在这里,向量数据库的功能是可以基于相似性搜索进行识别,而不是精准匹配。
嵌入模型 (Embedding Model) 和向量数据库是一对亲密无间的合作伙伴,两者的协同作用构成了现代语义搜索、推荐系统和 RAG(Retrieval Augmented Generation,检索增强生成)等应用的技术基础。
RAG 基本概念 RAG 的全称是 Retrieval-Augmented Generation,中文叫做检索增强生成。RAG 是一种结合了检索系统和生成模型的新型技术框架,其主要目的是利用外部知识库,帮助大模型生成更加准确、有依据、最新的回答。
通过使用 RAG,解决了传统 LLM(Large Language Model,大语言模型)存在的两个主要问题:
知识局限性 :LLM 的知识被固定在训练数据中,无法知道最新消息。
幻觉现象 :LLM 有时候会编造出并不存在的答案。
RAG 工作流程
用户输入问题 :用户在输入窗口输入自己的问题。
问题向量化 :根据用户初始输入的问题,调用 Embedding 模型,将问题转换为高维向量。
向量数据库检索 :系统连接到一个向量数据库,然后用刚才生成的问题向量,检索知识库中与之最相似的文档片段。
构建上下文 :组织提示词 (Prompt),让 LLM 更好地理解背景信息,包括系统提示词和构造最终输入。
调用 LLM :将构造好的 Prompt 提交给 LLM,模型读取检索到的内容和问题,组织自然、连贯、准确的回答。
返回最终回答给用户 :最终系统将生成的回答返回前端,展示给用户。
Spring AI 实现基本 RAG 流程
创建子模块 先创建子模块 springai_rag,依赖和配置文件与 springai_alibaba 中的一样,只不过端口号改为 8895。
创建配置类 package com.atguigu.ai.rag.config;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
@Configuration
public class RagConfig {
@Bean
ChatClient chatClient (ChatClient.Builder builder) {
return builder.defaultSystem("你将作为一名 Java 开发语言的专家,对于用户的使用需求作出解答" ).build();
}
@Bean
VectorStore vectorStore (@Qualifier("dashscopeEmbeddingModel") EmbeddingModel embeddingModel) {
SimpleVectorStore simpleVectorStore = SimpleVectorStore.builder(embeddingModel).build();
List<Document> documents = List.of(new Document (
"产品说明:名称:Java 开发语言\n" +
"产品描述:Java 是一种面向对象开发语言。\n" +
"特性:\n" +
"1. 封装\n" +
"2. 继承\n" +
"3. 多态\n" ));
simpleVectorStore.add(documents);
return simpleVectorStore;
}
}
通过这个配置类,完成以下内容:配置 ChatClient 作为 Bean,其中设置系统默认角色为 Java 开发语言专家;初始化 SimpleVectorStore,加载 Java 开发语言说明文档,将文档转换为向量形式存储。
编写 Controller package com.atguigu.ai.rag.controller;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/rag")
public class RagController {
@Resource
private ChatClient dashScopeChatClient;
@Resource
private VectorStore vectorStore;
@GetMapping(value = "/chat", produces = "text/plain; charset=UTF-8")
public String generation (@RequestParam("userInput") String userInput) {
return dashScopeChatClient.prompt().user(userInput)
.advisors(new QuestionAnswerAdvisor (vectorStore))
.call()
.content();
}
}
通过添加 QuestionAnswerAdvisor 并提供对应的向量存储,可以将之前放入的文档作为参考资料,并生成增强回答。
9. Spring AI 综合案例 智能简历筛选助手:该助手借助 Spring AI 的特性结合人工智能技术,为企业提供快速查看应聘候选人的信息及与候选人岗位的匹配度的服务。
搭建环境 创建名为 springai_all 的子模块,依赖和配置文件与 springai_alibaba 中的一样,只不过端口号改为 8896。
创建 RAG 知识库
创建 txt 文本 命名'张三简历.txt',放到 resource 目录下,内容包含教育经历、工作经验等信息。
添加配置类 package com.atguigu.all.config;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.reader.TextReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
@Configuration
public class RagConfig {
@Bean
VectorStore vectorStore (@Qualifier("dashscopeEmbeddingModel") EmbeddingModel embeddingModel) {
SimpleVectorStore simpleVectorStore = SimpleVectorStore.builder(embeddingModel).build();
String filePath = "张三简历.txt" ;
TextReader textReader = new TextReader (filePath);
textReader.getCustomMetadata().put("filePath" , filePath);
List<Document> documents = textReader.get();
TokenTextSplitter splitter = new TokenTextSplitter (1200 , 350 , 5 , 100 , true );
splitter.apply(documents);
simpleVectorStore.add(documents);
return simpleVectorStore;
}
}
通过以上过程,一个简单的 RAG 知识库就创建完成了,使用时直接在向量库中检索即可。
创建工具类 创建一个工具 (Function),可以用来查询候选人应聘的岗位。
package com.atguigu.all.function;
import java.util.function.Function;
public class RecruitServiceFunction implements Function <RecruitServiceFunction.Request, RecruitServiceFunction.Response> {
@Override
public Response apply (Request request) {
String position = "未知" ;
if (request.name.contains("张三" )) {
position = "算法工程师" ;
}
return new Response (position);
}
public record Request (String name) {}
public record Response (String position) {}
}
在 RagConfig.java 中添加如下配置:
@Bean
@Description("某某是否有资格面试")
public Function<RecruitServiceFunction.Request, RecruitServiceFunction.Response> recruitServiceFunction() {
return new RecruitServiceFunction ();
}
编写应用的人设 角色与目标:你是一个招聘助手,会针对用户的问题,结合候选人经历,岗位匹配度等专业知识,给用户提供指导。
指导原则:你需要确保给出的建议合理科学,不会对候选人的表现有言论侮辱。
限制:在提供建议时,需要强调在个性建议方面用户仍然需要线下寻求专业咨询。
澄清:在与用户交互过程中,你需要明确回答用户关于招聘方面的问题,对于非招聘方面的问题,你的回应是'我只是一个招聘助手,不能回答这个问题哦'。
个性化:在回答时,你需要以专业可靠的预期回答,偶尔可以带点幽默感。调节气氛。
编写 Controller 将人设、知识库、工具通过 Spring AI 框架串联起了,搭建成应用。
package com.atguigu.ai.all.controller;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.Generation;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.document.Document;
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.Map;
import java.util.Set;
import java.util.stream.Collectors;
@RestController
public class ChatController {
@Resource
private ChatModel chatModel;
@Resource
private VectorStore vectorStore;
@GetMapping("/ai/agent")
public String agent (@RequestParam("query") String query) {
List<Document> documents = vectorStore.similaritySearch(query);
String info = "" ;
if (documents.size() > 0 ) {
info = documents.get(0 ).getContent();
}
String systemPrompt = """
角色与目标:你是一个招聘助手,会针对用户的问题,结合候选人经历,岗位匹配度等专业知识,给用户提供指导。
指导原则:你需要确保给出的建议合理科学,不会对候选人的表现有言论侮辱。
限制:在提供建议时,需要强调在个性建议方面用户仍然需要线下寻求专业咨询。
澄清:在与用户交互过程中,你需要明确回答用户关于招聘方面的问题,对于非招聘方面的问题,你的回应是'我只是一个招聘助手,不能回答这个问题哦'。
个性化:在回答时,你需要以专业可靠的预期回答,偶尔可以带点幽默感。调节气氛。
给你提供一个数据参考,并且给你调用岗位投递检索公户
请你跟进数据参考与工具返回结果回复用户的请求。
""" ;
String userPrompt = """
给你提供一些数据参考:{info},请回答我的问题:{query}。
请你跟进数据参考与工具返回结果回复用户的请求。
""" ;
SystemMessage systemMessage = new SystemMessage (systemPrompt);
PromptTemplate promptTemplate = new PromptTemplate (userPrompt);
Message userMessage = promptTemplate.createMessage(Map.of("info" , info, "query" , query));
Prompt prompt = new Prompt (List.of(userMessage, systemMessage), DashScopeChatOptions.builder()
.withFunctions(Set.of("recruitServiceFunction" )).build());
List<Generation> results = chatModel.call(prompt).getResults();
String content = results.stream().map(x -> x.getOutput().getContent()).collect(Collectors.joining());
return content;
}
}
测试 在接口测试工具中输入 localhost:8896/ai/agent?query=java 语言有哪些特性,响应结果如下。
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
RSA密钥对生成器 生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online