赞
踩
Spring AI是AI工程师的一个应用框架,它提供了一个友好的API和开发AI应用的抽象,旨在简化AI应用的开发工序,例如开发一款基于ChatGPT的对话、图片、音频等应用程序。
Spring AI已经集成了OpenAI的API,因此我们不需要实现向OpenAI发送请求和接收响应的交互程序了,Spring AI已经实现了这一内容,我们只需要通过调用Spring AI为我们提供的接口即可
项目地址:https://github.com/spring-projects-experimental/spring-ai
文档地址:https://docs.spring.io/spring-ai/reference/
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>
- <repository>
- <id>spring-snapshots</id>
- <name>Spring Snapshots</name>
- <url>https://repo.spring.io/snapshot</url>
- <releases>
- <enabled>false</enabled>
- </releases>
- </repository>
- </repositories>
- <!-- 依赖管理配置 -->
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.springframework.ai</groupId>
- <artifactId>spring-ai-bom</artifactId>
- <version>0.8.1-SNAPSHOT</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- </dependencies>
- </dependencyManagement>
- <dependency>
- <groupId>org.springframework.ai</groupId>
- <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
- </dependency>
用于请求OpenAI平台相关模型,例如:对话用的ChatGPT、画图用的Dall-e-2/3、文本嵌入text-embedding-ada-002以及音频合成与识别的whisper和tts等相关模型。
将相关key和api信息进行填写
- spring:
- ai:
- openai:
- api-key: 123
- base-url: https://api.openai.com
- @Slf4j
- @RestController
- @RequestMapping("/chat")
- public class ChatController {
- @Autowired
- private ChatClient chatClient;
- @GetMapping("/demo")
- public String chat(String prompt){
- return chatClient.call(prompt);
- }
-
- }
运行结果:
流失对话的核心就是流式传输,AI的响应数据是一点一点传过来的,不用等AI将文本全部生成出来了才传过来。一定程度上能够提高使用上的响应速度,给用户一个非常好的体验。
- @Slf4j
- @RestController
- @RequestMapping("/chat")
- public class ChatController {
- @Autowired
- private StreamingChatClient streamingChatClient;
- // 流式调用 将produces声明为文本事件流
- @GetMapping(value = "/stream",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
- public Flux<String> stream(String prompt){
- long startTime = System.currentTimeMillis();
- Flux<String> res=streamingChatClient.stream(prompt).flatMapSequential(Flux::just);
- long endTime = System.currentTimeMillis();
- long duration = endTime - startTime;
- log.info("流式调用执行时间:{}",duration);
- // 将流中的内容按顺序返回
- return res;
- }
- }
运行结果:
ChatGPT上下文对话的实现原理较为简单,本质上其实就是将不同角色的聊天信息依次存储在一个队列中发送给ChatGPT即可,然后ChatGPT会根据整个聊天信息对回复内容进行判断。在OpenAI提供的接口中,每条信息的角色总共分为三类:
不过,根据OpenAI的计费规则,你的消息队列越长,单次问询需要的费用就会越高,因此我们需要对这个消息列表的长度进行限制。
- @Slf4j
- @RestController
- @RequestMapping("/chat")
- public class ChatController {
- @Autowired
- private ChatClient chatClient;
- // 历史消息列表
- static List<Message> historyMessage = new ArrayList<>();
- // 历史消息列表的最大长度
- static int maxLen = 10;
- @GetMapping("/context")
- public String context(String prompt) {
- // 用户输入的文本是UserMessage
- historyMessage.add(new UserMessage(prompt));
- // 发给AI前对历史消息对列的长度进行检查
- if(historyMessage.size() > maxLen){
- historyMessage = historyMessage.subList(historyMessage.size()-maxLen-1,historyMessage.size());
- }
- // 获取AssistantMessage
- ChatResponse chatResponse = chatClient.call(new Prompt(historyMessage));
- AssistantMessage assistantMessage = chatResponse.getResult().getOutput();
- // 将AI回复的消息放到历史消息列表中
- historyMessage.add(assistantMessage);
- return assistantMessage.getContent();
- }
-
- }
人设设定功能来自于“提示词(prompt)工程”的理论基础,可用来提高大语言模型处理复杂任务场景的能力
上面介绍Message的时候提到SystemMessage对AI生成的内容影响权重较大,人设设定就是需要靠SystemMessage
实现。我们提供一个SystemMessage放入历史消息列表中,并让SystemMessage在每次发给AI时始终在历史消息列表中。
- @Slf4j
- @RestController
- @RequestMapping("/chat")
- public class ChatController {
- @Autowired
- private ChatClient chatClient;
- // 历史消息列表
- final String systemPrompt="你现在是一个喜欢扮可爱的人,说话嗲嗲的";
- List<Message> historyMessage = new ArrayList<>(List.of(new SystemMessage(systemPrompt)));
- // 历史消息列表的最大长度
- static int maxLen = 10;
- @GetMapping("/context")
- public String context(String prompt) {
- // 用户输入的文本是UserMessage
- historyMessage.add(new UserMessage(prompt));
- // 发给AI前对历史消息对列的长度进行检查
- if(historyMessage.size() > maxLen){
- historyMessage = historyMessage.subList(historyMessage.size()-maxLen-1,historyMessage.size());
- }
- // 获取AssistantMessage
- ChatResponse chatResponse = chatClient.call(new Prompt(historyMessage));
- AssistantMessage assistantMessage = chatResponse.getResult().getOutput();
- // 将AI回复的消息放到历史消息列表中
- historyMessage.add(assistantMessage);
- return assistantMessage.getContent();
- }
-
- }
运行结果:
Spring AI为我们提供了提示词模板,允许我们通过一些模板,快速地动态生成提示词并发起提问
- @Slf4j
- @RestController
- @RequestMapping("/prompts")
- public class PromptController {
- @Autowired
- private ChatClient chatClient;
- @Value("classpath:prompt.st")
- private Resource templateResource;
- @GetMapping("/template")
- public String promptTemplate(String author){
- // 提示词
- final String template = "请问{author}最受欢迎的书是哪本书?什么时候发布的?书的内容是什么?";
- PromptTemplate promptTemplate = new PromptTemplate(template);
- // 动态地将author填充进去
- Prompt prompt = promptTemplate.create(Map.of("author", author));
- ChatResponse chatResponse = chatClient.call(prompt);
- AssistantMessage assistantMessage = chatResponse.getResult().getOutput();
- return assistantMessage.getContent();
- }
- @GetMapping("/config/template")
- public String promptConfigTemplate(String author) {
- PromptTemplate promptTemplate = new PromptTemplate(templateResource);
- // 动态地将author填充进去
- Prompt prompt = promptTemplate.create(Map.of("author", author));
- ChatResponse chatResponse = chatClient.call(prompt);
- AssistantMessage assistantMessage = chatResponse.getResult().getOutput();
- return assistantMessage.getContent();
- }
-
-
- }
请问{author}最受欢迎的书是哪本书?什么时候发布的?书的内容是什么?
SpringAi还为我们提供了OutputParser解析器,该解析器可以将AI生成的内容解析为Java Bean对象。该解析器类似于ORM框架中的Mapper,将AI的生成内容映射为Java对象。
- @Slf4j
- @RestController
- @RequestMapping("/parser")
- public class ParserController {
- @Autowired
- private ChatClient chatClient;
-
- @GetMapping("/bean")
- public Movie getBookByAuthor(String actor) {
- final String template = """
- 请告诉我{actor}最受欢迎的电影是哪个?什么时间上映?大概讲了什么?
- {format}
- """;
- // 定义一个输出解析器
- OutputParser<Movie> movieParser = new BeanOutputParser<>(Movie.class);
- PromptTemplate promptTemplate = new PromptTemplate(template);
- Prompt prompt = promptTemplate.create(Map.of("actor", actor, "format", movieParser.getFormat()));
- ChatResponse chatResponse = chatClient.call(prompt);
- AssistantMessage assistantMessage = chatResponse.getResult().getOutput();
- // 解析为一个Bean对象
- Movie movie = movieParser.parse(assistantMessage.getContent());
- return movie;
- }
- }
-
-
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class Movie {
- private String actor;
- private String movieName;
- private String publishedDate;
- private String description;
- }
Spring AI提供了图片生成接口,该接口可以用于与各种专门用于图像生成的人工智能模型进行交互。
在调用绘图时,我们只需要像调用对话一样传入一个Prompt:ImagePrompt。ImagePrompt中包含了我们需要绘制的图片信息,包括:ImageMessage(绘图指令)、ImageOptions(图片数、图片配置、返回的图片格式、绘图模型等)。AI拿到我们的Prompt后会根据里面的内容对图像进行生产
ImageOptions重要属性
- @Slf4j
- @RestController
- @RequestMapping("/image")
- public class ImageController {
- @Autowired
- private ImageClient imageClient;
- @GetMapping("/image")
- public String image(String prompt) {
- ImagePrompt imagePrompt =
- new ImagePrompt(prompt, OpenAiImageOptions.builder()
- .withModel(OpenAiImageApi.ImageModel.DALL_E_3.getValue())
- .withHeight(1024)
- .withWidth(1024)
- .withResponseFormat("url") // URL or b64_json
- .build());
- ImageResponse imageResponse = imageClient.call(imagePrompt);
- List<ImageGeneration> results = imageResponse.getResults();
- // 图片url
- String url = results.get(0).getOutput().getUrl();
- return String.format("<img src='%s' alt='%s'>",url,prompt);
- }
- }
通过AI自查手段将文本模型和图片生成模型进行组合实现一个既可以生成文本也可以生成AI的接口。这个关键点就是利用提示词限制AI的回复内容以达到一个自查手段
AI自查就是让AI判断你的问题是画一个图还是简简单单的对话。
- @Slf4j
- @RestController
- @RequestMapping("/judge")
- public class JudgeByAiController {
- @Autowired
- private ChatClient chatClient;
- @Autowired
- private ImageClient imageClient;
- @Value("classpath:judge.st")
- private Resource templateResource;
- @RequestMapping("/ai")
- public String ai(String prompt){
- try {
- return judge(prompt)?image(prompt):chat(prompt);
- } catch (Exception e) {
- return "error";
- }
- }
- private boolean judge(String promptString){
- PromptTemplate promptTemplate = new PromptTemplate(templateResource);
- // 动态地将prompt填充进去
- Prompt prompt = promptTemplate.create(Map.of("prompt", promptString));
- ChatResponse chatResponse = chatClient.call(prompt);
- AssistantMessage assistantMessage = chatResponse.getResult().getOutput();
- String judgeResult=assistantMessage.getContent();
- return judgeResult.toLowerCase().contains("yes")?true:false;
- }
- private String chat(String prompt){
- String res=chatClient.call(prompt);
- return res;
- }
- private String image(String prompt) {
- ImagePrompt imagePrompt =
- new ImagePrompt(prompt, OpenAiImageOptions.builder()
- .withModel(OpenAiImageApi.ImageModel.DALL_E_3.getValue())
- .withHeight(1024)
- .withWidth(1024)
- .withResponseFormat("url") // URL or b64_json
- .build());
- ImageResponse imageResponse = imageClient.call(imagePrompt);
- List<ImageGeneration> results = imageResponse.getResults();
- // 图片url
- String url = results.get(0).getOutput().getUrl();
- return String.format("<img src='%s' alt='%s'>",url,prompt);
- }
- }
Does this message want to generate an AI picture, image, art or anything similar? {prompt} . Simply answer with a yes or no.
openAI真正走向CloseAI,LLM国产替代浪潮即将到来
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。