테마 전환

RAG 시스템 최적화 실전: 검색 정확도와 생성 품질의 균형

Easton editorial illustration: multi-tenant AI service platform

사용자가 “비밀번호를 재설정하려면 어떻게 하나요?”라고 물었는데 시스템이 “비밀번호 복잡성 요구 사항”과 “계정 보안 설정”을 반환한다면 전형적인 RAG 검색 오류입니다. 원인은 의미적 간극에 있습니다. 사용자의 구어체 표현인 “비밀번호 재설정”과 문서의 공식 표현인 “비밀번호 초기화 절차”가 달라 벡터 모델이 연관성을 찾지 못하는 것입니다. RAG 시스템에는 세 가지 주요 병목이 있습니다. 의미적 간극(사용자 구어체 vs 문서 용어), 정확 일치의 약점(벡터는 의미에는 강하지만 키워드 일치에는 약함), 컨텍스트 단절(청킹이 완전한 정보를 끊음)입니다.

Query 재작성은 검색 정확도를 15%-25% 높이고, Hybrid Search(BM25 + 벡터 + RRF)는 재현율을 30%-50% 높이며, 의미 기반 청킹은 고정 청킹보다 정확도가 11%포인트 높습니다. 이 글에서는 Query 처리, 하이브리드 검색, 재순위화, 청킹 전략, 평가 피드백 루프의 다섯 단계를 체계적으로 살펴보고 정확도와 지연 시간의 균형을 맞추는 의사결정 프레임워크를 제시합니다.

1. RAG 시스템의 세 가지 주요 병목

조정을 시작하기 전에 우리가 정확히 어떤 문제와 씨름하고 있는지부터 이야기해 보겠습니다. 많은 경우 처음부터 Embedding 모델을 조정하거나 벡터 데이터베이스를 바꾸지만 결과는 기대만큼 좋지 않습니다. RAG 시스템의 문제는 대개 한 단계만의 잘못이 아니라 여러 단계의 문제가 겹친 결과이기 때문입니다.

의미적 간극: 사용자와 문서가 서로 다른 방식으로 말한다

이 문제는 아마 RAG 시스템에서 가장 골치 아픈 문제일 것입니다.

사용자는 “시스템이 죽으면 어떻게 해야 하나요?”라고 묻지만 지식 베이스에는 “서비스 이상 복구 절차”라고 적혀 있습니다. 의미상 두 문장은 분명 관련이 있지만 벡터 모델이 그 연관성을 찾지 못할 수 있습니다. 사용자는 구어체 표현을 선호하는 반면 문서는 대체로 더 공식적이고 전문적으로 작성되기 때문입니다.

예전에 한 금융 회사의 지식 베이스 Q&A를 구축할 때 사용자가 “신용카드가 정지됐는데 어떻게 해야 해요?”라고 물었지만 시스템은 “신용카드 분실 신고 절차”를 반환한 적이 있습니다. 사용자가 화를 낼 만했습니다. 정지를 해제하고 싶은데 분실 신고를 안내했으니까요. 나중에 Query 재작성을 도입해 “정지됨”을 “계정 정지 처리”에 매핑하자 재현율이 곧바로 상당히 개선됐습니다.

이 문제의 본질은 사용자의 질문 표현과 문서의 표현 사이에 의미적 간극이 존재한다는 것입니다. Embedding 모델은 의미 이해 능력이 뛰어나지만 사람의 마음을 읽지는 못합니다. 기존 학습 데이터를 바탕으로 유사도를 계산할 뿐입니다.

정확 일치: 벡터 검색의 약점

벡터 검색은 의미적 유사도에는 강하지만 정확한 일치가 필요한 상황에서는 힘을 쓰지 못할 때가 있습니다.

예를 들어 사용자가 “2024년 Q3 매출은 얼마인가요?”라고 물었고 문서에 “2024년 3분기 매출은 3억 2천만 위안에 달했다”라고 적혀 있다면, “Q3”와 “3분기”는 의미가 비슷하므로 벡터 검색이 이를 찾을 수 있습니다. 하지만 사용자가 “매출이 가장 높은 분기”를 묻는다면 벡터 검색은 난감해집니다. 이는 의미적 유사도의 문제가 아니라 데이터를 계산하고 비교해야 하는 문제이기 때문입니다.

더 알아차리기 어려운 경우도 있습니다. 바로 전문 용어의 정확한 일치입니다. 예를 들어 “OAuth 2.0”과 “OAuth 1.0”은 벡터 공간에서 가까울 수 있지만 실제로는 완전히 다른 프로토콜 버전입니다. 검색 결과가 섞여 반환되면 사용자는 잘못된 정보를 받게 됩니다.

Tencent Cloud 개발자 커뮤니티의 2026년 기술 보고서에 따르면 전문 분야에서 단일 벡터 검색의 평균 정확도는 60%-70%에 불과하지만, 키워드 검색을 결합하면 80% 이상에 도달할 수 있습니다. 솔직히 이 차이는 상당히 큽니다.

컨텍스트 단절: 청킹이 의미를 끊는다

이 문제는 책 한 권을 조각조각 찢은 뒤 다시 맞추는 것과 비슷합니다. 어떤 조각은 맞지만 어떤 조각은 아무리 해도 맞지 않습니다.

고정 청킹은 가장 간단한 방법이지만 문제도 가장 분명합니다. 예를 들어 코드 한 부분에서 함수 시그니처는 한 청크에, 함수 본문은 다른 청크에 들어갈 수 있습니다. 검색할 때 시그니처만 반환되고 구현 로직이 빠지면 사용자는 한참을 봐도 이 함수를 어떻게 사용해야 할지 알 수 없습니다.

62%
고정 청킹 정확도
500 token 고정 분할
73%
의미 기반 청킹 정확도
문단 경계에 따라 분할
11%
정확도 차이
단일 변수 비교
Source: 실측 데이터

제가 실제로 같은 기술 문서를 테스트한 결과, 500 token 단위의 고정 청킹에서는 검색 정확도가 62%였지만 문단과 섹션 경계에 따른 의미 기반 청킹으로 바꾸자 73%에 도달했습니다. 11%포인트 차이이며, 이것도 단일 변수만 비교한 결과입니다.

더 복잡한 점은 어떤 정보는 본래 여러 문단에 걸쳐 있다는 것입니다. 예를 들어 “이 방안의 단점은…”이라는 문장이 첫 번째 문단에 있고 구체적인 단점은 두 번째 문단에 적혀 있을 수 있습니다. 첫 번째 문단만 검색되면 모델은 “이 방안에는 단점이 있다”고 말할 뿐, 구체적인 단점이 무엇인지는 설명하지 못합니다. 전형적인 정보 단절입니다.

문제를 길게 이야기한 이유는 의욕을 꺾으려는 것이 아니라 조정에 앞서 병목이 어디에 있는지 분명히 파악해야 하기 때문입니다. 의사가 진료할 때 먼저 진단하고 처방하는 것과 같습니다.

2. Query 처리: 입력이 품질의 하한선을 결정한다

사용자가 던지는 질문은 매우 다양하지만 RAG 시스템의 검색 출발점은 하나뿐입니다. 바로 원본 Query입니다. 이 단계를 제대로 처리하지 못하면 이후에 아무리 조정해도 노력에 비해 효과가 작습니다.

사용자가 무엇을 묻는지 먼저 파악하기

사용자의 질문은 의외로 모호한 경우가 많습니다. 예를 들어 “이거 어떻게 써요?”라는 질문은 컨텍스트가 없으면 “이거”가 무엇을 가리키는지 알 수 없습니다. 하지만 지식 베이스 Q&A 시스템이라면 사용자의 이전 대화나 현재 페이지의 컨텍스트에서 의미를 추론할 수 있습니다.

실용적인 방법은 의도를 구조적으로 이해하는 것입니다. 사용자의 질문을 몇 가지 차원으로 나눕니다.

  • 핵심 의도: 사용자가 정확히 무엇을 알고 싶어 하는가? (기능 판단, 구성 요소 확인, 사용 방법, 문제 해결)
  • 관련 엔터티: 질문에 어떤 구체적인 대상이 등장하는가? (제품명, 버전 번호, 시간 범위)
  • 암묵적 조건: 활용할 수 있는 컨텍스트가 있는가? (사용자 역할, 운영 환경)

예를 들어 사용자가 “비밀번호 재설정에 실패하면 어떻게 하나요?”라고 묻는다면 구조화된 결과는 다음과 같습니다.

  • 핵심 의도: 문제 해결
  • 관련 엔터티: 비밀번호 재설정
  • 암묵적 조건: 사용자가 이미 비밀번호 재설정을 시도함

이렇게 재작성한 Query는 원본 질문보다 훨씬 정확합니다.

질문에 태그 붙이기

의도 분류는 새로운 기술이 아니지만 RAG 시스템에서는 특히 유용합니다.

“계정 문제”, “결제 문제”, “기술 장애”, “기능 문의” 같은 의도 태그를 미리 정의할 수 있습니다. 사용자가 질문하면 작은 분류 모델이나 LLM으로 태그를 먼저 붙인 뒤 해당 문서 하위 집합에서만 검색합니다.

이 방법의 장점은 검색 범위를 줄이고 노이즈를 낮춘다는 것입니다. VectorHub의 기술 블로그에 따르면 의도 사전 분류를 추가했을 때 검색 정확도가 평균 15%-25% 높아졌습니다. 제 테스트에서도 약 20% 정도로 비슷하게 개선됐습니다.

LangChain의 RunnableLambda를 사용하면 구현도 어렵지 않습니다.

from langchain_core.runnables import RunnableLambda

def classify_intent(query: str) -> str:
    # 간단한 예시: 키워드 일치
    if "密码" in query or "登录" in query:
        return "账户问题"
    elif "支付" in query or "退款" in query:
        return "支付问题"
    # ...추가 규칙
    return "通用咨询"

# 검색 체인에 결합
intent_chain = RunnableLambda(classify_intent)

물론 키워드 일치는 가장 단순한 방법입니다. 실제 프로젝트에서는 LLM으로 의도를 식별해 더 높은 정확도를 얻을 수 있지만 비용도 증가합니다.

Query 재작성 템플릿

마지막 방법은 Query 재작성입니다. 쉽게 말해 사용자의 구어체 표현을 문서의 “언어 스타일”로 바꾸는 것입니다.

질문 유형별 재작성 템플릿을 준비해 표준화할 수 있습니다. 예를 들면 다음과 같습니다.

원본 질문재작성 결과
이거 어떻게 써요?[제품명]의 사용 방법과 운영 단계
왜 오류가 발생했나요?[오류 정보]의 원인 분석과 해결 방법
더 빠른 방법이 있나요?[기능명]의 빠른 작업 방법

템플릿은 유지 관리가 쉽지만 사람이 설계하고 지속적으로 개선해야 한다는 단점이 있습니다. 도메인이 비교적 고정되어 있다면 템플릿 기반 재작성에 투자할 가치가 큽니다. 오픈 도메인 Q&A라면 LLM으로 실시간 재작성해야 하며, 효과는 더 좋지만 지연 시간과 비용도 증가합니다.

3. 하이브리드 검색 + 재순위화: 검색 정확도의 중요한 도약

Query 처리가 “입력 단계”의 작업이라면 하이브리드 검색은 “검색 단계”의 강력한 조합입니다. 2026년 현재 Hybrid Search는 엔터프라이즈 RAG 시스템의 표준 구성이 됐습니다.

단일 검색만으로 부족한 이유

순수 벡터 검색은 의미적 유사도에 강하지만 키워드의 정확한 일치에는 평범한 성능을 보입니다. 순수 키워드 검색(BM25)은 정확 일치에 강하지만 의미를 이해하지 못합니다. 둘 다 약점이 있지만 결합하면 서로를 보완할 수 있습니다.

비유하자면 벡터 검색은 “맥락을 이해하는 독자”와 같습니다. “사과”와 “과일”이 관련 있다는 것을 알고, “이 방안에는 결함이 있다”와 “이 방안에는 문제가 있다”가 의미상 비슷하다는 것도 이해합니다. 반면 BM25는 “문자 그대로 읽는 독자”와 같습니다. “OAuth 2.0”은 정확히 “OAuth 2.0”이며, “OAuth 1.0”은 다른 것입니다.

Hybrid Search는 두 방식을 결합합니다. 각각 검색한 다음 결과를 융합해 의미와 정확 일치라는 두 요구를 모두 충족합니다.

3단계 아키텍처: BM25 → 벡터 → 재순위화

성숙한 Hybrid Search 아키텍처는 보통 세 단계로 구성됩니다.

1단계: BM25 키워드 검색
키워드가 포함된 문서를 빠르게 검색합니다. 속도는 매우 빠르지만 결과가 충분히 정확하지 않을 수 있습니다. 이 단계는 주로 “넓은 검색”을 맡아 관련 가능성이 있는 문서를 모두 가져옵니다.

2단계: 벡터 의미 검색
Embedding 모델로 의미를 매칭해 의미상 비슷한 문서를 검색합니다. BM25가 놓친, 의미는 관련 있지만 키워드가 일치하지 않는 문서를 보충합니다.

3단계: Cross-Encoder 재순위화
앞의 두 단계에서 얻은 후보 문서를 한데 모아 Cross-Encoder 모델로 정밀하게 정렬합니다. Cross-Encoder는 Query와 각 후보 문서를 함께 처리해 정확한 관련성 점수를 계산합니다.

이 3단계 아키텍처의 효과는 데이터로도 확인됩니다. Dasroot 블로그의 실측 결과에 따르면 Hybrid Search + RRF + Rerank는 재현율을 30%-50% 높일 수 있습니다. 단일 벡터 검색과 비교하면 상당한 개선입니다.

RRF 융합 알고리즘

두 검색 결과는 어떻게 합칠까요? 가장 많이 사용하는 방법은 RRF(Reciprocal Rank Fusion) 알고리즘입니다.

RRF의 핵심 아이디어는 간단합니다. 각 문서가 서로 다른 검색 결과에서 차지한 순위를 점수로 변환한 뒤 합산합니다. 순위가 높으면 점수가 높고, 순위가 낮으면 점수가 낮습니다. 공식은 다음과 같습니다.

RRF_score = 1/(k + rank_BM25) + 1/(k + rank_vector)

k는 보통 60으로 설정합니다. 이 매개변수는 한쪽 순위가 최종 결과에 지나치게 큰 영향을 미치는 것을 방지합니다.

실제 구현에서는 LangChain이 이미 이를 제공합니다.

from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
from langchain_community.vectorstores import FAISS

# 두 검색기 초기화
bm25_retriever = BM25Retriever.from_documents(documents)
vector_retriever = FAISS.from_documents(documents, embeddings).as_retriever()

# 하이브리드 검색기로 결합
ensemble_retriever = EnsembleRetriever(
    retrievers=[bm25_retriever, vector_retriever],
    weights=[0.4, 0.6]  # BM25 가중치 40%, 벡터 가중치 60%
)

가중치는 데이터 특성에 따라 조정할 수 있습니다. 기술 규격이나 법률 조항처럼 문서의 키워드가 명확하다면 BM25의 가중치를 높일 수 있습니다. FAQ나 토론 게시물처럼 의미 표현이 다양하다면 벡터 가중치를 높일 수 있습니다.

Cross-Encoder 재순위화의 트레이드오프

Cross-Encoder의 정확도는 확실히 Bi-Encoder보다 높습니다. Medium의 기술 분석 보고서에 따르면 재순위화는 정확도를 추가로 2% 높일 수 있습니다. 하지만 Cross-Encoder는 각 후보 문서를 별도로 계산해야 하므로 약 100ms의 지연이 추가됩니다.

이 선택은 사용 환경에 따라 달라집니다. 사용자가 300-500ms의 응답 지연을 받아들일 수 있다면, 예를 들어 전문 상담 환경이라면 Cross-Encoder 재순위화를 추가할 가치가 있습니다. 실시간 고객 지원처럼 극도의 속도가 중요하다면 재순위화를 포기하고 Hybrid Search만 사용해야 할 수도 있습니다.

제안하자면 먼저 Hybrid Search(BM25 + 벡터 + RRF)를 실행해 재현율과 응답 시간을 측정하세요. 재현율이 여전히 부족할 때 Cross-Encoder를 추가하는 편이 좋습니다. 처음부터 모든 조정을 한꺼번에 넣으면 각 조정 항목이 실제로 얼마나 기여했는지 판단하기 어렵습니다.

4. 청킹 전략과 메타데이터 필터링

앞에서는 검색 계층의 문제를 다뤘습니다. 이제 문서를 어떻게 나누고 어떤 태그를 붙일지 살펴보겠습니다. 좋은 청킹 전략은 적은 노력으로 검색 효과를 크게 높이지만, 나쁜 청킹 전략은 완전한 정보를 산산조각 냅니다.

의미 기반 청킹 vs 고정 청킹

고정 청킹은 가장 구현하기 쉬운 방법입니다. 내용에 상관없이 N token마다 나눕니다. 구현은 간단하지만 완전한 정보가 두 개 이상의 청크로 잘릴 수 있다는 문제가 분명합니다.

의미 기반 청킹은 조금 더 영리합니다. 문단 끝, 섹션 전환, 코드 블록 종료 등 콘텐츠의 자연스러운 경계에 따라 나눕니다. 이렇게 나눈 각 청크는 비교적 완결된 의미 단위가 됩니다.

LangChain은 의미 기반 청킹을 위한 RecursiveCharacterTextSplitter를 제공합니다.

from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=800,           # 청크당 최대 800 token
    chunk_overlap=150,        # 150 token 오버랩
    separators=["\n\n", "\n", ". ", " ", ""]
    # 먼저 빈 줄로 나누고(문단), 다음으로 줄바꿈(문장), 마지막으로 공백(단어) 순서로 나눔
)

CSDN의 실전 사례에는 같은 기술 문서에서 고정 청킹의 검색 정확도는 62%, 의미 기반 청킹은 73%였다는 비교 데이터가 있습니다. 11%포인트 차이는 특별히 커 보이지 않을 수 있지만 대규모 애플리케이션에서는 사용자 만족도의 차이로 누적됩니다.

오버랩 전략

오버랩은 정보 단절을 막는 안전장치입니다.

연속된 두 콘텐츠가 다음과 같다고 가정해 보겠습니다.

  • 첫 번째 청크: ”…사용자는 다음 단계에 따라”
  • 두 번째 청크: “비밀번호 재설정을 완료합니다. 1. 로그인 페이지를 클릭…”

오버랩이 없으면 “비밀번호 재설정 단계”를 검색했을 때 두 번째 청크만 반환될 수 있습니다. 사용자는 “사용자는 다음 단계에 따라”라는 시작 부분을 보지 못해 정보가 불완전하다고 느낄 수 있습니다.

오버랩을 추가하면 첫 번째 청크의 끝과 두 번째 청크의 시작에 일부 콘텐츠가 반복됩니다. 따라서 어느 청크가 검색되더라도 비교적 완전한 정보를 얻을 수 있습니다.

CSDN의 실측 데이터에 따르면 150-200 token 오버랩은 재현율을 25% 높일 수 있습니다. 제 테스트에서도 비슷한 결과가 나왔습니다. 다만 오버랩이 너무 크면 저장 비용과 검색 노이즈가 증가하므로 균형을 맞춰야 합니다.

메타데이터 필터링: 검색 범위 줄이기

청킹 외에도 메타데이터는 검색 효율을 높이는 중요한 수단입니다.

각 문서 청크에 문서 출처, 작성 시간, 소속 카테고리, 작성자 등의 메타데이터를 추가할 수 있습니다. 검색할 때 먼저 메타데이터로 사전 필터링해 조건에 맞지 않는 문서를 제외한 다음, 남은 문서에서 벡터 매칭을 수행합니다.

예를 들어 사용자가 “2024년 비용 정산 절차”를 묻고 모든 문서에 “연도” 메타데이터가 있다면, 먼저 연도=2024인 문서를 필터링한 뒤 그 안에서 “비용 정산 절차”를 검색할 수 있습니다. 검색 범위를 줄이는 동시에 노이즈도 낮출 수 있습니다.

구현도 간단합니다.

# 벡터 데이터베이스가 메타데이터 필터링을 지원한다고 가정
results = vectorstore.similarity_search(
    query="报销流程",
    filter={"year": 2024, "category": "财务制度"}
)

메타데이터 필터링의 효과는 데이터 구조에 따라 달라지므로 하나의 수치로 정량화하기 어렵습니다. 하지만 문서 분류가 명확하고 시간 범위가 넓다면 메타데이터 필터링은 검색 속도뿐 아니라 결과 품질도 눈에 띄게 개선합니다.

5. 생성 처리와 평가 피드백 루프

앞의 네 개 섹션에서는 검색을 다뤘습니다. 마지막으로 생성과 평가를 살펴보겠습니다. RAG 시스템은 검색만 정확하다고 좋은 것이 아닙니다. 생성 품질도 똑같이 중요하며, 두 부분은 함께 조정해야 할 때가 많습니다.

검색 결과를 모델에 전달하는 방법

검색한 문서를 한꺼번에 LLM에 넣어서는 안 됩니다. 모델에는 컨텍스트 길이 제한이 있으며, 문서를 너무 많이 넣으면 token을 낭비할 뿐 아니라 노이즈까지 유입될 수 있습니다.

실용적인 전략은 컨텍스트 융합입니다. 검색된 여러 문서 청크를 그대로 이어 붙이지 않고 먼저 정리합니다.

구체적인 방법은 다음과 같습니다.

  • 문단 유사도 클러스터링: 의미가 비슷한 문단을 합쳐 중복 정보 줄이기
  • NER 엔터티 추출: 문서의 중요한 엔터티(인명, 지명, 용어)를 식별하고 해당 엔터티가 포함된 문단 우선 유지하기

이렇게 정리한 컨텍스트는 정보 밀도가 높고 노이즈가 적어 모델의 답변도 더 집중된 형태로 생성됩니다.

슬라이딩 윈도와 중요도 샘플링

문서가 많다면 슬라이딩 윈도 메커니즘도 사용할 수 있습니다. 매번 가장 관련성 높은 N개의 문서 청크만 모델에 전달하되, 이전 라운드의 컨텍스트 일부를 유지해 정보가 “이어지는” 흐름을 만듭니다.

또 다른 방법은 중요도 샘플링입니다. TF-IDF나 BM25로 각 문서 청크의 중요도 점수를 계산해 점수가 높은 문서를 우선 선택합니다. 재순위화와 비슷하지만 검색 단계가 아니라 생성 단계에서 적용한다는 점이 다릅니다.

솔직히 이런 기법의 개선 효과는 검색 조정만큼 크지 않으며 대략 3%-5% 정도입니다. 하지만 시스템이 이미 병목 구간까지 최적화됐다면 이런 미세 조정도 시도할 가치가 있습니다.

정량 평가: Ragas 지표 체계

평가가 없으면 조정은 눈을 감고 하는 것이나 다름없습니다. Ragas는 현재 가장 널리 사용되는 RAG 평가 프레임워크로, 검색과 생성 품질을 측정하는 정량 지표 체계를 제공합니다.

핵심 지표는 네 가지입니다.

지표의미목표값
Faithfulness생성된 답변이 검색 내용에 충실한가≥ 0.80
Context Precision검색 내용의 관련성≥ 0.70
Context Recall검색 내용이 필요한 정보를 포함하는가≥ 0.75
Answer Relevance답변이 사용자의 질문에 응답하는가≥ 0.80

Ragas를 사용하는 코드도 간단합니다.

from ragas import evaluate
from ragas.metrics import faithfulness, context_precision, answer_relevance

# 평가 데이터 세트: question, answer, contexts, ground_truth 포함
results = evaluate(
    dataset=eval_dataset,
    metrics=[faithfulness, context_precision, answer_relevance]
)

평가 결과는 시스템이 어느 차원에서 잘 작동하고 어떤 부분을 개선해야 하는지 명확한 수치로 보여 줍니다. 예를 들어 Faithfulness가 0.65에 불과하다면 생성 단계에 환각 문제가 있다는 뜻입니다. Context Precision이 0.50에 불과하다면 검색 단계에서 가져온 콘텐츠에 노이즈가 너무 많다는 뜻입니다.

정량 지표가 있으면 조정할 방향이 생깁니다. 무작정 시행착오를 반복하지 않고 취약한 부분에 맞춰 조정할 수 있습니다.

평가 피드백 루프 구축

평가는 일회성 작업이 아니라 지속적으로 수행해야 합니다. 다음과 같은 평가 피드백 루프를 구축하세요.

  1. 기준 평가: 시스템 출시 전 테스트 세트로 Ragas를 실행하고 기준 점수 기록
  2. 반복 조정: 조정할 때마다 다시 평가하고 기준과 비교해 효과 확인
  3. 운영 모니터링: 출시 후 사용자 피드백을 정기적으로 샘플링해 수동 또는 자동 평가 수행
  4. 피드백 기반 개선: 평가 결과에서 다음 조정 지점을 찾아 피드백 루프 형성

이 과정은 다소 번거로워 보이지만 RAG 시스템을 지속적으로 개선하는 핵심 메커니즘입니다. 피드백 루프가 없으면 조정은 산발적인 대응에 그칩니다. 피드백 루프가 있으면 조정은 체계적인 반복 개선이 됩니다.

결론

지금까지의 내용을 바탕으로 다양한 환경에서 어떤 전략을 사용해야 하는지 판단할 수 있는 의사결정 프레임워크를 정리해 보겠습니다.

먼저 사용 환경 유형을 판단하세요

지식 베이스가 동적으로 업데이트되나요, 아니면 비교적 안정적인가요? 뉴스나 제품 공지처럼 동적인 지식에는 RAG가 더 적합합니다. 지식 베이스를 업데이트하는 편이 모델을 파인튜닝하는 것보다 유연하기 때문입니다. 법률 조항이나 기술 규격처럼 안정적인 분야라면 모델이 지식을 내재화하도록 파인튜닝을 고려할 수 있습니다.

다음으로 정확도 요구 사항을 확인하세요

사용자가 어느 정도의 응답 시간을 받아들일 수 있나요? 실시간 고객 지원처럼 실시간성이 중요하다면 속도 우선 전략을 선택하세요. Hybrid Search(BM25 + 벡터 + RRF)를 사용하고 Cross-Encoder 재순위화는 추가하지 않습니다. 전문 상담처럼 사용자가 더 정확한 답변을 위해 몇 초 기다릴 수 있다면 Cross-Encoder 재순위화나 다중 검색까지 포함하는 정확도 우선 전략을 선택하세요.

제안: 평가부터 시작하세요

많은 개발자가 처음부터 “조정”하려고 하지만 무엇을 조정해야 하는지는 모릅니다. 먼저 Ragas 평가를 실행해 정량 지표를 얻고 취약한 단계를 찾은 다음 그 부분을 조정할 것을 권합니다.

Context Precision이 낮다면 검색 전략을 조정하고, Faithfulness가 낮다면 생성 단계의 컨텍스트 처리를 조정하세요. 이렇게 해야 목표에 맞는 개선을 할 수 있습니다.

RAG 시스템 최적화는 장기전입니다. 만능 해결책도 없고 명확한 종착점도 없습니다. 하지만 체계적인 접근법과 정량 피드백이 있다면 적어도 각 단계가 어느 방향으로 나아가는지는 알 수 있습니다. 이 글이 시행착오를 줄이는 데 도움이 되기를 바랍니다.

FAQ

RAG 시스템에서 가장 흔한 검색 문제는 무엇인가요?
가장 흔한 문제는 의미적 간극입니다. 사용자는 구어체로 질문하지만 문서는 공식적인 전문 용어를 사용합니다. 예를 들어 사용자가 ‘시스템이 죽으면 어떻게 해야 하나요?’라고 묻는데 문서에는 ‘서비스 이상 복구 절차’라고 적혀 있으면, 의미상 관련이 있어도 표현 차이가 커서 벡터 모델이 연관성을 찾지 못할 수 있습니다.
Hybrid Search가 단일 벡터 검색보다 효과적인 이유는 무엇인가요?
벡터 검색은 의미적 유사도에 강하지만 정확한 키워드 일치에는 약합니다. BM25는 정확한 일치에 강하지만 의미 이해 능력이 없습니다. 둘을 조합하면 서로를 보완할 수 있습니다. BM25가 키워드 기반 문서를 검색하고 벡터 검색이 의미상 관련된 문서를 보충한 다음, RRF로 결과를 융합하면 두 요구를 모두 충족할 수 있습니다. 실측 기준 재현율을 30%-50% 높일 수 있습니다.
청킹 전략은 검색 품질에 얼마나 큰 영향을 주나요?
영향이 상당히 큽니다. 고정 청킹은 완전한 정보를 여러 청크로 나눠 정보 단절을 일으킬 수 있습니다. 실측 데이터에 따르면 같은 문서에서 500 token 고정 청킹의 정확도는 62%, 의미 기반 청킹은 73%로 11%포인트 차이가 났습니다. 또한 150-200 token 오버랩은 재현율을 25% 높일 수 있습니다.
Cross-Encoder 재순위화는 사용할 가치가 있나요?
사용 환경에 따라 다릅니다. Cross-Encoder는 Bi-Encoder보다 정확도가 높고 정확도를 추가로 2% 높일 수 있지만, 약 100ms의 지연이 발생합니다. 사용자가 300-500ms의 응답 시간을 받아들일 수 있는 전문 상담 같은 환경이라면 사용할 가치가 있습니다. 실시간 고객 지원처럼 극도의 속도가 중요하다면 재순위화를 생략하고 Hybrid Search만 사용할 수 있습니다.
Ragas 평가 지표는 어떻게 해석해야 하나요?
핵심은 네 가지 지표입니다. Faithfulness는 검색 내용에 충실한 답변인지 평가하며 목표는 ≥0.80입니다. Context Precision은 검색 내용의 관련성을 평가하며 목표는 ≥0.70입니다. Context Recall은 검색 범위를 평가하며 목표는 ≥0.75입니다. Answer Relevance는 답변의 관련성을 평가하며 목표는 ≥0.80입니다. 낮은 지표에 맞춰 조정하면 됩니다. Precision이 낮으면 검색 전략을, Faithfulness가 낮으면 컨텍스트 처리를 조정합니다.
RAG와 파인튜닝은 어떻게 선택해야 하나요?
지식 베이스의 업데이트 빈도를 기준으로 선택합니다. 뉴스나 제품 공지처럼 동적인 지식에는 RAG가 적합합니다. 지식 베이스를 업데이트하는 편이 모델을 파인튜닝하는 것보다 유연하기 때문입니다. 법률 조항이나 기술 규격처럼 안정적인 분야에는 모델이 지식을 내재화하도록 파인튜닝을 고려할 수 있습니다. 엔터프라이즈 애플리케이션에서는 보통 두 방식을 결합해 RAG로 동적 지식을 처리하고 파인튜닝으로 특정 분야의 스타일에 적응시킵니다.

2분 읽기 · 게시일: 2026년 4월 21일 · 수정일: 2026년 9월 4일

댓글

GitHub로 로그인하여 댓글을 남기세요

Easton BlogEaston Blog