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

演示效果如下:

相关推荐
Pandaconda几秒前
【Golang 面试题】每日 3 题(三十九)
开发语言·经验分享·笔记·后端·面试·golang·go
编程小筑35 分钟前
R语言的编程范式
开发语言·后端·golang
技术的探险家38 分钟前
Elixir语言的文件操作
开发语言·后端·golang
ss2731 小时前
【2025小年源码免费送】
前端·后端
Ai 编码助手1 小时前
Golang 中强大的重试机制,解决瞬态错误
开发语言·后端·golang
齐雅彤2 小时前
Lisp语言的区块链
开发语言·后端·golang
齐雅彤2 小时前
Lisp语言的循环实现
开发语言·后端·golang
梁雨珈2 小时前
Lisp语言的物联网
开发语言·后端·golang
邓熙榆3 小时前
Logo语言的网络编程
开发语言·后端·golang
羊小猪~~7 小时前
MYSQL学习笔记(四):多表关系、多表查询(交叉连接、内连接、外连接、自连接)、七种JSONS、集合
数据库·笔记·后端·sql·学习·mysql·考研