Java 애플리케이션에 LLM 통합을 간소화하는 LangChain4j 소개
LangChain4j(Java용 LangChain)는 일반 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 프로젝트에서 제공하는 키를 사용할 것입니다:
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
우리는 위대한 올라마 프로젝트를 사용할 수 있습니다. 머신에서 로컬로 LLM을 실행하는 데 도움이 됩니다.
langchain4j-ollama 아티팩트를 추가해 보겠습니다:
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-ollama</artifactId>
<version>${langchain4j.version}</version>
</dependency>테스트를 사용하여 샘플 코드를 실행하고 있으므로 프로젝트에 Testcontainer를 추가해 보겠습니다:
<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 객체를 이전에 사용했던 대신 으로 변경하면 됩니다: OpenAiChatModel 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를 사용하여 비공개 데이터 세트에 질문을 하는 방법에 대해 알아보겠습니다. 이를 통해 애플리케이션 검색을 한 단계 더 발전시킬 수 있습니다.

