Spring AI -快速开发ChatGPT应用

  • Spring AI介绍

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能做什么?

  • 支持目前主流大语言模型平台,例如 OpenAI、Microsoft、Amazon、Google 和 Huggingface;
  • 支持阻塞与流式的文本对话;
  • 支持图像生成(当前仅限OpenAI的dall-e-*模型和SD);
  • 支持嵌入模型;
  • 支持LLM生成的内容转为POJO;
  • 支持主流的向量数据库或平台:Azure Vector Search, Chroma, Milvus, Neo4j, PostgreSQL/PGVector, PineCone, Qdrant, Redis 和 Weaviate
  • 支持函数调用
  • 支持自动装配和启动器(与Spring Boot完美集成);
  • 提供用于数据处理工程的ETL框架;
  • 项目实践

  1. 准备工作

  2. 版本说明

  • OpenAI的Key
  • OpenAI的Api
  • JDK >= 17
  • Spring 6.x;Spring Boot 3.x
  • Spring AI 0.8.1-SNAPSHOT
  1. pom引入

<!-- 仓库定义 -->
<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等相关模型。

  1. 配置文件application.yml

将相关key和api信息进行填写

spring:
  ai:
    openai:
      api-key: 123
      base-url: https://api.openai.com
  1. 快速对话ChatClient
@Slf4j
@RestController
@RequestMapping("/chat")
public class ChatController {
    @Autowired
    private  ChatClient chatClient;
    @GetMapping("/demo")
    public String chat(String prompt){
        return chatClient.call(prompt);
    }

}

运行结果:

  1. 流式对话StreamingChatClient

流失对话的核心就是流式传输,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;
    }
}

运行结果:

  1. 上下文对话

ChatGPT上下文对话的实现原理较为简单,本质上其实就是将不同角色的聊天信息依次存储在一个队列中发送给ChatGPT即可,然后ChatGPT会根据整个聊天信息对回复内容进行判断。在OpenAI提供的接口中,每条信息的角色总共分为三类:

  • SystemMessage:系统限制信息,这种信息在对话中的权重很大,AI会优先依据SystemMessage里的内容进行回复;
  • UserMessage:用户信息
  • AssistantMessage:AI回复信息

不过,根据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();
    }

}
  1. 人设设定

人设设定功能来自于“提示词(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();
    }

}

运行结果:

  1. 模板语法PromptTemplate

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}最受欢迎的书是哪本书?什么时候发布的?书的内容是什么?

  1. OutputParser 生成解析器

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;
}

  1. 绘图ImageClient

Spring AI提供了图片生成接口,该接口可以用于与各种专门用于图像生成的人工智能模型进行交互。

在调用绘图时,我们只需要像调用对话一样传入一个Prompt:ImagePrompt。ImagePrompt中包含了我们需要绘制的图片信息,包括:ImageMessage(绘图指令)、ImageOptions(图片数、图片配置、返回的图片格式、绘图模型等)。AI拿到我们的Prompt后会根据里面的内容对图像进行生产

ImageOptions重要属性

  • model:绘图模型,默认dall-e-3
    • dall-e-3:1024 x 1024 、 1024 x 1792、1792 x 1024;
    • dall-e-2: 256 x 256、512 x 512 、 1024 x 1024;
  • responseFormat:返回的图片格式,url 和 b64_json
@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);
    }
}
  1. AI自查实现对话和绘图

通过AI自查手段将文本模型和图片生成模型进行组合实现一个既可以生成文本也可以生成AI的接口。这个关键点就是利用提示词限制AI的回复内容以达到一个自查手段

AI自查就是让AI判断你的问题是画一个图还是简简单单的对话。

  • 用户输入文本prompt;
  • 先让AI判断文本prompt是否需要图片;
  • 如果需要图片,调用绘图模型获取绘图结果;
  • 如果不需要图片,直接调用对话模型;’
@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.
  • LLM领域新浪潮即将来临

openAI真正走向CloseAI,LLM国产替代浪潮即将到来

危!OpenAI 将限制中国开发者访问 API 服务-CSDN博客

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你想开发一个基于uni-app、Spring Boot和socket.io的ChatGPT聊天应用吗?这是一个很有趣的项目!下面是一些简要的步骤和建议: 1. 首先,你需要了解uni-app、Spring Boot和socket.io的基础知识。uni-app是一个跨平台的开发框架,可以用于开发iOS、Android和Web应用程序。Spring Boot是一个用于快速构建基于Spring框架的应用程序的工具。socket.io是一个实时的、双向通信的库,用于在客户端和服务器之间建立WebSocket连接。 2. 接下来,你需要确定ChatGPT的实现方式。ChatGPT是基于自然语言处理的人工智能聊天机器人,需要使用GPT模型对用户输入进行处理和回复。你可以使用已经训练好的GPT模型,也可以使用开源框架如Hugging Face Transformers来构建自己的模型。 3. 然后,你需要设计和实现前端界面。你可以使用uni-app提供的UI组件和样式来构建聊天界面。你可以使用socket.io-client库来处理客户端和服务器之间的WebSocket连接,并将用户输入发送到服务器进行处理。 4. 在后端,你需要使用Spring Boot框架来处理WebSocket连接和GPT模型。你可以使用socket.io服务器库来处理WebSocket连接,并使用Hugging Face Transformers框架来构建ChatGPT模型。当服务器接收到用户输入时,它将使用ChatGPT模型进行处理并生成回复,然后将回复发送回客户端。 5. 最后,你需要进行测试和部署。你可以使用Postman或其他工具来测试API端点和WebSocket连接。你可以将应用程序部署到云服务器或Heroku等云平台上,以便用户可以随时随地访问应用程序。 希望这些建议能帮助你开始开发ChatGPT聊天应用程序!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值