Getting started with Langchain4j

박병주·2025년 4월 21일
0

Spring

목록 보기
8/9

항상 AI 모델을 쓰려면 파이썬을 통해서 가져왔는데, 기본적인 Spring AI는 그 기능이 너무 제한적이어서 사용하기 불편했다. 이번에는 자바를 위한! Langchain4j를 프로젝트에 도입해 보았다.

의존성 추가

implementation 'dev.langchain4j:langchain4j-google-ai-gemini:1.0.0-alpha1'
implementation 'dev.langchain4j:langchain4j-open-ai:1.0.0-alpha1'
implementation 'dev.langchain4j:langchain4j-neo4j:1.0.0-alpha1'
  • 먼저 프로젝트의 의존성을 추가한다. gradle 기준으로 작성 되었다.
  • 첫 번째와 두 번째 각각 어떤 모델을 쓸지에 따라 바뀐다. (1번 gemini, 2번 gpt)
    각각 본인이 쓸 모델이 맞춰서 잘 가져올 것!
  • 세번째는 이번 프로젝트에서 사용한 neo4j(그래프db)와 ai 모델과 결합하기 위한 의존성 추가이다. 작성하지 않아도 무관하다.

설정

각각 모델에 맞는 구현체를 찾아 API key와 모델 명을 넣어주고 추가적인 파라미터를 넣어준다.

Gemini Configuration

@Configuration
public class ChatLanguageModelConfig {
    @Value("${GEMINI_AI_KEY}")
    private String aiKey;
    @Value("${GEMINI_AI_MODEL_NAME}")
    private String modelName;

    // Gemini 사용 시
    @Bean
    public ChatLanguageModel chatLanguageModel() {
        return GoogleAiGeminiChatModel.builder()
                .apiKey(aiKey) // API 키 설정
                .modelName(modelName) // 모델 이름 설정
                .temperature(1.0)
                .build();
    }

ChatGpt Configuration


@Configuration
public class ChatLanguageModelConfig {

    @Value("${OPEN_AI_KEY}")
    private String aiKey;
    @Value("${OPEN_AI_MODEL_NAME}")
    private String modelName;

    // chat gpt 사용 시
    @Bean
    public ChatLanguageModel chatLanguageModel() {
        return OpenAiChatModel.builder()
                .apiKey(aiKey)
                .temperature(1.0)
                .timeout(Duration.ofSeconds(10000)) // 추론형 테스트 용 타임아웃
                .modelName(modelName)
                .build();
    }
}
  • 추론형 모델을 쓸 경우 응답시간이 오래 걸릴 수 있기 때문에 Timeout을 지정해두었다.

활용

@Slf4j
@Service
@RequiredArgsConstructor
public class AiService {
    private final ChatLanguageModel chatLanguageModel;

    // 임의 작성된 AI 시스템 프롬프트
    private static final String SYSTEM_PROMPT = 
    		"""
            당신은 친절한 상담가입니다. 마음이 아픈 사람으로 
            부터 심리상담을 전문적으로 진행합니다.
            항상 다음 요건에 따라 상담이 진행되어야 합니다.
            1. 현재 심리 상태를 파악한다.
            2. 심리상태에 대해서 설명한다.
            3. 부정적인 부분에 대한 해결책을 제시한다.
            """;
    
    public String consult(String request) {
        try {
            String userPrompt = request;

            // AI 모델에서 응답 얻기
            SystemMessage systemMessage = new SystemMessage(SYSTEM_PROMPT);
            UserMessage userMessage = new UserMessage(userPrompt);
            AiMessage aiMessage = chatLanguageModel.generate(systemMessage, userMessage).content();
            // Langchain4j AiMessage에는 text() 메서드가 표준입니다. toString()은 객체 표현을 반환할 수 있습니다.
            String response = aiMessage.text();

            log.info("AI 응답 수신 완료: {} 자", response.length());
            log.debug("AI 응답 전문: {}", response);
            return response;
        } catch (Exception e) {
            log.error("AI로 음원 데이터 생성 실패", e);
            throw new RuntimeException("AI로 응답 데이터 생성 실패: " + e.getMessage(), e);
        }
    }
}
  • 시스템 프롬프트를 적절히 작성 후 유저 프롬프트는 파라미터로 받아서 보내도 록 작성 했다.
  • 시스템 프롬프트는 요청 시. AI 서비스 부분에서 맡는 역할이나, 변하지 않는 기본적인 사항들을 적어주며, 유저 프롬프트는 사용자의 입력같은 요청마다 유동적으로 변하는 값들을 넣어준다.
  • 실제 프로젝트에 사용된 코드를 간소화하여 작성된 코드입니다. 실제 동작에는 수정이 필요할 수 있습니다.

활용 2

neo4j의 데이터 구조를 참조하여 원하는 사이퍼 쿼리 값을 가져온다.

@Service
@RequiredArgsConstructor
public class Neo4jContentRetrieverService {

    private final Neo4jGraph neo4jGraph; // 의존성 주입된 Neo4jGraph
    private final ChatLanguageModel model;
    private Neo4jContentRetriever retriever;

    @PostConstruct
    public void init() {
        this.retriever = Neo4jContentRetriever.builder()
                .graph(neo4jGraph)
                .chatLanguageModel(model)
                .build();
    }

    public List<Integer> retrieveContent(int trackCount) {
        // 쿼리 실행 및 결과 조회
        Query query = new Query("3번 트랙에 추천할 다른 트랙 " + trackCount + "개");
        List<Integer> list = new ArrayList<>();
        for (Content content : retriever.retrieve(query)) {
            list.add(Integer.parseInt(content.textSegment().text()));
        }
        return list;
    }
}
  • Neo4jContentRetriever는 빈에 등록되어 있지 않아서 init()으로 객체를 할당.
  • 코드의 일관성을 유지하기 위해서 빈으로 등록하는 작업을 하시는 것을 추천한다.
  • 사이퍼 쿼리에 대한 값을 가져온다.

문제점

  1. 복잡한 사이퍼 쿼리문을 요구할 때 문법적 오류가 발생한다.
  2. 데이터 반환 형식이 일정하지 않다.

마무리

LangChain4j는 Java 개발자에게 Python 없이도 강력한 AI 모델을 쉽게 통합할 수 있는 훌륭한 도구이다. Spring AI보다 유연하고 확장 가능한 기능을 제공하며, Gemini, ChatGPT, Neo4j 등 다양한 기술과 통합할 수 있어 프로젝트에 큰 도움이 되었다. 아직 초기 버전이라 안정성이 조금 떨어지지만, 간단하게 Java로 AI를 활용하고 싶다면 LangChain4j를 적극 추천한다.

profile
응애

0개의 댓글