博客

引入 LangChain4j 以简化 LLM 与 Java 应用程序的集成

LangChain4j(LangChain for Java)是一个功能强大的工具集,可用于在纯 Java 中构建 RAG 应用程序。

LangChain4j 框架正是以此为目标于 2023 年创建的:

LangChain4j 的目标是简化将 LLM 集成到 Java 应用程序中的过程。

LangChain4j 提供了一种标准的方法:

  • 根据给定内容(例如文本)创建嵌入向量

  • 将嵌入式存储在嵌入式存储库中

  • 在嵌入存储中搜索相似向量

  • 与法律硕士讨论

  • 使用聊天记忆功能,记住与法律硕士讨论的来龙去脉

此列表并不详尽,LangChain4j 社区一直在实施新功能。

本帖将介绍该框架的第一个主要部分。

将 LangChain4j OpenAI 添加到我们的项目中

与所有 Java 项目一样,这只是一个依赖关系问题。这里我们将使用 Maven,但任何其他依赖管理器也可以实现同样的功能。

作为构建项目的第一步,我们将使用 OpenAI,因此只需添加langchain4j-open-ai 工具:

<properties>
  <langchain4j.version>0.34.0</langchain4j.version>
</properties>

<dependencies>
  <dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-open-ai</artifactId>
    <version>${langchain4j.version}</version>
  </dependency>
</dependencies>

在其余代码中,我们将使用自己的 API 密钥(可通过注册OpenAI 账户获得),或者 LangChain4j 项目提供的 API 密钥(仅供演示使用):

static String getOpenAiApiKey() {
  String apiKey = System.getenv(API_KEY_ENV_NAME);
  if (apiKey == null || apiKey.isEmpty()) {
    Logger.warn("Please provide your own key instead using [{}] env variable", API_KEY_ENV_NAME);
    return "demo";
  }
  return apiKey;
}

现在我们可以创建 ChatLanguageModel 的实例:

ChatLanguageModel model = OpenAiChatModel.withApiKey(getOpenAiApiKey());

最后,我们可以问一个简单的问题,并得到答案:

String answer = model.generate("Who is Thomas Pesquet?");
Logger.info("Answer is: {}", answer);

给出的答案可能是这样的

Thomas Pesquet is a French aerospace engineer, pilot, and European Space Agency astronaut.
He was selected as a member of the European Astronaut Corps in 2009 and has since completed 
two space missions to the International Space Station, including serving as a flight engineer 
for Expedition 50/51 in 2016-2017. Pesquet is known for his contributions to scientific 
research and outreach activities during his time in space.

如果您想运行这段代码,请查看Step1AiChatTest.java类。

使用 langchain4j 提供更多语境

让我们添加langchain4j 手工艺品:

<dependency>
  <groupId>dev.langchain4j</groupId>
  <artifactId>langchain4j</artifactId>
  <version>${langchain4j.version}</version>
</dependency>

它提供了一个工具集,可以帮助我们建立更高级的 LLM 集成,以构建我们的助手。在这里,我们只需创建一个Assistant 接口,该接口提供的chat 方法将自动调用我们之前定义的ChatLanguageModel

interface Assistant {
  String chat(String userMessage);
}

我们只需请求 LangChain4jAiServices 类为我们构建一个实例:

Assistant assistant = AiServices.create(Assistant.class, model);

然后调用chat(String) 方法:

String answer = assistant.chat("Who is Thomas Pesquet?");
Logger.info("Answer is: {}", answer);

这与之前的行为相同。那么,我们为什么要修改代码呢?首先,它更优雅,但更重要的是,你现在可以使用简单的注释向 LLM 发出一些指示:

interface Assistant {
  @SystemMessage("Please answer in a funny way.")
  String chat(String userMessage);
}

这就是现在的奉献:

Ah, Thomas Pesquet is actually a super secret spy disguised as an astronaut! 
He's out there in space fighting aliens and saving the world one spacewalk at a time. 
Or maybe he's just a really cool French astronaut who has been to the International 
Space Station. But my spy theory is much more exciting, don't you think?

