学习使用 Java 中的 Spring Boot、LangChain 和 Hilla 构建 ChatGPT 克隆。涵盖同步聊天完成和高级流完成。
许多用于 AI 应用程序开发的库主要是用Python或 JavaScript 编写的。好消息是其中一些库也具有 Java API。在本教程中,我将向您展示如何使用Spring Boot、 LangChain 和Hilla构建 ChatGPT 克隆。
本教程将涵盖简单的同步聊天完成和更高级的流式完成,以获得更好的用户体验。
大神完成得开源源代码
您可以在我的GitHub 存储库中找到该示例的源代码。
https://github.com/marcushellberg/spring-boot-react-langchain-chatgpt
要求
Java 17+
Node 18+
Hilla(https://hilla.dev/)
LangChain4j(https://github.com/langchain4j/langchain4j)
OPENAI_API_KEY环境变量中的 OpenAI API 密钥
创建Spring Boot和React项目,添加LangChain
首先,使用 Hilla CLI 创建一个新的 Hilla 项目。这将创建一个带有React前端的 Spring Boot 项目。
npx @hilla/cli init ai-assistant
在 IDE 中打开生成的项目。然后,将LangChain4j依赖项添加到文件中pom.xml:
<dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j</artifactId> <version>0.22.0</version> <!-- TODO: use latest version --> </dependency>
使用 LangChain 使用内存完成简单的 OpenAI 聊天
我们将通过简单的同步聊天完成来开始探索 LangChain4j。在本例中,我们希望调用 OpenAI 聊天完成 API 并获得单个响应。我们还希望跟踪聊天历史记录中最多 1,000 个标记。
在com.example.application.service包中,创建一个ChatService.java包含以下内容的类:
@BrowserCallable @AnonymousAllowed public class ChatService { @Value("${openai.api.key}") private String OPENAI_API_KEY; private Assistant assistant; interface Assistant { String chat(String message); } @PostConstruct public void init() { var memory = TokenWindowChatMemory.withMaxTokens(1000, new OpenAiTokenizer("gpt-3.5-turbo")); assistant = AiServices.builder(Assistant.class) .chatLanguageModel(OpenAiChatModel.withApiKey(OPENAI_API_KEY)) .chatMemory(memory) .build(); } public String chat(String message) { return assistant.chat(message); } }
@BrowserCallable使该类可供前端使用。
@AnonymousAllowed允许匿名用户调用这些方法。
@Value从环境变量注入 OpenAI API 密钥OPENAI_API_KEY。
Assistant是我们用来调用聊天 API 的接口。
init()使用 1,000 个令牌内存和模型初始化助手gpt-3.5-turbo。
chat()是我们将从前端调用的方法。
Application.java通过在 IDE 中运行或使用默认Maven目标来启动应用程序:
MVN
这将为前端生成TypeScript 类型和服务方法。
接下来,App.tsx在frontend文件夹中打开并使用以下内容更新它:
export default function App() { const [messages, setMessages] = useState<MessageListItem[]>([]); async function sendMessage(message: string) { setMessages((messages) => [ ...messages, { text: message, userName: "You", }, ]); const response = await ChatService.chat(message); setMessages((messages) => [ ...messages, { text: response, userName: "Assistant", }, ]); } return ( <div className="p-m flex flex-col h-full box-border"> <MessageList items={messages} className="flex-grow" /> <MessageInput onSubmit={(e) => sendMessage(e.detail.value)} /> </div> ); }
文章来源地址https://www.toymoban.com/diary/java/380.html
我们使用Hilla UI 组件库中的MessageList和组件MessageInput
sendMessage()将消息添加到消息列表中,并调用类chat()上的方法ChatService。收到响应后,会将其添加到消息列表中。
您现在拥有一个正在运行的聊天应用程序,该应用程序使用 OpenAI 聊天 API 并跟踪聊天历史记录。它对于短消息非常有效,但对于长答案来说速度很慢。为了改善用户体验,我们可以使用流式完成来代替,在收到响应时显示响应。
使用 LangChain 使用内存流式传输 OpenAI 聊天完成情况
让我们更新该类ChatService以使用流式完成:
@BrowserCallable @AnonymousAllowed public class ChatService { @Value("${openai.api.key}") private String OPENAI_API_KEY; private Assistant assistant; interface Assistant { TokenStream chat(String message); } @PostConstruct public void init() { var memory = TokenWindowChatMemory.withMaxTokens(1000, new OpenAiTokenizer("gpt-3.5-turbo")); assistant = AiServices.builder(Assistant.class) .streamingChatLanguageModel(OpenAiStreamingChatModel.withApiKey(OPENAI_API_KEY)) .chatMemory(memory) .build(); } public Flux<String> chatStream(String message) { Sinks.Many<String> sink = Sinks.many().unicast().onBackpressureBuffer(); assistant.chat(message) .onNext(sink::tryEmitNext) .onComplete(sink::tryEmitComplete) .onError(sink::tryEmitError) .start(); return sink.asFlux(); } }
代码与以前基本相同,但有一些重要的区别:
Assistant现在返回 a TokenStream而不是 a String。
init()使用streamingChatLanguageModel()而不是 chatLanguageModel().
chatStream()返回 一个 Flux<String>而不是 一个 String。
更新App.tsx以下内容:
export default function App() { const [messages, setMessages] = useState<MessageListItem[]>([]); function addMessage(message: MessageListItem) { setMessages((messages) => [...messages, message]); } function appendToLastMessage(chunk: string) { setMessages((messages) => { const lastMessage = messages[messages.length - 1]; lastMessage.text += chunk; return [...messages.slice(0, -1), lastMessage]; }); } async function sendMessage(message: string) { addMessage({ text: message, userName: "You", }); let first = true; ChatService.chatStream(message).onNext((chunk) => { if (first && chunk) { addMessage({ text: chunk, userName: "Assistant", }); first = false; } else { appendToLastMessage(chunk); } }); } return ( <div className="p-m flex flex-col h-full box-border"> <MessageList items={messages} className="flex-grow" /> <MessageInput onSubmit={(e) => sendMessage(e.detail.value)} /> </div> ); }
模板与以前相同,但我们处理响应的方式不同。我们不再等待收到响应,而是开始监听响应块。当收到第一个块时,我们将其添加为新消息。当收到后续块时,我们将它们附加到最后一条消息中。
重新运行应用程序,您应该看到响应按收到时的样子显示。
结论
正如您所看到的,LangChain 可以轻松地在 Java 和 Spring Boot 中构建由 LLM 驱动的 AI 应用程序。
完成基本设置后,您可以按照本文前面链接的 LangChain4j GitHub 页面上的示例,通过链接操作、添加外部工具等来扩展功能。在Hilla 文档中了解有关 Hilla 的更多信息。
Hilla 文档:https://hilla.dev/docs/react文章来源:https://www.toymoban.com/diary/java/380.html
到此这篇关于使用Spring Boot和LangChain构建Java中的AI ChatGPT仿制教程的文章就介绍到这了,更多相关内容可以在右上角搜索或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!