
RAG 시스템의 핵심은 Retriever가 질문과 유사도 높은 문서를 가져온 것을 활용해 LLM이 최신화되고 정확한 응답을 생성하도록 하는 것이다. 기본 방식으로도 이전보다는 뛰어난 응답을 생성해낼 수 있지만 더나아가 LLM의 특성을 이용해 더 높은 품질의 응답을 이끌어 낼 수 있다. LLM은 유사한 문서가 많다고 응답 품질이 무작정 높아지는 것이 아니라 유사한 문서가 상위에 있어야 더 높은 품질의 응답을 생성해준다. 즉, 검색된 유사도 높은 문서에 더 정교한 기준으로 다시 평가해 관련성 높은 문서를 위로 올리거나 관련 없는 문서를 제외함으로써 품질을 높일 수 있다. 이때, 더 높은 유사도의 문서를 검색할 수 있게 도와주는 추가적인 방법이 Re-rank이다. Re-rank는 말 그대로 순위를 다시 매기..

공약21 서비스는 기본적으로 후보자 정당에서 내놓은 PDF 정책 공약집에 포함된 내용을 바탕으로 정보를 제공하기 때문에 이를 기반으로 한 전처리 과정이 필요하다.전처리를 위한 전처리공약 데이터는 크게 PDF와 이미지로만 사용했고 만약 정책 공약 데이터가 PDF라면 먼저 RAG 시스템을 위한 전처리 과정(LOAD → SPLIT → EMBED → STORE)의 전처리 과정이 필요하다.PDF를 페이지(쪽)별로 저장주요 정당의 정책 공약집은 아래처럼 PDF의 한 페이지가 양쪽(양쪽 스캔 방식)으로 구성되어 있다.개발시에 21대 대통령 후보의 정책 공약집이 발표되지 않아 20대 대선 공약집을 기준으로 개발했으며 21대 후보의 공약집 또한 비슷한 형태였다. 이러한 구성 방식은 텍스트를 추출할 때 200쪽과 201쪽..

RAG(Retrieval-Augmented Generation)이번 공약21 프로젝트를 하면서 LLM을 사용해서 사용자에게 더 정확한 후보자의 공약정보를 제공하기 위해 RAG 시스템을 담당하게 됐다. 그렇다면 이 RAG 시스템은 무엇일까? Why RAG?LLM이 등장한 이후로 많은 사람들이 적극적으로 LLM을 이용해 학습하거나 일을 처리하거나 등의 다양한 작업을 처리한다. 이런 일이 가능한 이유는 LLM을 개발하는 개발사에서 대량의 학습 데이터를 활용해 AI를 학습시켜놓았기 때문이다. 하지만 이러한 학습은 실시간으로 이루어지는 과정이 아니다. 즉, 어제 새로운 정보가 등장했다면 AI는 이 정보에 대한 데이터를 학습하지 못했다는 의미로 사용자의 질문에 답하기 위해서는 외부 검색 등을 통해 그럴듯한 답을 내..

> 공약21 사용해보기 공약21 - 21대 대선 후보자 공약 비교 서비스AI가 21대 대선 후보자들의 공식 정책 공약집을 쉽고 명확하게 비교해드립니다. 대선 공약, 정책, 후보자 비교를 한눈에 확인하세요.gongyak21.site 소개대선 후보자를 선택할 때 중요한 요인 중 하나는 후보자가 내새운 공약일 것입니다. 20대 대선을 치뤘던 과거 자료들을 보면 10대 공약과 같은 주요 공약들은 비교적 쉽게 찾아볼 수 있습니다. 하지만 10대 공약 이외에도 해당 정당에서 내세운 공약들이 정말 많습니다. 20대 대선 당시 국민의힘이 제공한 대통령선거 정책공약집은 174페이지 분량의 PDF 문서입니다. 더불어민주당의 경우에는 194페이지의 PDF 문서입니다. 이를 꼼꼼히 확인하여 후보를 선택하는 것이 가장 좋겠지..
110 옮기기 정의0과 1로 이루어진 문자열에서 110을 뽑아서 임의의 위치에 다시 삽입하여 변형할 수 있는 문자열 중 사전 순으로 가장 앞에 오는 문자열을 구해야 한다. 풀이이 문제를 크게 2 부분으로 나눌 수 있다.문자열에서 모든 110을 뽑아내는 과정뽑아낸 110을 임의의 위치를 찾아 삽입하는 과정첫 번째 과정인 문자열에서 모든 110을 뽑아내는 과정은 스택 자료구조를 활용해 뽑을 수 있다.int count = 0;Deque stack = new ArrayDeque();for (char ch : str.toCharArray()) { if (stack.size() >= 2 && ch == '0') { char p = stack.pop(); char pp = stack.pop(); if (p ..

먼저, 스프링부트와 JPA에서 데이터를 저장하는 다음과 같은 코드를 보자.@Service @RequiredArgsConstructor public class UserService { private final UserRepository userRepository; public User externalSave(User user) { return internalSave(user); } @Transactional public User internalSave(User user) { return userRepository.save(user); } }만약 외부에서 UserService.externalSave(user); 를 실..
스트래티지 패턴이라는 이름을 처음 들어봤어도 스프링을 사용해보았다면 아마 금방 이해할 수 있을 것이다. 우리가 스프링을 사용해 웹 애플리케이션을 구현할 때, 일반적으로 사용할 빈 타입을 클래스 내에 멤버 변수로 포함시키고 스프링이 해당 빈 객체를 주입함으로써 사용하게 된다. @Controllerpublic class HelloController { private final HelloService service; public HelloController(HelloService service) { this.service = service; }} 이렇게 함으로써 HelloController의 HelloService 객체는 런타임에서 어떤 객체가 주입되느냐에 따라 실행할 동작을 결..

언론사나 매거진 등은 구독 서비스를 제공한다. 해당 매체에 구독을 신청하게 되면 구독자가 직접 매체에 방문하지 않더라도 매체에 새로운 글이 발행되는 등의 이벤트에 따라 구독자에게 메일을 전송해 알려준다. 그럼 구독자는 메일을 보고 글을 읽는 등의 이벤트를 처리하게 된다.옵저버 패턴은 이와 동일하다. 옵저버 패턴은 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들한테 연락이 가고 자동으로 내용이 갱신되는 방식으로 일대다(one-to-many) 의존성을 정의한다. 옵저버 패턴의 참여자는 둘로 나뉜다.주제 객체(subject) : 언론사나 매거진 같이 데이터를 제공하는 객체옵저버(observer) : 주제 객체를 구독하고 있는 객체 옵저버 객체들은 주제 객체를 구독한다. 주제 객체의 상태가 업데이트되면..

스프링을 배웠다면 수도 없이 많이 들었던 개념 중 하나가 싱글턴 패턴일 것이다. 스프링은 빈으로 등록된 객체들은 기본적으로 싱글턴으로 관리되기 때문이다. 객체들 중에는 사실 단 하나만 존재해도 되는 것들이 있다. 스레드 풀이나 로그 기록용 객체 등이 이에 해당한다. 예를 들어 스레드 풀 객체가 두 개가 존재한다고 생각해 보자. 어떤 객체는 스레드 풀 A에서, 또 어떤 객체는 스레드 풀 B에서 스레드를 가져와 사용했을 때, 스레드 풀 A에서 가져다 쓰는 객체의 호출 빈도가 높다면 A 스레드 풀 내의 스레드는 쉴 틈 없이 사용되고 있을 것이고 이에 비해 B 스레드 풀의 스레드들은 놀고 있는 상황이 되어 모든 자원을 효율적으로 사용하지 못해 성능을 온전히 낼 수 없게 된다. 즉, 하나만 존재해도 되는 객체가 ..

SpringBoot에서 RabbitMQ의 메시지를 처리하다 예외가 발생하게 되면 어떻게 될까? `Consumer.receiveMessage(User user)` 메서드에서 일부러 `RuntimeException`을 발생시켜 보자.public void receiveMessage(User user) { System.out.println("Received "); throw new RuntimeException("message processing failed");} 저번에 메시지를 보내는 것과 동일한 테스트 코드를 실행시킨다.@Testpublic void obj_message() throws InterruptedException { User user = new User("name", "email..