编程技术文章分享与教程

网站首页 > 技术文章 正文

Java 中的 AI:使用 Spring Boot 和 LangChain 构建 ChatGPT 克隆

hmc789 2024-11-15 19:35:18 技术文章 2 ℃

学习在 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
@AnonymousAllowedbr
public class ChatService {br
br
    @Value("${openai.api.key}")br
    private String OPENAI_API_KEY;br
br
    private Assistant assistant;br
br
    interface Assistant {br
        String chat(String message);br
    }br
br
    @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
    }br
br
    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

mvn

This 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[]>([]);br
br
  async function sendMessage(message: string) {br
    setMessages((messages) => [br
      ...messages,br
      {br
        text: message,br
        userName: "You",br
      },br
    ]);br
br
    const response = await ChatService.chat(message);br
    setMessages((messages) => [br
      ...messages,br
      {br
        text: response,br
        userName: "Assistant",br
      },br
    ]);br
  }br
br
  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
@AnonymousAllowedbr
public class ChatService {br
br
    @Value("${openai.api.key}")br
    private String OPENAI_API_KEY;br
    private Assistant assistant;br
br
    interface Assistant {br
        TokenStream chat(String message);br
    }br
br
    @PostConstructbr
    public void init() {br
        var memory = TokenWindowChatMemory.withMaxTokens(1000, new OpenAiTokenizer("gpt-3.5-turbo"));br
br
        assistant = AiServices.builder(Assistant.class)br
                .streamingChatLanguageModel(OpenAiStreamingChatModel.withApiKey(OPENAI_API_KEY))br
                .chatMemory(memory)br
                .build();br
    }br
br
    public Flux<String> chatStream(String message) {br
        Sinks.Many<String> sink = Sinks.many().unicast().onBackpressureBuffer();br
br
        assistant.chat(message)br
                .onNext(sink::tryEmitNext)br
                .onComplete(sink::tryEmitComplete)br
                .onError(sink::tryEmitError)br
                .start();br
br
        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[]>([]);br
br
  function addMessage(message: MessageListItem) {br
    setMessages((messages) => [...messages, message]);br
  }br
br
  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
  }br
br
  async function sendMessage(message: string) {br
    addMessage({br
      text: message,br
      userName: "You",br
    });br
br
    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
  }br
br
  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

标签列表
最新留言