LLM을 공부하다 보면 RAG라는 용어를 종종 접하게 된다.
RAG는 Retrieval-Augmented Generation의 약자로, 대규모 언어 모델의 출력을 최적화하기 위해 응답을 생성하기 전에 학습 데이터 소스 외부의 신뢰할 수 있는 정보를 참조하도록 하는 프로세스이다.
무엇이 문제였나?
LLM은 모두가 알고 있듯이, ChatGPT, Claude, Gemini 등과 같은 대규모 언어 모델은 방대한 데이터셋을 사용해 학습되었으며 이를 통해 다양한 작업을 수행할 수 있다.
그러나 일반적인 지식을 학습하고 확률적으로 답변을 생성하다 보니 다음과 같은 문제가 발생한다.
1. hallucination
가장 큰 문제 중 하나는 hallucination으로, 이는 모델이 학습한 데이터에 존재하지 않는 정보를 생성하는 현상을 의미한다.
최근에는 추론까지 가능한 모델의 경우 이러한 문제가 현저히 줄었으나, 확률적으로 답변을 생성하는 모델은 ‘확률’이라는 특성상 이 문제를 피하기 어렵다.
2. 오래된 정보 제공
LLM은 방대한 데이터셋을 학습했기 때문에 오래된 정보도 포함된다.
특히 개발을 하다 보면 굉장히 오래된 버전의 라이브러리를 사용하여 코드를 설명하거나, 복사 및 붙여넣기를 할 경우 해당 함수가 이미 deprecated되었음을 알 수 있는 문제가 발생할 수 있다.
3. 신뢰할 수 없는 출처로부터 응답 생성
인터넷에 올라와 있는 정보 중에는 사람이 업로드한 허위 정보나 신뢰할 수 없는 정보도 포함되어 있어, AI가 이를 학습함에 따라 가끔 출처가 불분명한 정보를 제공할 수 있다.
4. 용어 혼동으로 인한 정확성 부재
LLM은 다양한 훈련 소스에서 학습되기 때문에 여러 용어가 혼재하여 답변할 때, 동일한 개념이 다른 용어로 표현되어 사용자가 혼동할 수 있다.
RAG의 탄생
Input에 레퍼런스를 몽땅 넣어보자
위와 같은 문제들로 인해 초기에는 입력 프롬프트를 극도로 늘려 문제를 해결하려 했다.
예를 들어, 법에 관한 답변을 생성할 때 법전을 통째로 넣어버리는 식이었다.
하지만 입력할 때마다 법전을 참조해야 하므로 비용적으로 매우 비효율적이며 실제로 사용하기에도 매우 불편하다.
또한 LLM의 특성상 입력 데이터가 너무 많으면 hallucination 문제가 더욱 심해질 수 있다.
관련 있는 데이터만 참조하자: RAG
그래서 RAG는 이러한 문제를 해결하기 위해 입력 데이터 중 관련 있는 데이터만을 참조하도록 하는 방법을 제안한다.
위 도표처럼 RAG는 입력 데이터 중 관련 있는 데이터만을 참조하여 hallucination을 줄이고, 신뢰할 수 있는 정보를 바탕으로 응답을 생성한다.
너무 많은 컨텍스트는 Retrieval을 통해 제거되고, 신뢰할 수 있는 연관된 컨텍스트를 기반으로 응답을 생성하게 된다.
이 중 Search Relevant Information
의 경우 현재 일반적으로 임베딩 모델을 활용한 벡터 검색을 통해 관련 있는 정보를 찾아내고 있다.
검색은 검색 엔진이 있지 않나?
전통적인 검색 엔진은 토크나이저를 이용한 역인덱싱을 통해 매우 빠른 검색 속도를 제공한다.
그러나 일반적으로 키워드가 정확히 일치하는 경우에만 검색이 가능하기 때문에 산문으로 이루어진 Query를 이용해 검색해야 하는 RAG에는 적합하지 않다.
예를 들어 다음과 같은 문장을 이용해 검색한다면
스테이크의 익기 정도에 대해 검색해줘
검색 엔진은 다음과 같이 토크나이징한다
[스테이크, 익기, 정도, 검색]
이처럼 토크나이징되기 때문에, OR 조건에서는 관련 없는 ‘정도’와 ‘검색’ 키워드만 포함된 문서가 검색될 수 있고, AND 조건에서는 모든 키워드가 포함된 매우 적은 문서만 검색될 수 있다.
정작 사용자가 알고 싶었던 스테이크의 익기 정도(예: 웰던, 레어, 미디움 등)에 대한 정보는 검색되지 않는다.
해당 내용은 역인덱싱과 토크나이저 기반의 일반적인 검색 엔진 알고리즘을 따른 것이다. 최근에는 많은 검색 엔진이 벡터 검색을 지원하기 시작했다.
임베딩 모델
그래서 일반적으로 RAG에서는 임베딩 모델을 활용해 문장을 벡터로 변환하고 이를 이용하여 검색한다.
전통적인 검색 엔진은 단순히 ‘원숭이’ 키워드로 검색하면 해당 키워드가 포함된 문서를 찾아내는 방식이었다면, 임베딩 모델을 사용한 방식은 ‘원숭이’뿐만 아니라 ‘유인원’, ‘침팬지’ 등 원숭이와 관련된 모든 문서를 검색할 수 있다.
벡터는 단어를 숫자로 변환한 것으로, 일정한 차원을 가진다.
차원
예를 들어 ‘사과’와 ‘바나나’라는 단어를 각각 [0.5, 0.4]
, [0.2, 0.1]
로 변환할 수 있다.
quadrantChart Apple: [0.5, 0.4] Banana: [0.2, 0.1]
평면에 나타내면 위와 같이 표현할 수 있다.
이렇게 변환된 벡터를 바탕으로, 유사한 경우에는 서로 가깝게, 다른 경우에는 멀게 위치시키는 방법을 사용하여 유사한 문장을 찾아낼 수 있다.
이때 차원이 높을수록 보다 정밀한 검색이 가능하다. 예를 들어 평면(2차원)에서는 x, y 두 축만 존재하지만, 이를 100차원, 1000차원으로 확장할 수 있어 더욱 정확한 검색이 가능하다.
여기서 차원은 여러 기준을 내포할 수 있다. 예를 들어 ‘스펠링이 비슷한가’, ‘의미가 비슷한가’ 등이 그 예시가 될 수 있다.
당연히 차원이 많을수록 보다 포괄적인 의미에서 단어의 유사성을 판단할 수 있게 된다.
+ 차원의 저주
차원이 높을수록 ‘차원의 저주’ 문제가 발생한다.
즉, 차원이 증가하면 데이터의 밀도가 감소하여, 예를 들어 2차원 평면에 100개의 데이터를 표시한 것과 3차원 평면에 100개의 데이터를 표시한 것을 비교하면, 3차원 평면의 데이터가 더욱 희소해 보인다.
따라서 이러한 경우에는 차원을 축소하기 위해 PCA, T-SNE 등을 사용하기도 한다.
최근에는 임베딩 모델에서 차원의 저주는 주요 문제가 아니다. 구글에서 3072 차원의 모델을 발표한 것을 보면, 이러한 문제는 어느 정도 해결된 것으로 보인다.
누가 만들었을까?
잘 생각해보면, 수많은 산문을 벡터화하기 위해서는 엄청난 양의 데이터 관계 정보가 필요하다.
예를 들어, 한국어 ‘사과’와 영어 ‘Apple’을 의미적으로 동일하게 판단하기 위해서는, 사전에 이러한 정보를 포함한 데이터가 필요하다.
세상에는 수천, 수억 개의 단어가 있으며, 이들 간의 관계를 모두 라벨링하는 것은 일반적인 기업에서 불가능한 일이다.
이를 활용할 수 있는 형태로 모델을 만들어 제공하는 기업으로는 우리가 흔히 알고 있는 구글, OpenAI 등이 있다.
이들은 미리 조합된 AI 모델을 보유하고 이를 API 형태로 제공하고 있다.
실제 사용은 다음과 같은 다이어그램으로 표현할 수 있다.

