Spring AI: Make Spring Great Again!设计并实现一款智能Chat Bot!

什么是Spring AI

Spring AI 是 Spring 框架的新项目,旨在简化将生成式 AI 集成到 Java 应用程序中的过程。这个项目通过提供与主流 AI 提供商(如 OpenAI、Anthropic 和 Azure AI)兼容的 API 和抽象层,帮助开发人员在 Spring Boot 应用中利用 AI 功能。开发者可以使用 Spring AI 轻松地调用各种生成式 AI 功能,如文本生成、图像生成、语音识别和嵌入模型等。Spring AI 还支持向量数据库(如 MongoDB Atlas 和 Pinecone),适合构建基于 AI 的推荐系统或搜索功能。

Spring AI 的主要组件包括 AiClient 接口和 Prompt 类,帮助开发者更灵活地管理提示和生成输出。该框架还允许开发者利用 Spring Boot 的自动配置功能来集成这些 AI 功能,使构建和管理生成式 AI 应用变得更便捷。

Quick Start

创建一个SpringBoot工程

创建完成一个 Spring Boot 工程之后,导入 Spring AI 相关依赖项:

xml 复制代码
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.3.5</version>
</parent>

<properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>io.springboot.ai</groupId>
        <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
        <version>1.0.3</version>
    </dependency>
</dependencies>

因为 Spring AI 需要使用 JDK 17,所以你需要升级一下 JDK 版本。演示的项目使用了 Spring Boot 3.x 版本。

申请 API Key

笔者使用的是 hunyuan 大模型,通过 hunyuan 大模型调用 OpenAI 的接口。直接使用 OpenAI 的接口比较麻烦,所以还是选择了这款大模型。

编写配置项

一切就绪之后,编写一下 application.yml 文件。需要将 spring.ai.openai.base-url 配置项替换为腾讯云混元大模型的地址,api-key 替换为你的申请的 api-key

yaml 复制代码
server:
  port: 8080
  
spring:
  application:
    name: spring-service-demo
  ai:
    openai:
      base-url: https://api.hunyuan.cloud.tencent.com
      api-key: your api key
      chat:
        options:
          model: hunyuan-functioncall

开发一个接口

上面的准备工作准备完成之后,现在就可以聚焦于业务代码的编写了。现在来编写第一个调用大模型的接口的 Controller

java 复制代码
package org.codeart.ai.controller;

import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
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 AIController {

    private final OpenAiChatClient chatClient;

    @Autowired
    public AIController(OpenAiChatClient chatClient) {
        this.chatClient = chatClient;
    }

    @GetMapping("/generate")
    public ResponseEntity<String> generate(@RequestParam(value = "msg", defaultValue = "Tell me a joke") String msg) {
        String ans = chatClient.call(msg);
        return ResponseEntity.ok(ans);
    }
}

启动应用程序,打开浏览器访问接口可以看到服务器成功地返回了一则笑话:

这说明调用大模型接口已经成功了。

开发一个简单的聊天UI

为了优化一下用户使用体验,可以考虑开发一个简单的交互界面。这里使用 Vue3 + Naive UI 搭建了一个简单的界面。

安装 Naive UI 和 axios:

bash 复制代码
pnpm i -D naive-ui
bash 复制代码
pnpm i axios

修改 App.vue 文件:

ts 复制代码
<template>
  <n-layout class="layout-container">
    <n-card style="width: 1200px">
      <div style="height: 600px; overflow-y: auto; border: 1px solid #ddd; padding: 10px;">
        <div v-for="(message, index) in messages" :key="index" :class="{
          'user-msg': message.role === 'user',
          'bot-msg': message.role === 'bot'
        }">
          <n-space>
            <n-avatar v-if="message.role === 'bot'" round>{{ botAvatar }}</n-avatar>
            <div class="message-content">{{ message.content }}</div>
            <n-avatar v-if="message.role === 'user'" round>{{ userAvatar }}</n-avatar>
          </n-space>
        </div>
      </div>
      <n-space vertical style="margin-top: 10px;">
        <n-input
          v-model:value="input"
          placeholder="输入消息..."
          @keyup.enter="sendMessage"
          :disabled="loading"
        />
        <n-button @click="sendMessage" :disabled="loading">发送</n-button>
      </n-space>
    </n-card>
  </n-layout>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import { NAvatar, NButton, NCard, NInput, NLayout, NSpace } from 'naive-ui'
import axios from 'axios'

const messages = ref<{ role: string; content: string }[]>([])
const input = ref('')
const loading = ref(false)
const userAvatar = '👤'
const botAvatar = '🤖'
const CHAT_API = 'http://localhost:8080/ai/generate'

const sendMessage = async () => {
  if (!input.value || loading.value) return
  const userMessage = { role: 'user', content: input.value }
  messages.value.push(userMessage)
  input.value = ''

  loading.value = true

  try {
    const response = await axios.get(CHAT_API, {
      params: {
        msg: userMessage.content,
      },
    })
    const botMessage = { role: 'bot', content: response.data }
    messages.value.push(botMessage)
  } catch (error) {
    messages.value.push({ role: 'bot', content: '抱歉,获取回复失败,请稍后再试。' })
  } finally {
    loading.value = false
  }
}
</script>

<style scoped>
.user-msg {
  display: flex;
  justify-content: flex-end;
  margin-top: 10px;
}

.bot-msg {
  display: flex;
  justify-content: flex-start;
  margin-top: 10px;
}

.message-content {
  display: inline-block;
  padding: 10px;
  border-radius: 8px;
  background-color: #f0f0f0;
  max-width: 70%;
  min-width: 125px;
}

.layout-container {
  display: flex;
  justify-content: center;
  height: 100vh;
  margin-top: 50px;
}
</style>

记得在后端工程内部配置一下 CORS,不然浏览器会报跨域访问的错误:

java 复制代码
package org.codeart.ai.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CORSConfig implements WebMvcConfigurer {

    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        // 允许的域
        config.addAllowedOrigin("http://localhost:5173");
        // 允许发送cookie信息
        config.setAllowCredentials(true);
        // 设置被允许的请求类型
        config.addAllowedMethod("*");
        // 设置被允许的头信息
        config.addAllowedHeader("*");

        UrlBasedCorsConfigurationSource configurationSource = new UrlBasedCorsConfigurationSource();
        configurationSource.registerCorsConfiguration("/**", config);
        return new CorsFilter(configurationSource);
    }
}

演示效果如下:

相关推荐
Takumilove37 分钟前
MQTT入门:在Spring Boot中建立连接及测试
java·spring boot·后端
凡人的AI工具箱1 小时前
每天40分玩转Django:Django管理界面
开发语言·数据库·后端·python·django
cloud___fly1 小时前
Spring AOP入门
java·后端·spring
小奏技术1 小时前
我用github新开源的3D图生成工具生成了自己github历史贡献3D图
后端·开源
每天写点bug2 小时前
【go每日一题】:并发任务调度器
开发语言·后端·golang
一个不秃头的 程序员2 小时前
代码加入SFTP Go ---(小白篇5)
开发语言·后端·golang
这里有鱼汤2 小时前
数据分析从入门到放飞:Python三大金刚来助阵!
后端·python
Y编程小白2 小时前
SpringBoot的创建方式
java·spring boot·后端
基哥的奋斗历程2 小时前
初识Go语言
开发语言·后端·golang