RAG (Retrieval Augmented Generation, 검색 증강 생성)
오늘은 요즘 LLM 관련 기술 중 많이 언급되는 RAG에 대해서 이야기해보려고 합니다. RAG(영어권 사람들은 '랙'이라고 읽더라고요)은 Retrieval Augmented Generation의 약자입니다. 우리 말로는 검색 증강 생성이라고 부릅니다. Retrieval을 검색이라고 번역한 것인데요. 보통 검색하면 Retrieval보다는 Search가 떠오르지 않으시나요?
Search와 Retrieval의 차이는 무엇일까요? 좀 뜬금없어 보이지만 오늘 논의와 관련이 있기 때문에 잠시 이야기하고 넘어가겠습니다.
먼저 사전적인 의미부터 살펴보면 Search는 말 그대로 검색을 의미합니다. 수많은 후보 중에 내가 원하는 특정 대상을 찾는 것이 검색입니다. 인터넷의 수많은 웹페이지 중에 내가 원하는 웹페이지를 찾는 것도 검색입니다. 긴 문서에서 Control(또는 Cmd)+F를 누르면 검색 창이 뜨고, 여기에서 내가 찾고 싶은 키워드를 입력해서 그 부분을 찾는 것도 검색입니다.
Retrieval의 사전적의미는 회수입니다. 수많은 후보 중에서 내가 원하는 것을 꺼내 온다는 뜻을 가지고 있습니다. 도서관의 수많은 책 중에서 내가 원하는 책을 꺼내는 것, 데이터베이스의 수많은 항목 중에 내가 원하는 항목을 꺼내는 것이 Retrieval입니다. 그런데 생각해보면 Retrieval을 하기 위해서는 그전에 Search를 해야 합니다. 도서관에서 내가 원하는 책을 먼저 검색하고 나서 그 책을 꺼낼 수 있고, 데이터베이스에서 내가 원하는 항목을 검색하고 나서 그 항목을 꺼낼 수 있습니다. 이런 특성 때문에 Retrieval은 대부분 검색을 동반합니다. 즉, Retrieval은 보통 검색 + 검색된 항목을 꺼내는 것을 의미합니다.
엄밀히 따지면 RAG는 검색 증강 생성보다는 "검색+대상 항목 인출 증강 생성"이 정확하겠지만 말이 너무 길고 복잡하고 입에 잘 안 붙습니다. 한편으로 생각해 보면 검색을 하는 이유가 검색된 항목을 가지고 이어서 다른 동작을 하기 위한 것이기 때문에 틀린 이름은 아닙니다.
RAG 기술에 대해서 본격적으로 이야기하기 전에 도대체 왜 RAG라는 기술이 나왔는지부터 이야기해 보겠습니다.
LLM의 고질적인 문제
LLM(요즘 대세인 Decoder 모델)이 하는 일은 단순하게 말하면 주어진 입력의 다음 단어(정확히는 토큰)을 예측하는 것입니다. "무궁화 꽃이"라는 입력을 주면 "피었습니다."를 예측(생성)하는 것이 LLM이 하는 일입니다. LLM의 작동 원리는 https://jins-sw.tistory.com/48 을 참조해 주세요.
그럼 LLM은 어떻게 다음 단어를 예측할 수 있을까요? 훈련 과정에서 엄청난 양의 텍스트를 봤기 때문입니다. LLM은 훈련 과정에서 "무궁화 꽃이 피었습니다."라는 문장을 봤을 겁니다. 직접 보지는 않았더라도 "개나리 꽃이 피었습니다."같은 비슷한 문장을 봤을 수도 있습니다. 즉, LLM은 훈련 과정에서 배운 데이터를 기반으로 다음 단어를 예측합니다.
여기에서 한 가지 의문이 생깁니다. 만약에 LLM이 훈련 과정에서 본 적이 없는 입력을 받으면 어떻게 될까요? 사람이라면 모르는 질문을 받으면 모른다고 할 겁니다. 하지만 Machine Learning은 모른다는 개념을 모릅니다. 자칫 철학적인 이야기로 번질 수 있는데요. AI에게 "모른다는 사실"을 가르치는 것은 또 하나의 커다란 연구 분야입니다. 오늘은 이 이야기는 하지 않겠습니다.
대신 LLM은 자신이 할 수 있는 범위 내에서 최선을 다해 다음 단어를 예측합니다. 최선을 다하기는 하지만 LLM이 예측한 다음 단어의 신뢰도는 떨어집니다. LLM이 엉뚱한 단어를 예측하기 시작하면 이상한 문장이 만들어지고 우리는 LLM이 헛소리를 한다고 알 수 있지 않을까요? 안타깝게도 그렇지 않습니다. 다행인지 불행인지 LLM은 너무나도 많은 데이터를 보고 훈련됐기 때문에 사실성은 떨어질 수 있지만 겉보기에는 그럴듯한 문장들을 만들어냅니다. 말빨(?)은 엄청 좋고 자존심은 강하지만 역사에 대해서 전혀 모르는 사람이 있다고 생각해 봅시다. 이 사람에게 고려 무신 정권에 대해서 물어봤다고 합시다. 이 사람은 사실 고려 무신 정권에 대해서는 아는 바가 전혀 없지만 특유의 말빨을 활용해 정말 그럴듯한 거짓말을 지어냅니다. LLM도 같습니다. 이런 형상을 Hallucination이라고 부릅니다. LLM이 거짓말쟁이라는 불명예를 가지게 된 이유죠.
예를 들어 ChatGPT에게 우리 부서 또는 우리 반에서 가장 키가 큰 사람이 누구인지 물어봤다고 해보죠. LLM은 태연하게 "철수가 203cm로 가장 크다"고 대답할 수 있습니다. 하지만 실제로 우리 부서에는 철수라는 사람도 없고, 있다고 하더라도 철수는 키가 203cm도 아닙니다. 아마 LLM 학습 데이터 어딘가에 비슷한 문장이 있었을 겁니다. LLM 입장에서는 최선을 다해서 "다음 단어를 예측"한 것뿐입니다. LLM은 진실을 말하는 기술이 아니라 단순히 "다음 단어를 예측"하는 기술이니까요.
Hallucination은 굉장히 골치 아픈 문제입니다. LLM이 만든 정보는 너무 진짜 같아서 거짓말인진 아닌지 판단하기가 어렵기 때문입니다. 그래서 LLM 개발자들은 (어려운 일이지만) LLM에게 답을 모르는 경우는 모른다고 답하도록 가르칩니다. 이제 LLM은 (완전하지는 않지만) 자기가 모르는 것에 대해서는 모른다고 답을 하기 시작합니다.
이제 LLM에게 우리 부서 또는 우리 반에서 가장 키가 큰 사람이 누구인지 물어보면 LLM은 모른다고 답합니다. 문제를 완화하기는 했지만 근본적인 문제를 해결하지는 못 합니다. 우리 부서에서 가장 키 큰 사람이 누군지 알아내지 못한 것은 마찬가지니까요. 그리고 여전히 가끔 Hallucination(거짓말)을 일으키기도 합니다.
이제 풀어야 할 두 가지 문제를 정의해 보겠습니다.
- LLM이 어떤 질문에 대해서는 답을 주지 못하고 모른다고 하는 문제
- LLM이 어떤 질문에 대해서는 마치 그럴듯한 거짓말을 하는 문제 (Hallucination)
LLM이 답을 모른다고 하는 것은 Hallucination을 막기 위해 LLM에게 그렇게 가르쳤기 때문입니다. 그럼 Hallucination은 왜 생기는 걸까요? 여러 가지 이유가 있지만 가장 근본적인 이유는 LLM이 답(다음 단어)을 만들어 내기에 충분한 데이터를 가지고 있지 않기 때문입니다.
문제 해결을 위한 아이디어
LLM에 대한 환상(?)과는 다르게 LLM은 배우지 않은 것에 대해서는 답을 하지 못 합니다. 글짓기나 이메일 초안 쓰기처럼 사실에 기반하지 않은 태스크에는 큰 영향이 없을 수 있습니다. 하지만 사실에 입각해서 답을 해야 할 때는 곤란한 상황이 펼쳐집니다.
(이 때문에 AI가 발달하더라도 창의적인 예술 분야는 대체가 어려울 것이라는 예상과 달리 예술처럼 창의적인 분야가 빠르게 위협을 받고 있습니다)
그렇다면 해결법은 무엇일까요? 예를 들어 앞에 들었던 예시인 우리 부서에서 가장 키가 큰 사람을 찾는 문제를 생각해 보겠습니다. 가장 간단한 해결 방법은 LLM에게 우리 부서 사람들의 키를 가르쳐 주는 겁니다. 이 방법에는 두 가지 문제가 있습니다.
첫 번째는 어마어마하게 방대한 LLM 훈련 데이터 중 내가 추가한 조그마한 데이터가 과연 얼마나 LLM에 영향을 미칠지 알 수 없습니다. LLM 훈련 데이터 중 전 세계 인구의 키에 대한 글이 있었다면 거기에 묻혀 버릴지도 모릅니다.
두 번째는 내 데이터를 넣어서 LLM을 훈련시키는 것이 엄청나게 어렵고 비싼 일이라는 점입니다. GPT나 Gemini 정도의 LLM을 만들 수 있는 회사는 전 세계에서도 손에 꼽힙니다. 기술력도 중요하지만 데이터와 훈련 인프라를 감당할 자본력도 중요합니다. 좀 작은 LLM으로 가더라도 쉽지 않습니다. 효율적인 Fine Tuning 기법들(https://jins-sw.tistory.com/59)이 많이 나오고는 있지만 Fine Tuning도 그렇게 녹녹한 일은 아닙니다.
이때 똑똑한 누군가(https://arxiv.org/abs/2005.11401) 아이디어를 냅니다.
"LLM은 그대로 쓰고, 답에 필요한 정보만 찾아서 그때그때 넣어주면 되지 않을까?"
사용자가 궁금해하는 질문에 대한 답을 가지고 있을 법한 정보를 찾고(Retrieval), 이 정보를 중요하게 여기게 한 다음에(Augmented), 답을 생성(Generation)하자! Retrieval Augmented Generation!
Instruction Tuning 그리고 Prompt
LLM은 다음 단어를 예측하는 기술입니다. 앞에 이야기한 대로 "무궁화 꽃이"라고 하면 "피었습니다."를 예측(생성)하는 기술이죠. 만약에 LLM에게 "세계에서 가장 높은 산이 어디야?"라고 하면 "에베레스트산입니다."라고 할 겁니다. 안타깝게도 실제로는 그렇지 않습니다. LLM은 아마도 "나도 그 질문이 궁금해"라거나 "라는 질문은 흔한 질문 중 하나입니다."와 같은 말을 만들어 낼 겁니다.
- 세계에서 가장 높은 산이 어디야? 에베레스트산입니다.
- 세계에서 가장 높은 산이 어디야? 나도 그 질문이 궁금해.
- 세계에서 가장 높은 산이 어디야?라는 질문은 흔한 질문 중 하나입니다.
세 가지 문장 중에 1번 문장이 특별히 더 자연스러울까요? 아닙니다. 다음 단어를 예측한다는 관점에서는 1, 2, 3 모두 자연스러운 문장입니다. 하지만 우리가 LLM에게 기대하는 것은 1번이고, 실제로 ChatGPT나 Gemini는 1번과 같은 답을 생성합니다.
비결은 Instruction Tuning이라고 부르는 기술입니다.
막 훈련을 마친 LLM에게 "세계에서 가장 높은 산이 어디야?"라고 물으면 1, 2, 3 중 어떤 것을 만들어내더라도 이상한 일이 아닙니다. 주어진 입력에 이어질 자연스러운 단어를 예측하라고 배운 모델이기 때문입니다. 1, 2, 3 중 우리가 원하는 답이 있다면 LLM이 이 쪽으로 답을 하도록 가르쳐야 합니다. 즉, 나의 지시(Instruction)를 따라 답을 하도록 튜닝해야 합니다.
우리의 예로 보면, "세계에서 가장 높은 산이 어디야?"라고 했을 때 "에베레스트산입니다."라고 답하도록 추가 훈련을 시키는 겁니다. 이런 추가 훈련을 Instruction Tuning이라고 부릅니다. Instruciton Tuning을 할 때는 Prompt 형태로 입력을 주고, 원하는 값을 출력으로 줍니다. 아래와 같은 데이터를 많이 만들어서 훈련을 시킵니다.
입력:
다음 질문에 대해 답해주세요. "세계에서 가장 높은 산이 어디야?"
출력:
에베레스트산입니다.
이 과정을 거치면 LLM은 단순히 다음 단어를 예측하는 것이 아니라 특정한 방향으로 답하기 시작합니다.
대규모 텍스트 데이터로 막 훈련을 마친 LLM을 Pre-trained Model이라고 부르고, Instruction Tuning을 마친 모델을 Instruction tuned Model이라고 부릅니다. LLaMA, Gemma, OpenELM 등 LLM을 공개할 때 보면 Pre-trained Model과 Instruction tuned Model(Chat 모델이라고 된 경우도 많습니다)을 따로 공개하는 경우들이 있습니다. 두 가지 모델의 용도가 다르기 때문입니다. 우리가 일반적으로 생각하는 용도로 쓰기에는 Instruction tuned model이 적합하지만 순수한 Pre-trained Model을 필요로 하는 경우도 있습니다.
Instruction tuned Model의 여러 가지 장점 중 하나는 Instruction(또는 Prompt)을 잘 따른다는 점입니다. Instruction Following을 잘한다고도 하는데요(전설의 레전드, 어둠의 다크니스 느낌). Instruction tuning 과정에서 입력으로 주어진 Prompt에 따라 출력을 생성하는 훈련이 됐기 때문에 새로운 Prompt를 보더라도 이 Prompt에 맞춰 답을 생성합니다. Pre-trained Model은 이런 개념이 없기 때문에 내가 시킨 지시(Instruction)를 무시하는 경우가 상대적으로 많습니다.
그런데 왜 RAG 이야기를 하다가 이렇게 길게 Instruction Tuning 이야기를 했을까요? 바로 Prompt와 Instruction Following이 RAG의 핵심 중 하나이기 때문입니다.
RAG
아래는 https://aws.amazon.com/ko/what-is/retrieval-augmented-generation/ 에 실린 RAG 아키텍처입니다.
RAG는 명성에 비해 상대적으로 직관적인 기술입니다. RAG가 인기 있는 이유 중 하나이기도 하고요. RAG는 아래와 같이 작동합니다.
- 사용자가 질문을 보냅니다. 이 정보는 Prompt와 함께 시스템에 전달됩니다.
- 시스템은 질문과 가장 관련성이 높은(그래서 답을 가지고 있을 것 같은) 정보(문서, 데이터 덩어리 등)를 검색하고 꺼냅니다(Retrieval).
- 시스템은 기존 Prompt에 앞에서 찾은 정보를 추가(Augmented)합니다.
- 시스템은 이렇게 보강된 Prompt를 LLM에게 보냅니다.
- LLM은 사용자 질문과 관련된 정보를 고려해 답을 생성합니다.
설명만으로 느낌이 잘 안 오니 예시를 들어보겠습니다.
- 사용자가 "우리 부서에서 키가 가장 큰 사람은 누구야?"라고 물어봅니다. 시스템은 Query:"우리 부서에서 키가 가장 큰 사람은 누구야?", Prompt:"아래 사용자의 질문에 적절한 답을 생성하시오."라는 입력을 받습니다.
- 시스템은 "우리 부서에서 키가 가장 큰 사람은 누구야?"과 가장 관련성이 높은 데이터를 찾아봅니다. 데이터 베이스에서 우리 부서 사람들의 키 목록을 찾았습니다. 시스템에게 "신장 정보 - 철수 192cm, 길동 175cm, 영희 163cm, 제임스 187cm"라는 문서를 보내줍니다.
- 시스템은 아래와 같은 최종 Prompt를 만듭니다.
추가 정보: 신장 정보 - 철수 192cm, 길동 175cm, 영희 163cm, 제임스 187cm 추가 정보를 고려해 아래 사용자 질문에 적절한 답을 생성하시오. 사용자 질문: 우리 부서에서 키가 가장 큰 사람은 누구야?
- 시스템은 위의 Prompt를 LLM에게 보냅니다.
- LLM은 "가장 키가 큰 사람은 철수로 192cm입니다."라는 답을 생성합니다.
여기에는 두 가지 주요한 기술이 필요합니다.
Neural Retrieval
첫 번째는 사용자 질문과 관련성이 높은 데이터를 찾아낼 수 있어야 합니다. 이 단계는 어떤 검색(또는 Information Retrieval) 기술도 사용할 수 있지만 RAG를 구성하는 데는 보통 Neural Retrieval 기술을 사용합니다. Neural Retrieval 기술은 두 대상 사이의 유사도를 측정하고, 유사도가 높을수록 관련성이 높다고 간주하는 방식입니다.
예를 들어, 데이터 베이스에 아래 문서들이 있다고 가정해 보겠습니다.
- 신장 정보 - 철수 192cm, 길동 175cm, 영희 163cm, 제임스 187cm
- 생일 정보 - 철수 5/12, 길동 4/5, 영희 12/21, 제임스 1/3
- 2023년 예산 및 집행 계획
이 셋 중에 "우리 부서에서 키가 가장 큰 사람은 누구야?"라는 문장과 유사도가 가장 높은 문서는 무엇일까요? 첫 번째 문서입니다. 그렇다면 Neural Retriveal 기술은 첫번째 문서가 "우리 부서에서 키가 가장 큰 사람은 누구야?"와 유사하다는 것을 어떻게 알까요?
먼저 Embedding 기술을 써서 문서들을 Vector로 변환합니다. Embedding 기술을 사용하면 텍스트를 수치(Vector)로 변환할 수 있습니다. 단순히 수치로 변환되는 것이 아니라 의미적으로 비슷한 텍스트는 비슷한 수치를 가지게 됩니다. (백두산, 한라산)은 비슷한 값을 가지고 (백두산, 페라리)는 차이가 큰 값을 가집니다. 이렇게 변환한 Vector들을 DB로 저장해 둡니다. Vector를 효과적으로 저장하고 찾기 위한 다양한 솔루션(Vector DB)들도 개발되고 있습니다.
이제 사용자 질문이 들어오면 동일한 Embedding 기술을 써서 사용자 질문을 Vector로 변환합니다. 그리고 이 사용자 질문 Vector를 앞의 문서 Vector DB 내 Vector들과 비교해 봅니다. 가장 유사한 (차이가 적은) Vector를 선택하고 거기에 딸린 문서를 꺼내옵니다.
이 글의 처음에 굳이 지루하게 Search와 Retrieval에 대해서 다룬 이유가 이것입니다. RAG에서 Search가 아닌 Retrieval이라는 표현을 쓴 이유는 DB에 저장된 문서를 Retrieval 해온다는 의미가 중요하기 때문입니다.
Augmented Prompt
이후 과정은 상대적으로 간단합니다. LLM에게 보낼 Prompt에 Retrieval 단계에서 찾은 정보를 추가하고, 이 정보를 참고하라고 알려주면 됩니다. 좀 더 엄격하게 하고 싶다면 Retrieval한 정보에 기반해서만 답을 하라고 하면 됩니다.
이 과정이 간단할 수 있는 이유는 Instruction Following 단계에서 LLM이 Prompt를 잘 따르도록 이미 훈련을 시켰기 때문입니다. 이 과정이 없었다면 LLM은 Retrieval 한 정보를 무시할 가능성이 높습니다.
하지만 이렇게 하더라도 LLM이 Prompt를 잘 따르지 않거나 성능이 만족스럽지 않을 수 있습니다. 이럴 때는 Augmented Prompt 형태로 데이터를 만들고 Fine Tuning을 시키면 성능을 높일 수 있습니다.
RAG는 언제 쓸까요?
RAG는 구현 난이도에 비해 효과가 매우 좋은 편에 속합니다. 그리고 LLM의 고질적인 문제인 Hallucination을 줄이고, 훈련 데이터에 없는 정보를 추가할 수 있다는 장점 때문에 널리 쓰이고 있습니다.
그럼 RAG를 사용하는 실제 사례는 어떤 것들이 있을까요?
최신 정보에 기반한 질의응답
LLM은 태생적으로 과거의 정보만 가지고 있습니다. LLM 훈련 데이터를 만든 시점까지 데이터만 가지고 있죠. 예를 들어 GPT-3.5는 2022년 1월, GPT-4는 2023년 4월 시점에 훈련 데이터를 끊었습니다. 즉, GPT-4에게 2024년 4월 유튜브 조회수 1위를 몰어봐도 답을 못 합니다.
하지만 RAG를 사용해서 최신 유튜브 정보를 넣어주면 이야기가 달라집니다. GPT는 Retrieval를 통해 받은 추가 정보를 사용해 정확한 답을 할 수 있게 됩니다.
특수한 정보에 기반한 질의응답
앞에 예시로 사용한 우리 부서원들의 키 정보처럼 LLM 훈련 데이터에 포함되기 어려운 특수한 데이터들도 있습니다.
제가 우리 회사 인사 제도에 대한 질의응답을 해주는 AI를 만들다고 생각해 보겠습니다. LLM은 당연히 우리 회사의 인사 제도에 대해 모릅니다. 그래서 "1년 복지 포인트가 얼마냐?"가 물어보면 모른다고 하거나 심지어는 거짓말을 할 겁니다.
이를 해결하기 위해서 우리 회사 인사 제도에 대한 데이터를 넣고 LLM을 파인튜닝 시킬 수도 있습니다. 하지만 이렇게 하면 인사 규정이 바뀔 때마다 LLM을 다시 훈련시켜야 합니다.
더 나은 방법은 RAG를 사용하는 것입니다. "1년 복지 포인트가 얼마냐?"는 질문이 들어오면 Neural Retrieval을 사용해 복지 포인트와 관련된 문서를 찾고, LLM에게 이 정보를 기반해서 답을 만들라고 합니다. LLM을 매번 다시 훈련시킬 필요도 없고, LLM이 거짓말을 할 가능성도 줄어듭니다.
'Deep Learning' 카테고리의 다른 글
LLM : Token (2) | 2024.06.10 |
---|---|
LLM : Context Window (1) | 2024.05.25 |
LLM : Fine Tuning & LoRA (3) | 2023.11.12 |
Cross Entropy 이야기 (0) | 2023.05.21 |
LLM : In-Context Learning, 남은 이야기들 (12) | 2023.04.12 |