如何使用Spring AI、React和Docker构建AI聊天机器人
嘿,Java开发者们,我有个好消息:Spring 现在正式支持使用 Spring AI 模块构建 AI 应用程序。
在本教程中,我们将使用 Spring Boot、React、Docker 和 OpenAI 构建一个聊天机器人应用程序。此应用程序将允许用户与 AI 驱动的聊天机器人互动、提出问题并实时接收回复。
本文中提到的整个源代码已经在 GitHub 存储库中提供。
为了让你对我们将要构建的内容有个概念,最终应用程序将如下所示:
你兴奋吗?让我们从头开始构建它!
先决条件
在开始构建聊天机器人之前,你需要了解一些基础知识:
- 对 Java 和 Spring Boot 有基本的了解。
- 对 React 和 CSS 有基本的了解。
- 将 JDK、Node Package Manager 和 Docker 安装到您的计算机上。
获取您的 OpenAI 密钥
首先,如果您没有 OpenAI 帐户,则需要注册一个 OpenAI 帐户。登录后,您将被带到主页。
在右上角,单击 “Dashboard” 菜单。在侧边栏上,单击“API Keys”,然后单击“Create new secret key”按钮以生成您的密钥:
复制密钥并将其保存在安全的地方,因为您稍后需要它来将您的应用程序连接到 OpenAI API。
您可以浏览 调用API、它接受哪些请求以及它给出的响应的更多信息。
在 Spring Boot 中构建 REST API
让我们转到 spring initializer 以生成样板代码:
您可以提供您选择的组、构件、名称、描述和包。我们使用 Maven 作为构建工具,使用 Spring Boot 版本 3.3.3,使用 Jar 作为打包选项,并使用 Java 版本 17。
点击生成按钮,将下载 zip。解压缩文件并将它们作为 Maven 项目导入到您最喜欢的 IDE 中(我的是 Intellij)。
在 Spring 中配置您的 OpenAI 密钥
你可以使用现有的application.properties文件或创建一个application.yaml文件。我喜欢使用 Yaml,所以我创建了一个application.yaml文件,我可以在其中放置我所有的 Spring Boot 配置。
将OpenAIKey、Model和Temperature添加到你的application.yaml文件中:
spring:
ai:
openai:
chat:
options:
model: "gpt-3.5-turbo"
temperature: "0.7"
key: "PUT YOUR OPEN_API_KEY HERE"
在application.properties中的类似配置可能如下所示:
spring.ai.openai.chat.options.model=gpt-3.5-turbo
spring.ai.openai.chat.options.temperature=0.7
spring.ai.openai.key="PUT YOUR OPEN_API_KEY HERE"
构建 ChatController
让我们创建一个带有URL /ai/chat/string的GET API和一个处理逻辑的方法:
@RestController
public class ChatController {
@Autowired
private final OpenAiChatModel chatModel; @GetMapping("/ai/chat/string")
public Flux generateString(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
return chatModel.stream(message);
}
}```
- 首先,我们在ChatController类上添加@RestController注解以将其标记为我们Spring控制器。
- 然后,我们注入了OpenAiChatModel类的依赖项。然后,我们注入了OpenAiChatModel类的依赖项。它作为Spring AI依赖项的一部分可以立即使用。
- OpenAiChatModel类有一个stream(message)方法,该方法接受提示作为字符串并返回一个字符串响应(技术上讲,它是一个Flux,因为我们使用了相同的方法的响应式版本)。
- 在内部,OpenAiChatModel.stream(message)将[调用OpenAI](https://www.explinks.com/blog/ua-how-to-call-openai-o1-api/) API并从那里获取响应。OpenAI调用将使用你在application.yaml文件中提到的配置文件,因此请确保使用有效的OpenAI密钥。
- 我们已经创建了一个方法来处理GET [API调用](https://www.explinks.com/wiki/what-is-an-api-call/),该方法接受消息并返回Flux作为响应。
### 构建、运行和测试 REST API
使用 maven 命令构建并运行 Spring Boot 应用程序:
./mvnw clean install spring-boot:run
理想情况下,它会在8080端口上运行,除非你已自定义端口。确保该端口空闲以便成功运行应用程序。
你可以使用Postman或Curl命令来测试你的REST API:
curl –location ‘http://localhost:8080/ai/chat/string?message=How%20are%20you%3F‘
## 使用 React.js 构建 ChatUI
为了本教程,我们将使它非常简单和容易,所以请原谅我没有遵循任何React的最佳实践。
### 创建App.js来管理ChatUI表单
我们将使用useState来管理状态:
const [messages, setMessages] = useState([]);
const [input, setInput] = useState(”);
const [loading, setLoading] = useState(false);
- messages
:它将存储聊天中的所有消息。每条消息都有文本内容和发送者(要么是'user'(用户),要么是'ai'([人工智能](https://www.explinks.com/wiki/what-is-artificial-intelligence/)))。
- input
:用于存储用户在文本框中输入的内容。
- loading
:当[聊天机器人](https://www.explinks.com/blog/ua-what-is-the-best-free-unlimited-ai-chatbot)正在等待AI的响应时,此状态设置为true,收到响应后设置为false。
__创建handleSend函数__:当用户点击按钮或按下Enter键发送消息时调用此函数。
const handleSend = async () => {
if (input.trim() === ”) return;
const newMessage = { text: input, sender: 'user' };
setMessages([...messages, newMessage]);
setInput('');
setLoading(true); try {
const response = await axios.get('http://localhost:8080/ai/chat/string?message=' + input);
const aiMessage = { text: response.data, sender: 'ai' };
setMessages([...messages, newMessage, aiMessage]);
} catch (error) {
console.error("Error fetching AI response", error);
} finally {
setLoading(false);
}
};“`
以下是逐步发生的事情:
- 检查空输入:如果输入字段为空,则函数会提前返回(不发送任何内容)。
- 用户发送新消息:一条新消息会被添加到消息数组中。这条消息包含用户输入的文本,并被标记为由’user’(用户)发送。
- 重置输入:发送消息后,输入字段将被清除。
- 开始加载:在等待AI响应的过程中,加载状态被设置为true,以显示加载指示器。
- 发起API请求:代码使用axios来请求AI聊天机器人API,并传递用户的消息。当收到响应时,AI的一条新消息会被添加到聊天中。
- 错误处理:如果获取AI响应时出现问题,则会在控制台记录一个错误。
- 停止加载:最后,加载状态被关闭。
现在,我们来编写一个函数,以便用户在输入字段中输入内容时更新输入状态:
const handleInputChange = (e) => {
setInput(e.target.value);
};
这个函数会监听输入字段的变化,并将新的输入值存储到状态中,以便后续使用。每当用户在输入框中输入或删除字符时,这个函数都会被调用。
const handleKeyPress = (e) => {
if (e.key === 'Enter') {
handleSend();
}
};
现在让我们创建 UI 元素来呈现聊天消息:
{messages.map((message, index) => (
<div key={index} className={message-container ${message.sender}
}>
<img
src={message.sender === 'user' ? 'user-icon.png' : 'ai-assistant.png'}
alt={${message.sender} avatar
}
className="avatar"
/>
<div className={message ${message.sender}
}>
{message.text}
此区块呈现聊天中的所有消息:
- 通过消息映射:使用
.map()
方法遍历消息数组,将每条消息以div
的形式显示出来。 - 消息样式:根据发送者(用户或AI)的不同,为消息设置不同的类名,从而清晰地表明消息的发送者。
- 头像图像:每条消息都显示一个小头像,用户和AI的头像图片不同。
接下来,让我们创建一些逻辑,根据一个标志(flag)来显示加载器:
{loading && (

...
)}
当AI正在思考(即加载状态为true时),我们显示一个加载消息(例如“…”),以便用户知道响应很快就会到来。...
最后,创建一个按钮来触发发送消息的操作:
这个按钮在被点击时会触发handleSend()
函数。这里使用的图标是一张纸飞机,它是“发送”按钮的常见图标。
完整的Chatbot.js
文件如下所示:
const Chatbot = () => {
const [messages, setMessages] = useState([]);
const [input, setInput] = useState('');
const [loading, setLoading] = useState(false);
const handleSend = async () => {
if (input.trim() === '') return;
const newMessage = { text: input, sender: 'user' };
setMessages([...messages, newMessage]);
setInput('');
setLoading(true);
try {
const response = await axios.get('http://localhost:8080/ai/chat/string?message=' + input);
const aiMessage = { text: response.data, sender: 'ai' };
setMessages([...messages, newMessage, aiMessage]);
} catch (error) {
console.error("Error fetching AI response", error);
} finally {
setLoading(false);
}
};
const handleInputChange = (e) => {
setInput(e.target.value);
};
const handleKeyPress = (e) => {
if (e.key === 'Enter') {
handleSend();
}
};
return (

Home > Chat
{messages.map((message, index) => (
<div key={index} className={message-container ${message.sender}
}>
<img
src={message.sender === 'user' ? 'user-icon.png' : 'ai-assistant.png'}
alt={${message.sender} avatar
}
className="avatar"
/>
<div className={message ${message.sender}
}>
{message.text}
))}
{loading && (
...
)}