RAG 아키텍처의 이해
(참조 자료: Understanding RAG architecture and its fundamentals)
인공지능(AI) 에이전트와 에이전틱 AI. 이 용어들은 혼란스럽습니다. 특히 관련 업계가 아직 이들을 개발하고 배포하는 방법에 대한 합의를 이루지 못한 상황에서는 더욱 그런데요,
이것들은 특히 2023년 이후 IT 업계에서 광범위한 합의를 이룬 검색 증강 생성(RAG) 아키텍처의 경우에는 훨씬 덜 적용됩니다. 검색을 통한 증강 생성은 생성형 AI 모델의 결과가 진실에 기반을 두도록 하는데, 이 방법이 환각 현상을 완전히 방지하지는 못하지만, 기업의 내부 데이터나 검증된 지식 기반의 정보를 바탕으로 관련성 높은 답변을 얻는 것을 목표로 하기 때문입니다.
이를 생성형 AI와 기업용 검색 엔진의 교차점으로 요약할 수 있습니다.
RAG 아키텍처란?
RAG 시스템의 프로세스는 넓은 의미에서는 이해하기 간단한데요, 이는 사용자가 프롬프트(질문 또는 요청)를 전송하는 것으로 시작됩니다. 이 자연어 프롬프트와 연관된 쿼리는 지식 기반의 콘텐츠와 비교되는데, 요청과 가장 유사한 결과가 관련성 순위로 정렬된 후, 전체 프로세스가 LLM(대규모 언어 모델)로 전달되어 최종적인 답변을 생성하고 사용자에게 반환됩니다.
RAG를 도입한 기업들은 해당 접근법의 세부 사항을 파악하게 되었는데, 이는 RAG 메커니즘을 구성하는 다양한 구성 요소 지원부터 시작됩니다. 이러한 구성 요소는 데이터를 소스 시스템에 수집하는 단계부터 LLM을 활용한 응답 생성에 이르기까지 데이터 변환에 필요한 단계들과 연관되어 있습니다.
핵심 프로세스 요약
- 사용자 프롬프트 입력: 자연어 형태의 질문/요청 전송
- 지식 기반 검색: 벡터 임베딩 기반 유사도 분석을 통해 관련 문서 추출
- 관련성 순위 매기기: 코사인 유사도(Cosine Similarity) 등 알고리즘으로 순위 결정
- LLM 기반 답변 생성: 검색된 문서를 컨텍스트로 활용해 정확한 답변 생성
- 최종 출력 반환: 사용자에게 신뢰할 수 있는 응답 제공
주요 구성 요소
- 데이터 수집 파이프라인: 구조화/비구조화 데이터 통합
- 전처리 시스템: 청킹(Chunking), 벡터 임베딩 변환
- 벡터 데이터베이스: FAISS, Pinecone 등 유사도 검색 엔진
- 검색-생성 연동 모듈: LangChain, LlamaIndex 등의 프레임워크 활용
- LLM 통합 계층: GPT, Claude 등 생성 모델과의 인터페이스
이 아키텍처는 기업이 도메인 특화 지식과 LLM의 생성 능력을 결합해 환각(Hallucination)을 줄이고 정확성을 높이는 핵심 메커니즘이라 할 수 있습니다.
데이터 준비, RAG를 사용하더라도 필수적인 요소
RAG 시스템 구축의 첫 단계는 검색하고자 하는 문서를 수집하는 것인데요, 모든 문서를 무작정 수집하고 싶어질 수 있지만, 이는 잘못된 전략입니다. 특히 시스템을 배치(batch)로 업데이트할지, 지속적으로(continuous) 업데이트할지 결정해야 하기 때문입니다.
RAG의 성공여부는 입력 데이터의 품질에서 비롯됩니다. 누군가 ‘문서가 200만 개 있는데, 3주 안에 RAG를 만들어 주세요’라고 말한다면, 당연히 그렇게는 될 수가 없습니다. 머신러닝 맥락에서는 잘 이해됐던 정제(refinement) 개념이 생성형 AI에서는 종종 잊혀지는 경우가 있는데요, 생성형 AI가 모두 초코파이가 되는 건 아닙니다.
LLM은 본질적으로 데이터 준비 도구가 아닙니다. 중복 문서와 중간 버전의 문서를 제거하고, 최신 항목을 선택하는 전략을 적용하는 것이 바람직합니다. 이러한 사전 선택(pre-selection)은 시스템에 불필요한 정보를 과도하게 주입하는 것을 방지하고, 성능 저하도 막을 수 있습니다.
문서가 선정되면, 로우 데이터(HTML 페이지, PDF 문서, 이미지, doc 파일 등)를 사용할 수 있는 형식, 예를 들어 텍스트와 관련 메타데이터가 포함된 JSON 파일 등으로 변환해야 합니다. 이 메타데이터는 데이터의 구조뿐 아니라 작성자, 출처, 생성일 등도 문서화할 수 있는데요, 이렇게 포맷된 데이터는 이후 토큰과 벡터로 변환됩니다.
특히 퍼블리셔들은 대량의 문서와 긴 텍스트를 다룰 때 전체 문서를 벡터화하는 것이 비효율적이라는 사실을 깨달았습니다.
청킹(chunking) 전략
위와 같은 이유로 인해 따라서 “청킹(chunking)” 전략을 구현하는 것이 중요합니다. 청킹은 문서를 짧은 추출물로 분할하는 것을 의미하는데요, Mistral AI에 따르면, 이는 “검색 과정에서 가장 관련성 높은 정보를 식별하고 검색하기 쉽게 만든다”고 합니다.
여기에는 두 가지 고려 사항이 있습니다. 바로 조각의 크기와 그것을 얻는 방식입니다.
청크의 크기는 종종 문자 수나 토큰 수로 표현되는데, 더 많은 청크를 만들면 결과의 정확도가 향상되지만, 벡터가 많아질수록 이를 처리하는 데 필요한 자원과 시간이 증가합니다. 텍스트를 청크로 나누는 방법에는 아래와 같이 여러 가지가 있습니다.
- 첫 번째는 고정 크기 조각(문자, 단어, 토큰 단위)으로 자르는 것입니다. 이 방법은 간단하기 때문에 데이터를 빠르게 탐색해야 하는 데이터 처리 초기 단계에서 인기 있는 선택지입니다.
- 두 번째 접근법은 의미론적 분할, 즉 “자연스러운” 분할입니다. 예를 들어 문장별, 섹션별(HTML 헤더로 정의), 주제별, 단락별로 나누는 것입니다. 구현은 더 복잡하지만 이 방법이 더 정밀한데요, 이는 종종 재귀적 접근에 의존하는데, 공백, 쉼표, 마침표, 헤딩 등 논리적 구분자를 사용하는 것이기 때문입니다.
- 세 번째 접근법은 앞의 두 가지를 결합한 것입니다. 하이브리드 청킹은 매우 정밀한 응답이 필요한 경우, 초기 고정 분할에 의미 기반 방법을 결합합니다. 이러한 기술 외에도, 청크 일부의 내용이 겹칠 수 있다는 점을 고려해 조각을 서로 연결할 수 있습니다.
LLM 플랫폼 Cohere의 문서에 따르면, “오버랩(overlap)은 세그먼트 사이에 항상 여유 공간을 남겨두어, 초기 청킹 전략에 따라 분할되어도 중요한 정보를 포착할 가능성을 높여준다”고 합니다. 다만 이 방법의 단점은 중복성이 발생한다는 점입니다.
가장 널리 사용되는 솔루션은 100200단어의 고정 조각을 유지하면서, 청크 간 내용의 2025%를 오버랩시키는 것입니다. 이러한 분할은 종종 SpaCy나 NLTK 같은 파이썬 라이브러리, 또는 LangChain 프레임워크의 “text splitters” 도구를 사용해 수행됩니다.
적절한 접근법은 일반적으로 사용자가 요구하는 정밀도에 따라 달라집니다. 예를 들어, 법률 문서의 조항처럼 특정 정보를 찾는 것이 목적이라면 의미 기반 분할이 더 적합해 보입니다.
청크의 크기는 임베딩 모델의 용량에 맞아야 하는데요, 바로 이것이 청킹이 처음부터 필요한 이유입니다. Microsoft 문서에 따르면, 이는 “임베딩 모델의 입력 토큰 한도를 초과하지 않게 해준다”고 설명하고 있습니다. 예를 들어, Azure OpenAI text-embedding-ada-002 모델의 입력 텍스트 최대 길이는 8,191 토큰입니다. 현재 OpenAI 모델에서 토큰 하나는 평균 약 네 글자에 해당하므로, 이 최대 한도는 약 6,000단어에 해당됩니다.
벡터화 및 임베딩 모델
임베딩 모델은 청크나 문서를 벡터로 변환하는 역할을 합니다. 이 벡터들은 데이터베이스에 저장되는데요, 여기서도 여러 유형의 임베딩 모델이 있는데, 주로 밀집(dense) 모델과 희소(sparse) 모델이 있습니다.
밀집 모델은 일반적으로 고정 크기의 벡터를 생성하며, x개의 차원으로 표현됩니다. 후자는 입력 텍스트의 길이에 따라 크기가 달라지는 벡터를 생성합니다. 세 번째 접근법은 이 둘을 결합하여 짧은 추출물이나 코멘트를 벡터화합니다(Splade, ColBERT, IBM sparse-embedding-30M 등).
차원 수의 선택은 결과의 정확도와 속도를 결정하는데, 차원이 많은 벡터는 더 많은 맥락과 뉘앙스를 포착할 수 있지만, 생성 및 검색에 더 많은 자원이 필요할 수 있습니다. 차원이 적은 벡터는 정보가 덜 풍부하지만 검색 속도가 더 빠릅니다.
임베딩 모델의 선택은 또한 벡터가 저장될 데이터베이스, 연동될 대형 언어 모델, 그리고 수행할 작업에 따라 달라집니다. MTEB 순위와 같은 벤치마크는 매우 유용합니다. 때로는 동일한 LLM 컬렉션에 속하지 않은 임베딩 모델을 사용할 수도 있지만, 문서 베이스와 사용자 질문을 벡터화할 때는 반드시 같은 임베딩 모델을 사용해야 합니다.
임베딩 모델이 특정 도메인(예: 종양학, 시스템 엔지니어링)과 관련된 언어 지식을 충분히 포함하지 않을 경우, 임베딩 모델을 파인튜닝하는 것이 유용할 수 있다는 점도 참고해야 합니다.
벡터 데이터베이스와 리트리버 알고리즘
벡터 데이터베이스는 단순히 벡터를 저장하는 것 이상의 기능을 수행합니다. 일반적으로 최근접 이웃(nearest-neighbour) 기법을 기반으로 한 의미론적 검색 알고리즘을 통합해 정보를 인덱싱하고 질문에 해당하는 정보를 검색하는데요, 대부분의 업체는 HNSW(Hierarchical Navigable Small Worlds) 알고리즘을 구현했습니다.
마이크로소프트는 정확도를 희생하는 대신 대량의 벡터를 처리할 때 이상적인 성능-비용 비율을 얻기 위해 설계된 오픈소스 알고리즘인 DiskANN으로도 영향력을 행사하고 있고. 구글은 대량 데이터 처리에도 적합한 자체 모델인 ScANN을 개발하기로 선택했습니다. 검색 프로세스는 벡터 그래프의 차원을 탐색하여 가장 가까운 근사 이웃을 찾는 것을 포함하며, 코사인 또는 유클리드 거리 계산을 기반으로 합니다.
코사인 거리는 의미론적 유사성을 식별하는 데 더 효과적인 반면, 유클리드 방식은 더 단순하지만 컴퓨팅 자원 측면에서 덜 부담이 됩니다.
대부분의 데이터베이스가 최근접 이웃에 대한 근사 검색을 기반으로 하기 때문에, 시스템은 답변에 해당할 수 있는 여러 벡터를 반환합니다. 결과 수를 제한하는 것(top-k cutoff)이 가능합니다. 이는 사용자의 쿼리와 답변 생성에 사용되는 정보가 LLM 컨텍스트 창에 맞도록 하기 위해 필요합니다. 그러나 데이터베이스에 매우 많은 수의 벡터가 포함된 경우, 정밀도가 떨어지거나 찾고자 하는 결과가 설정된 한계를 벗어날 수 있습니다.
하이브리드 검색 및 순위 재조정
BM25와 같은 전통적인 검색 모델을 HNSW 유형의 검색기와 결합하는 것은 비용 대비 성능 측면에서 유용할 수 있지만, 반환되는 결과 수가 제한될 수 있습니다. 특히 HNSW 모델과 BM25의 결합(하이브리드 검색으로도 알려짐)을 지원하지 않는 벡터 데이터베이스가 많기 때문입니다.
**리랭커(Reranker)**는 응답에 유용하다고 판단되는 콘텐츠를 더 많이 찾는 데 도움을 줄 수 있습니다. 이는 “검색기” 모델이 반환하는 결과의 제한을 늘리는 것을 포함합니다. 그런 다음 이름에서 알 수 있듯이, 리랭커는 질문과의 관련성에 따라 청크를 재정렬합니다. 리랭커의 예로는 Cohere Rerank, BGE, Janus AI, Elastic Rerank 등이 있습니다. 반면, 이러한 시스템은 사용자에게 반환되는 결과의 지연 시간을 증가시킬 수 있습니다. 또한 문서 기반에서 사용된 용어가 특정 분야에 한정된 경우 이 모델을 재교육해야 할 수 있습니다. 그러나 일부에서는 관련성 점수가 RAG 시스템의 성능을 감독하는 데 유용한 데이터라고 평가합니다.
리랭커 사용 여부와 관계없이, 응답을 LLM에 전송해야 합니다. 여기서도 모든 LLM이 동일하지 않습니다. 컨텍스트 창 크기, 응답 속도, 문서 접근 없이도 사실에 기반한 답변 능력 등은 모두 평가해야 할 기준입니다. 이러한 측면에서 Google DeepMind, OpenAI, Mistral AI, Meta, Anthropic은 이 사용 사례를 지원하기 위해 자체 LLM을 학습해 왔습니다.
평가 및 관찰
리랭커 외에도, LLM을 판정자로 사용하여 결과를 평가하고 응답을 생성해야 하는 LLM의 잠재적인 문제를 식별할 수 있습니다. 일부 API는 대신 규칙에 의존하여 특정 사용자의 유해한 콘텐츠나 기밀 문서 접근 요청을 차단합니다. 의견 수집 프레임워크 또한 RAG 아키텍처를 정교하게 다듬는 데 사용할 수 있습니다. 이 경우, 사용자는 RAG 시스템의 긍정적, 부정적 측면을 식별하기 위해 결과를 평가하도록 초대받습니다. 마지막으로, 비용, 보안, 성능 문제를 피하기 위해 각 구성 요소의 가시성(observability)이 필요합니다.