什么是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);
}
}
演示效果如下: