RAG 시스템의 첫 번째 단계는 청크(Chunk) 튜닝입니다. PDF 같은 문서를 벡터 데이터베이스에 넣으려면 문서를 일정한 크기로 쪼개야 하는데, 이때 어떻게 쪼개느냐에 따라 검색 결과가 완전히 달라집니다.
일반적으로는 문장이나 문단 단위로 쪼개는 방법을 사용합니다. 이때 파이썬의 정규표현식이나 nltk
, spacy
와 같은 라이브러리를 활용해 문맥을 유지하며 쪼개는 것이 중요합니다. LLM의 토크나이저를 이용하면 문장을 더욱 정확하게 분리할 수 있습니다.
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 예제 텍스트
text = "RAG는 검색을 통해 얻은 정보로 LLM의 답변을 보강하는 기술입니다. LLM이 최신 정보나 비공개 데이터를 활용할 수 있게 합니다."
# RecursiveCharacterTextSplitter를 사용하여 문장 단위로 분리
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=50, # 청크의 최대 크기
chunk_overlap=10, # 청크 간 겹치는 부분
separators=["\n\n", "\n", ".", " ", ""] # 분리 기준
)
# 텍스트를 청크로 분할
chunks = text_splitter.split_text(text)
for i, chunk in enumerate(chunks):
print(f"--- Chunk {i+1} ---")
print(chunk)
[실행 결과]
--- Chunk 1 ---
RAG는 검색을 통해 얻은 정보로 LLM의 답변을
--- Chunk 2 ---
보강하는 기술입니다. LLM이 최신 정보나 비공개
--- Chunk 3 ---
데이터를 활용할 수 있게 합니다.
위 예제는 LangChain의 RecursiveCharacterTextSplitter
를 사용해 텍스트를 문장과 글자 수를 기준으로 쪼개는 방법을 보여줍니다. RAG 구축 시에는 청크 크기, 겹침(Overlap) 정도, 분리 기준 등을 조절하여 최적의 청크 상태를 찾아야 합니다.
청크를 만들었다면 이제 그 청크를 벡터로 변환하는 임베딩 모델을 선택하고 튜닝해야 합니다.
from transformers import pipeline
# 허깅 페이스의 sentence-transformer 파이프라인 사용
# (실제 환경에서는 별도의 임베딩 모델을 사용합니다)
embedder = pipeline("feature-extraction", model="intfloat/multilingual-e5-large")
# 예제 텍스트
text1 = "고양이는 야행성 동물입니다."
text2 = "고양이는 밤에 활동하는 동물입니다."
text3 = "강아지는 충성심이 강한 동물입니다."
# 텍스트를 벡터로 변환 (임베딩)
vector1 = embedder(text1)
vector2 = embedder(text2)
vector3 = embedder(text3)
# 변환된 벡터 출력
print(f"텍스트 1 임베딩 벡터 차원: {len(vector1[0][0])}")
print(f"텍스트 2 임베딩 벡터 차원: {len(vector2[0][0])}")
print(f"텍스트 3 임베딩 벡터 차원: {len(vector3[0][0])}")
[실행 결과]
텍스트 1 임베딩 벡터 차원: 1024
텍스트 2 임베딩 벡터 차원: 1024
텍스트 3 임베딩 벡터 차원: 1024
위 코드는 huggingface transformers
라이브러리를 사용해 임베딩을 수행하는 예시입니다. 실제 RAG 시스템에서는 LangChain과 같은 프레임워크를 사용해 임베딩 모델을 연동하는 것이 일반적입니다.
임베딩된 데이터로 벡터 데이터베이스를 구축했다면, 이제 사용자 질의에 맞춰 관련 청크를 검색하는 검색(Retriever) 튜닝을 할 차례입니다.
앙상블 리트리버(Ensemble Retriever) 사용: 벡터 유사도 검색과 키워드 검색(BM25)을 결합하는 방법입니다. 키워드 검색은 Elasticsearch
같은 전문 검색 엔진을 활용해 정확도를 높일 수 있습니다.
질의 키워드 추출: 사용자의 질문에서 검색에 필요한 핵심 키워드를 LLM으로 추출하여 검색 엔진에 전달하는 방법입니다.
검색 결과가 나왔더라도, 그 순서가 항상 정확한 것은 아닙니다. 이때 재순위(Reranker) 모델을 사용하여 검색 결과를 다시 정렬해 품질을 높일 수 있습니다.
마지막 단계는 최종 검색 결과를 바탕으로 LLM이 답변을 생성하도록 하는 프롬프트 튜닝입니다.
이상의 단계를 종합하면 RAG 시스템은 다음과 같은 흐름으로 구축할 수 있습니다.
RAG는 단순히 하나의 기술이 아니라 여러 튜닝 과정을 거쳐야 완성되는 복합적인 시스템입니다. 각 단계에서 지속적인 테스트와 튜닝을 통해 최적의 결과를 얻을 수 있습니다.