저장하고 검색하기
매번 API를 통해 검색 데이터를 모두 벡터로 변환한다면 매우 비효율적이며, Embedding API 사용 비용도 상당히 높아질 것이다.
이를 해결하기 위해 검색 데이터를 벡터로 변환하여 저장하고, 벡터 연산을 활용하는 방법을 사용한다.
요즘은 잘 알려진 대부분의 데이터베이스가 벡터 연산 기능을 제공하고 있다.
(참조: PostgreSQL, MySQL, MongoDB)
이를 다이어그램으로 표현하면 다음과 같다.
- 검색 대상 데이터를 Embedding API를 통해 벡터로 변환한다.
- 변환된 벡터를 DB에 저장한다.
- 사용자가 질의하면, 질의를 Embedding API를 통해 벡터로 변환한다.
- 변환된 벡터를 DB에 저장된 벡터와 비교하여 가장 유사한 N개의 벡터를 찾아낸다.
- 찾아낸 벡터의 원본 데이터를 반환한다.
벡터 연산은 일반적으로 코사인 유사도를 사용한다.
코사인 유사도는 두 벡터 사이의 각도를 이용해 유사도를 측정하는 방법이다.
일반적으로 벡터의 크기는 고려하지 않는데, 이는 벡터의 크기가 유사도에 영향을 미치지 않기 때문이다.
결론
예전에는 Elastic Search와 같은 검색 엔진을 이용한 검색이 굉장한 신기술로 여겨졌으나, 현재는 임베딩 모델이 전통적인 검색 엔진을 대체하고 있는 것 같다.
키워드 일치가 중요하다면 전통적 검색엔진을 사용해볼 만하지만, 단순히 키워드 일치뿐만 아니라 의미적인 추론까지 가능한 임베딩 모델은 많은 부분에서 큰 가능성을 보여준다.
다음 포스팅에서는 실제로 구글의 임베딩 모델을 사용한 예제 코드를 통해 RAG의 구현 방법에 대해 보다 심층적으로 살펴보겠다.
Reference
- https://aws.amazon.com/ko/what-is/retrieval-augmented-generation/
- https://the-dev.tistory.com/30
- https://www.syncly.kr/blog/what-is-embedding-and-how-to-use
- https://modulabs.co.kr/blog/%EC%B0%A8%EC%9B%90%EC%9D%98-%EC%A0%80%EC%A3%BC-curse-of-dimensionality
- https://docs.voyageai.com/reference/embeddings-api
- https://api.ncloud-docs.com/docs/clovastudio-embedding
- http://platform.openai.com/docs/guides/embeddings
- https://cloud.google.com/vertex-ai/generative-ai/docs/embeddings?hl=ko