ブログ

LangChain4j を導入して、LLM の Java アプリケーションへの統合を簡素化します。

LangChain4j (LangChain for Java) は、プレーン Java で RAG アプリケーションを構築するための強力なツールセットです。

LangChain4j フレームワークは次の目標を掲げて 2023 年に作成されました。

LangChain4j の目標は、LLM を Java アプリケーションに簡単に統合することです。

LangChain4j は次の標準的な方法を提供します:

  • 与えられたコンテンツ(例えばテキスト)から埋め込み(ベクトル)を作成する

  • 埋め込みを埋め込みストアに保存する

  • 埋め込みストア内の類似ベクトルを検索する

  • LLMと議論する

  • チャットメモリを使用して、LLMとの議論の文脈を記憶する

このリストは網羅的なものではなく、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>

残りのコードでは、 OpenAIにアカウントを登録することで取得できる独自の API キー、またはデモ目的でのみ 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 統合を構築するのに役立つツールセットを提供します。ここでは、先ほど定義したChatLanguageModelを自動的に呼び出すchatメソッドを提供するAssistantインターフェイスを作成します。

interface Assistant {
  String chat(String userMessage);
}

LangChain4j AiServicesクラスにインスタンスを構築するよう依頼するだけです。

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

素晴らしい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();
}

先ほど使用したOpenAiChatModelではなく、 modelオブジェクトをOllamaChatModelに変更するだけです。

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

Elasticsearchを埋め込みストアとして使用したLangChain4j

David Pilato

最先端の検索体験を構築する準備はできましたか?

十分に高度な検索は 1 人の努力だけでは実現できません。Elasticsearch は、データ サイエンティスト、ML オペレーター、エンジニアなど、あなたと同じように検索に情熱を傾ける多くの人々によって支えられています。ぜひつながり、協力して、希望する結果が得られる魔法の検索エクスペリエンスを構築しましょう。

はじめましょう