网站首页 > java教程 正文
学习在 Java 中使用 Spring Boot、LangChain 和 Hilla 构建 ChatGPT 克隆。涵盖同步聊天完成和高级流式处理完成。
许多用于 AI 应用程序开发的库主要是用 Python 或 JavaScript 编写的。好消息是,其中一些库也具有 Java API。在本教程中,我将向您展示如何使用 Spring Boot、LangChain 和 Hilla 构建 ChatGPT 克隆。
本教程将介绍简单的同步聊天完成和更高级的流式处理完成,以获得更好的用户体验。

已完成的源代码
您可以在我的 GitHub 存储库中找到该示例的源代码。
要求
- Java 17+
- Node 18+
- An OpenAI API key in an environment variableOPENAI_API_KEY
创建一个 Spring Boot 和 React 项目,添加 LangChain
首先,使用 Hilla CLI 创建一个新的 Hilla 项目。这将创建一个带有 React 前端的 Spring Boot 项目。
npx @hilla/cli init ai-assistant在 IDE 中打开生成的项目。然后,将 LangChain4j 依赖项添加到文件中:pom.xml
.XML
<dependency>br <groupId>dev.langchain4j</groupId>br <artifactId>langchain4j</artifactId>br <version>0.22.0</version> <!-- TODO: use latest version -->br</dependency>使用 LangChain 使用内存完成简单的 OpenAI 聊天
我们将通过简单的同步聊天完成开始探索 LangChain4j。在本例中,我们希望调用 OpenAI 聊天完成 API 并获得单个响应。我们还希望跟踪多达 1,000 个聊天记录的令牌。
在包中,创建一个包含以下内容的类:
com.example.application.serviceChatService.java
@BrowserCallablebr@AnonymousAllowedbrpublic class ChatService {brbr @Value("${openai.api.key}")br private String OPENAI_API_KEY;brbr private Assistant assistant;brbr interface Assistant {br String chat(String message);br }brbr @PostConstructbr public void init() {br var memory = TokenWindowChatMemory.withMaxTokens(1000, new OpenAiTokenizer("gpt-3.5-turbo"));br assistant = AiServices.builder(Assistant.class)br .chatLanguageModel(OpenAiChatModel.withApiKey(OPENAI_API_KEY))br .chatMemory(memory)br .build();br }brbr public String chat(String message) {br return assistant.chat(message);br }br}- @BrowserCallable使该类可用于前端。
- @AnonymousAllowed允许匿名用户调用这些方法。
- @Value从环境变量中注入 OpenAI API 密钥。OPENAI_API_KEY
- Assistant是我们将用于调用聊天 API 的接口。
- init()使用 1,000 个令牌的内存和模型初始化助手。gpt-3.5-turbo
- chat()是我们将从前端调用的方法。
通过在 IDE 中运行或使用默认的 Maven 目标来启动应用程序:Application.java
mvnThis will generate TypeScript types and service methods for the front end.
Next, open in the folder and update it with the following content:App.tsxfrontend
TypeScript-JSX
export default function App() {br const [messages, setMessages] = useState<MessageListItem[]>([]);brbr async function sendMessage(message: string) {br setMessages((messages) => [br ...messages,br {br text: message,br userName: "You",br },br ]);brbr const response = await ChatService.chat(message);br setMessages((messages) => [br ...messages,br {br text: response,br userName: "Assistant",br },br ]);br }brbr return (br <div className="p-m flex flex-col h-full box-border">br <MessageList items={messages} className="flex-grow" />br <MessageInput onSubmit={(e) => sendMessage(e.detail.value)} />br </div>br );br}- 我们使用 Hilla UI 组件库中的 和 组件。MessageListMessageInput
- sendMessage()将消息添加到消息列表中,并调用该类的方法。收到响应后,该响应将添加到消息列表中。chat()ChatService
您现在有一个使用 OpenAI 聊天 API 并跟踪聊天历史记录的工作聊天应用程序。它非常适合短消息,但对于长答案来说很慢。为了改善用户体验,我们可以改用流式处理完成,在收到响应时显示响应。
使用 LangChain 将 OpenAI 聊天完成与内存进行流式处理
让我们更新类以改用流式处理完成:ChatService
@BrowserCallablebr@AnonymousAllowedbrpublic class ChatService {brbr @Value("${openai.api.key}")br private String OPENAI_API_KEY;br private Assistant assistant;brbr interface Assistant {br TokenStream chat(String message);br }brbr @PostConstructbr public void init() {br var memory = TokenWindowChatMemory.withMaxTokens(1000, new OpenAiTokenizer("gpt-3.5-turbo"));brbr assistant = AiServices.builder(Assistant.class)br .streamingChatLanguageModel(OpenAiStreamingChatModel.withApiKey(OPENAI_API_KEY))br .chatMemory(memory)br .build();br }brbr public Flux<String> chatStream(String message) {br Sinks.Many<String> sink = Sinks.many().unicast().onBackpressureBuffer();brbr assistant.chat(message)br .onNext(sink::tryEmitNext)br .onComplete(sink::tryEmitComplete)br .onError(sink::tryEmitError)br .start();brbr return sink.asFlux();br }br}代码与以前基本相同,但有一些重要区别:
- Assistant现在返回 a 而不是 .TokenStreamString
- init()用代替 .streamingChatLanguageModel()chatLanguageModel()
- chatStream()返回 a 而不是 .Flux<String>String
使用以下内容进行更新:App.tsx
打字稿-JSX
export default function App() {br const [messages, setMessages] = useState<MessageListItem[]>([]);brbr function addMessage(message: MessageListItem) {br setMessages((messages) => [...messages, message]);br }brbr function appendToLastMessage(chunk: string) {br setMessages((messages) => {br const lastMessage = messages[messages.length - 1];br lastMessage.text += chunk;br return [...messages.slice(0, -1), lastMessage];br });br }brbr async function sendMessage(message: string) {br addMessage({br text: message,br userName: "You",br });brbr let first = true;br ChatService.chatStream(message).onNext((chunk) => {br if (first && chunk) {br addMessage({br text: chunk,br userName: "Assistant",br });br first = false;br } else {br appendToLastMessage(chunk);br }br });br }brbr return (br <div className="p-m flex flex-col h-full box-border">br <MessageList items={messages} className="flex-grow" />br <MessageInput onSubmit={(e) => sendMessage(e.detail.value)} />br </div>br );br}模板与以前相同,但我们处理响应的方式不同。我们不是等待收到响应,而是开始侦听响应的块。当收到第一个块时,我们将其添加为新消息。当收到后续块时,我们将它们附加到最后一条消息中。
重新运行应用程序,您应该会看到响应在收到时显示。
结论
正如你所看到的,LangChain使得在Java和Spring Boot中构建LLM驱动的AI应用程序变得容易。
完成基本设置后,您可以按照本文前面链接的 LangChain4j GitHub 页面上的示例,通过链接操作、添加外部工具等来扩展功能。在 Hilla 文档中了解有关 Hilla 的更多信息。
原文标题:AI in Java: Building a ChatGPT Clone With Spring Boot and LangChain
原文链接:
https://dzone.com/articles/ai-in-java-building-a-chatgpt-clone-with-spring-bo
作者:Marcus Hellberg
编译:LCR
猜你喜欢
- 2025-07-03 java配置使用kafka(kafka配置jdk)
- 2025-07-03 Java双非本科,非科班,自学1年时间终于斩获offer
- 2025-07-03 MySQL 的异步复制(mysql支持异步吗)
- 2025-07-03 深入浅出JVM(一)之Hotspot虚拟机中的对象
- 2025-07-03 高可用MySQL集群实战教程,详解主从复制搭建步骤
- 2025-07-03 一文带你了解MySQL主从复制(Master-Slave)
- 2025-07-03 Java中List赋值给另一个List的6种方法详解
欢迎 你 发表评论:
- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)

本文暂时没有评论,来添加一个吧(●'◡'●)