如果您想运行这段代码,请查看Step2AssistantTest.java类。

转到另一个 LLM:langchain4j-ollama

我们可以利用伟大的奥拉马项目。在本地计算机上运行 LLM 会有帮助。

让我们添加langchain4j-ollama 手工艺品:

<dependency>
  <groupId>dev.langchain4j</groupId>
  <artifactId>langchain4j-ollama</artifactId>
  <version>${langchain4j.version}</version>
</dependency>

由于我们要使用测试来运行示例代码,因此让我们在项目中添加Testcontainers

<dependency>
  <groupId>org.testcontainers</groupId>
  <artifactId>ollama</artifactId>
  <version>1.20.1</version>
  <scope>test</scope>
</dependency>

现在我们可以启动/停止 Docker 容器了:

static String MODEL_NAME = "mistral";
static String DOCKER_IMAGE_NAME = "langchain4j/ollama-" + MODEL_NAME + ":latest";

static OllamaContainer ollama = new OllamaContainer(
  DockerImageName.parse(DOCKER_IMAGE_NAME).asCompatibleSubstituteFor("ollama/ollama"));

@BeforeAll
public static void setup() {
  ollama.start();
}

@AfterAll
public static void teardown() {
  ollama.stop();
}

我们只需"," ,将model 对象改为OllamaChatModel ,而不是之前使用的OpenAiChatModel

OllamaChatModel model = OllamaChatModel.builder()
  .baseUrl(ollama.getEndpoint())
  .modelName(MODEL_NAME)
  .build();

请注意,提取图像及其模型可能需要一些时间,但一段时间后,您就可以得到答案了:

Oh, Thomas Pesquet, the man who single-handedly keeps the French space program running 
while sipping on his crisp rosé and munching on a baguette! He's our beloved astronaut 
with an irresistible accent that makes us all want to learn French just so we can 
understand him better. When he's not floating in space, he's probably practicing his 
best "je ne sais quoi" face for the next family photo. Vive le Thomas Pesquet! 
🚀🌍🇫🇷 #FrenchSpaceHero

记忆力更好

如果我们提出多个问题,系统默认情况下不会记住之前的问题和答案。因此,如果我们在第一个问题之后提问"他是什么时候出生的?" 、我们的应用程序会回答:

Oh, you're asking about this legendary figure from history, huh? Well, let me tell 
you a hilarious tale! He was actually born on Leap Year's Day, but only every 400 
years! So, do the math... if we count backwards from 2020 (which is also a leap year), 
then he was born in... *drumroll please* ...1600! Isn't that a hoot? But remember 
folks, this is just a joke, and historical records may vary.

这是无稽之谈。相反,我们应该使用聊天记忆

ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10);
Assistant assistant = AiServices.builder(Assistant.class)
  .chatLanguageModel(model)
  .chatMemory(chatMemory)
  .build();

现在运行同样的问题就能得到有意义的答案:

Oh, Thomas Pesquet, the man who was probably born before sliced bread but after dinosaurs! 
You know, around the time when people started putting wheels on suitcases and calling it 
a revolution. So, roughly speaking, he came into this world somewhere in the late 70s or 
early 80s, give or take a year or two - just enough time for him to grow up, become an 
astronaut, and make us all laugh with his space-aged antics! Isn't that a hoot? 
*laughs maniacally*

结论

下一篇文章中,我们将了解如何使用 Elasticsearch 作为嵌入存储,向我们的私有数据集提问。这将为我们提供一种方法,使我们的应用程序搜索工作更上一层楼。

相关内容

使用模拟和真实 Elasticsearch 测试 Java 代码

Piotr Przybyl

LangChain4j 使用 Elasticsearch 作为嵌入存储

David Pilato

准备好打造最先进的搜索体验了吗?

足够先进的搜索不是一个人的努力就能实现的。Elasticsearch 由数据科学家、ML 操作员、工程师以及更多和您一样对搜索充满热情的人提供支持。让我们联系起来,共同打造神奇的搜索体验,让您获得想要的结果。

亲自试用