일반적인 LLM 모델은 학습된 데이터를 기반으로 답변합니다. 하지만 다음과 같은 한계가 있습니다:
학습 데이터의 시점 이후 정보는 알지 못함(지식 단절)
회사 내부 문서나 개인 데이터에 접근할 수 없음
때때로 부정확하거나 만들어낸 정보를 제공할 수 있음(환각)
그럼 모든 정보를 미리 프롬프트에 넣으면 어떨까요? 회사 내부 데이터를 전부 LLM 챗봇에 프롬프트로 제공하는 겁니다. 작동은 하겠지만, 이 경우에도 문제가 있습니다.
최대로 처리할 수 있는 컨텍스트 크기에 한계가 있음.
답변에 필요 없는 정보까지 들어갈 수 있음
비용이 높아짐
RAG는 이러한 문제를 해결하기 위해 연구된 기술입니다. 필요한 정보만 검색하고(지식 단절과 내부 정보 접근성 극복) AI가 그것을 참고하여 답변(환각 줄임)하도록 합니다. 필요한 정보만 사용하니 모든 정보를 넣는 것보다 낫고요.
그럼 RAG는 어떻게 작동하는 걸까요? RAG의 동작 원리를 알기 위해서는 벡터DB와 임베딩에 대해 알아야 합니다.
벡터 DB? 임베딩?
벡터 DB는 임베딩된 데이터를 벡터 형태로 저장, 검색하는 특수한 DB입니다.
다음 두 지식을 분류한다고 생각해 봅시다.
A. 조선의 4대 왕은 세종대왕이다.
B. 미국의 인구는 3억 명이다.
미리 분류 기준을 준비했습니다. 아래 이미지를 보고, A, B가 어느 칸에 들어가면 될지 생각해보세요.
어떤 지식이 어떤 칸에 들어갈까요?
지식 A는 “조선”, “사건”과 관련이 있으므로 1사분면에, 지식 B는 “미국”, “통계”와 관련이 있으므로 3사분면에 들어갔습니다. 이제 두 지식에 대해 묻는 질문이 들어오면, 관련 지식을 찾을 수 있겠죠.
예를 들어, “조선의 4대 왕은 누구야?”라는 질문은 1사분면에 연결될 겁니다. 그럼 같은 1사분면에 있는 지식 A을 “질문과 유사한 지식”이라고 판단해 답변에 활용할 수 있습니다. “미국의 인구수는?”은 3사분면이겠죠.
저희는 지식의 위치를 알아냈고, 질문과 유사한 지식을 찾았습니다.
임베딩은 문서를 벡터로 변환하는 과정입니다. 즉 지식의 위치를 찾는 행위입니다. 임베딩 모델을 사용해 수행합니다.
벡터DB는 문서의 위치(벡터)를 저장하고, 주어진 벡터와 유사도가 가장 높은 벡터들을 탐색하는 데 최적화된 DB입니다.
RAG는 사용자의 질문과 유사한 벡터DB의 지식을 찾고, 응답에 참고하는 기술입니다.
💡
이해를 위해 2차원 표, “위치”나 “사분면”이라는 표현을 사용했지만, 실제 벡터DB는 임베딩된 지식을 [0.258172, 0.418726, 0.412876, 0.512291...] 과 같은 벡터 형태로 저장합니다. 많은 정보를 구분할 수 있도록 차원도 높습니다(OpenAI의 text-3-embedding-large는 기본 3072차원).
또한 예제에서의 “유사함”의 기준은 “같은 사분면에 있는가?”를 사용하였지만, 실제 벡터DB들은 다양한 유사도 측정 방법을 사용합니다. 일반적으로 많이 사용되는 것은 코사인 유사도입니다.
이 세 가지 기술은 다음과 같이 함께 작동합니다.
임베딩으로 문서(지식)를 벡터로 변환
변환된 벡터를 벡터DB에 저장
사용자 질문도 임베딩으로 벡터화
벡터 DB에서 유사한 벡터(관련 문서) 검색
RAG 수행: 검색된 문서를 참고하여 답변 생성
RAG 활용 사례
RAG는 대량의 내부 정보를 참고해야 하는 작업에 사용하기 좋습니다. “내부 정보”란 LLM이 학습하지 않은 데이터를 의미합니다.
고객 지원 챗봇: 회사 FAQ, 매뉴얼을 RAG로 검색하여 정확한 답변 제공
문서 검색 시스템: 대량의 문서에서 관련 정보 빠르게 찾기
코드 검색: 코드베이스에서 관련 함수나 예제 찾기
RAG의 사용 여부
RAG는 분명 강력한 기술입니다. 하지만 데이터의 성격에 따라 RAG 외의 대안이 더 효율적일 수도 있으므로, 항상 작업 전후 성능을 측정하는 것이 중요합니다.
시스템 프롬프트: 오늘 날짜, 항상 필요한 지식 등 간단하고 정적인 정보는 RAG를 통하지 않고 시스템 프롬프트를 통해 직접 처리하는 것이 좋습니다.
캐싱 활용: 최신 LLM은 수십만 토큰에 달하는 긴 컨텍스트 윈도우를 지원합니다. Anthropic은 200,000토큰 이하의 정적인 지식에 대해서는 RAG 대신 전체 데이터를 프롬프트에 포함하고 캐싱을 활성화하는 방식도 추천하고 있습니다.