본문으로 건너뛰기

© 2026 Molayo

HN요약2026. 05. 20. 14:07

고급 RAG 파이프라인의 신비 해제

요약

LlamaIndex나 Haystack 같은 프레임워크는 RAG 파이프라인 구축을 용이하게 하지만, 내부 작동 방식의 투명성이 낮다는 단점이 있습니다. 본 문서는 EvaDB 애플리케이션을 통해 고급 RAG 파이프라인의 메커니즘, 한계 및 비용을 심층적으로 조사하여 내부 작동 원리를 밝히는 것을 목표로 합니다.

핵심 포인트

  • RAG는 최신 정보 유지와 출처 추적을 통해 LLM의 환각 현상을 완화할 수 있는 핵심 패러다임입니다.
  • 기존 프레임워크의 높은 추상화 수준은 편리함을 제공하지만, 오류 발생 시 내부 디버깅을 어렵게 만듭니다.
  • RAG 파이프라인은 데이터 웨어하우스, 벡터 검색, 응답 생성의 세 단계로 구성됩니다.
  • 하위 질문 쿼리 엔진과 같은 고급 추상화 기술은 더 복잡한 질문에 대응할 수 있게 합니다.

고급 RAG 파이프라인의 신비 해제

대규모 언어 모델 (LLMs) 기반의 검색 증강 생성 (Retrieval-Augmented Generation, RAG) 파이프라인은 엔드 투 엔드 (end-to-end) 질의응답 시스템을 구축하기 위해 점점 더 인기를 얻고 있습니다. LlamaIndexHaystack과 같은 프레임워크는 RAG 파이프라인을 사용하기 쉽게 만드는 데 상당한 진전을 이루었습니다. 이러한 프레임워크는 고급 RAG 파이프라인을 구축하기 위한 훌륭한 추상화 (abstractions)를 제공하지만, 그 대가로 투명성을 희생합니다. 사용자 관점에서는 특히 오류나 불일치가 발생했을 때 내부에서 어떤 일이 일어나고 있는지 명확하게 알기 어렵습니다.

EvaDB 애플리케이션에서는 종종 불투명하게 남아 있는 메커니즘, 한계 및 비용을 조사함으로써 고급 RAG 파이프라인의 내부 작동 원리를 밝혀낼 것입니다.

<p align="center"> <img width="70%" src="images/intro.png" title="llama working on a laptop to retrieve data" > <br> <b><i>노트북으로 작업 중인 Llama</i> 🙂</b> </p>

빠른 시작 (Quick start)

바로 시작하고 싶다면 다음 명령어를 사용하여 애플리케이션을 실행하세요:

pip install -r requirements.txt

echo OPENAI_API_KEY='yourkey' > .env
...

RAG 개요

검색 증강 생성 (Retrieval-augmented generation, RAG)은 LLM 기반 질의응답을 위한 최첨단 AI 패러다임입니다.
RAG 파이프라인은 일반적으로 다음을 포함합니다:

  1. 데이터 웨어하우스 (Data Warehouse) - 질의응답 작업과 관련된 정보를 포함하는 데이터 소스(예: 문서, 테이블 등)의 집합입니다.

  2. 벡터 검색 (Vector Retrieval) - 질문이 주어지면 질문과 가장 유사한 상위 K개의 데이터 청크 (chunks)를 찾습니다. 이는 벡터 스토어 (예: Faiss)를 사용하여 수행됩니다.

  3. 응답 생성 (Response Generation) - 상위 K개의 가장 유사한 데이터 청크가 주어지면, 대규모 언어 모델 (예: GPT-4)을 사용하여 응답을 생성합니다.

RAG는 기존의 LLM (Large Language Model) 기반 질의응답에 비해 두 가지 핵심적인 장점을 제공합니다:

  1. 최신 정보 (Up-to-date information) - 데이터 웨어하우스 (Data warehouse)를 실시간으로 업데이트할 수 있으므로, 정보가 항상 최신 상태를 유지합니다.

  2. 출처 추적 (Source tracking) - RAG는 명확한 추적 가능성 (Traceability)을 제공하여 사용자가 정보의 출처를 식별할 수 있게 합니다. 이는 정확성 검증 및 LLM의 환각 (Hallucination) 현상을 완화하는 데 매우 중요합니다.

고급 RAG 파이프라인 구축하기

더 복잡한 질문에 답할 수 있도록 하기 위해, LlamaIndex와 같은 최신 AI 프레임워크는 하위 질문 쿼리 엔진 (Sub-question Query Engine)과 같은 더 발전된 추상화 (Abstractions)를 도입했습니다.

이 애플리케이션에서 우리는 하위 질문 쿼리 엔진을 예시로 사용하여 정교한 RAG 파이프라인의 신비를 풀어볼 것입니다. 우리는 하위 질문 쿼리 엔진의 내부 작동 원리를 조사하고, 추상화된 개념들을 핵심 구성 요소로 단순화할 것입니다. 또한 고급 RAG 파이프라인과 관련된 몇 가지 과제들도 살펴볼 것입니다.

설정 (The setup)

데이터 웨어하우스 (Data warehouse)는 질의응답 작업과 관련된 정보를 포함하는 데이터 소스(예: 문서, 테이블 등)의 집합입니다.

이 예제에서는 LlamaIndex의 예시 유스케이스 (illustrative use-case)에서 영감을 받아

우리는 다음과 같은 *검색 방법 (retrieval methods)*을 사용할 수 있습니다:

  1. 벡터 검색 (vector retrieval) - 질문과 데이터 소스가 주어지면, 데이터 소스에서 질문과 가장 유사한 상위 K개 (top-K)의 데이터 청크 (data chunks)를 컨텍스트 (context)로 사용하여 LLM 응답을 생성합니다. 우리는 벡터 검색을 위해 EvaDB의 기성 FAISS 벡터 인덱스 (vector index)를 사용합니다. 하지만 이 개념은 어떤 벡터 인덱스에도 적용 가능합니다.

  2. 요약 검색 (summary retrieval) - 요약 질문과 데이터 소스가 주어지면, 전체 데이터 소스를 컨텍스트 (context)로 사용하여 LLM 응답을 생성합니다.

비법 (The secret sauce)

우리의 핵심 통찰은 고급 RAG 파이프라인의 각 구성 요소가 단일 LLM 호출 (LLM call)에 의해 구동된다는 점입니다. 전체 파이프라인은 정교하게 설계된 프롬프트 템플릿 (prompt templates)을 사용하는 일련의 LLM 호출 과정입니다. 이 프롬프트 템플릿들이 바로 고급 RAG 파이프라인이 복잡한 작업을 수행할 수 있게 만드는 비법 (secret sauce)입니다.

사실, 모든 고급 RAG 파이프라인은 다음과 같은 보편적인 입력 패턴을 따르는 일련의 개별 LLM 호출로 분해될 수 있습니다:

<!-- LLM input = **Prompt Template** + **Context** + **Question** -->

여기서:

  • 프롬프트 템플릿 (Prompt Template) - 특정 작업(예: 하위 질문 생성, 요약)을 위해 큐레이션된 프롬프트 템플릿
  • 컨텍스트 (Context) - 작업을 수행하는 데 사용할 컨텍스트 (예: 상위 K개 가장 유사한 데이터 청크)
  • 질문 (Question) - 답변해야 할 질문

이제, 하위 질문 쿼리 엔진 (Sub-question Query Engine)의 내부 작동 방식을 살펴봄으로써 이 원리를 설명하겠습니다.

하위 질문 쿼리 엔진은 세 가지 작업을 수행해야 합니다:

  1. 하위 질문 생성 (Sub-question generation) - 복잡한 질문이 주어지면, 이를 일련의 하위 질문 세트로 분해하는 동시에 각 하위 질문에 적합한 데이터 소스와 검색 함수 (retrieval function)를 식별합니다.
  2. 벡터/요약 검색 (Vector/Summary Retrieval) - 각 하위 질문에 대해, 선택된 검색 함수를 해당 데이터 소스에 적용하여 관련 정보를 검색합니다.
  3. 응답 집계 (Response Aggregation) - 하위 질문들로부터 얻은 응답들을 하나의 최종 응답으로 집계합니다.

각 작업을 자세히 살펴보겠습니다.

작업 1: 하위 질문 생성 (Sub-question Generation)

우리의 목표는 복잡한 질문을 일련의 하위 질문들로 분해하는 동시에, 각 하위 질문에 적합한 데이터 소스 (Data Source) 및 검색 함수 (Retrieval Function)를 식별하는 것입니다. 예를 들어, *"어느 도시의 인구가 가장 많은가?"*라는 질문은 각 도시에 대해 *"{도시}의 인구는 얼마인가?"*라는 형식의 다섯 가지 하위 질문으로 분해됩니다. 각 하위 질문의 데이터 소스는 해당 도시의 위키 (Wiki)여야 하며, 검색 함수는 벡터 검색 (Vector Retrieval)이어야 합니다.

언뜻 보기에 이는 매우 까다로운 작업처럼 보입니다. 구체적으로, 우리는 다음과 같은 질문에 답해야 합니다:

  1. 어떤 하위 질문을 생성해야 하는지 어떻게 알 수 있는가?
  2. 각 하위 질문에 어떤 데이터 소스를 사용해야 하는지 어떻게 알 수 있는가?
  3. 각 하위 질문에 어떤 검색 함수를 사용해야 하는지 어떻게 알 수 있는가?

놀랍게도, 이 세 가지 질문에 대한 답은 모두 동일합니다. 바로 단 한 번의 LLM 호출 (LLM Call)입니다! 전체 하위 질문 쿼리 엔진은 정교하게 설계된 프롬프트 템플릿 (Prompt Template)을 사용한 단 한 번의 LLM 호출로 구동됩니다. 이 템플릿을 **하위 질문 프롬프트 템플릿 (Sub-question Prompt Template)**이라고 부르겠습니다.

-- 하위 질문 프롬프트 템플릿 (Sub-question Prompt Template) --

"""
...

LLM 호출을 위한 컨텍스트 (Context)는 데이터 소스의 이름들과 시스템에서 사용 가능한 함수들입니다. 질문은 사용자의 질문입니다. LLM은 각각 함수와 데이터 소스가 포함된 하위 질문 리스트를 출력합니다.

세 가지 예시 질문에 대해, LLM은 다음과 같은 출력을 반환합니다:

<details> <summary> LLM 출력 테이블 (LLM output Table) </summary> <table> <thead> <tr> <th>질문 (Question)</th> <th>하위 질문 (Subquestions)</th> <th>검색 방법 (Retrieval method)</th> <th>데이터 소스 (Data Source)</th> </tr> </thead> <tbody> <tr> <td>"시카고의 인구는 얼마인가요?"</td> <td>"시카고의 인구는 얼마인가요?"</td> <td>벡터 검색 (vector retrieval)</td> <td>Chicago</td> </tr> <tr> <td>"애틀랜타의 긍정적인 측면들을 요약해 주세요."</td> <td>"애틀랜타의 긍정적인 측면들을 요약해 주세요."</td> <td>요약 검색 (summary retrieval)</td> <td>Atlanta</td> </tr> <tr> <td rowspan=5>"어느 도시의 인구가 가장 높은가요?"</td> <td>"토론토의 인구는 얼마인가요?"</td> <td>벡터 검색 (vector retrieval)</td> <td>Toronto</td> </tr> <tr> <td>"시카고의 인구는 얼마인가요?"</td> <td>벡터 검색 (vector retrieval)</td> <td>Chicago</td> </tr> <tr> <td>"휴스턴의 인구는 얼마인가요?"</td> <td>벡터 검색 (vector retrieval)</td> <td>Houston</td> </tr> <tr> <td>"보스턴의 인구는 얼마인가요?"</td> <td>벡터 검색 (vector retrieval)</td> <td>Boston</td> </tr> <tr> <td>"애틀랜타의 인구는 얼마인가요?"</td> <td>벡터 검색 (vector retrieval)</td> <td>Atlanta</td> </tr> </tbody> </table> </details>

작업 2: 벡터/요약 검색 (Task 2: Vector/Summary Retrieval)

각 하위 질문에 대해, 우리는 해당 데이터 소스에 대해 선택된 검색 함수를 사용하여 관련 정보를 검색합니다. 예를 들어, 하위 질문인 *"시카고의 인구는 얼마인가요?"*의 경우, Chicago 데이터 소스에 대해 벡터 검색 (vector retrieval)을 사용합니다. 마찬가지로, 하위 질문인 *"애틀랜타의 긍정적인 측면들을 요약해 주세요."*의 경우, Atlanta 데이터 소스에 대해 요약 검색 (summary retrieval)을 사용합니다.

두 검색 방법 모두에 대해, 우리는 동일한 LLM 프롬프트 템플릿 (prompt template)을 사용합니다. 실제로, 우리는 LangchainHub에서 제공하는 대중적인 **RAG 프롬프트 (RAG Prompt)**가 이 단계에서 별도의 설정 없이도 매우 잘 작동한다는 것을 확인했습니다.

-- RAG 프롬프트 템플릿 (RAG Prompt Template) --

"""
...

두 검색 방법(retrieval methods)은 LLM 호출에 사용되는 컨텍스트(context)에서만 차이가 있습니다. 벡터 검색(vector retrieval)의 경우, 서브 질문(sub-question)과 가장 유사한 상위 K개의 데이터 청크(data chunks)를 컨텍스트로 사용합니다. 요약 검색(summary retrieval)의 경우, 전체 데이터 소스(data source)를 컨텍스트로 사용합니다.

작업 3: 응답 집계 (Response Aggregation)

이것은 서브 질문들로부터 얻은 응답들을 하나의 최종 응답으로 집계하는 마지막 단계입니다. 예를 들어, *"어느 도시의 인구가 가장 많습니까?"*라는 질문에 대해, 서브 질문들이 각 도시의 인구를 검색하면 응답 집계 단계에서 인구가 가장 많은 도시를 찾아 반환합니다.
**RAG 프롬프트 (RAG Prompt)**는 이 단계에서도 매우 훌륭하게 작동합니다.

LLM 호출을 위한 컨텍스트는 서브 질문들로부터 얻은 응답 리스트입니다. 질문은 원래의 사용자 질문이며, LLM은 최종 응답을 출력합니다.

종합하기

추상화의 계층을 하나씩 벗겨낸 결과, 우리는 서브 질문 쿼리 엔진(sub-question query engine)을 구동하는 비밀 재료를 발견했습니다. 그것은 바로 서로 다른 프롬프트 템플릿(prompt template), 컨텍스트(context), 그리고 질문을 가진 4가지 유형의 LLM 호출입니다. 이는 우리가 앞서 식별한 보편적인 입력 패턴(universal input pattern)과 완벽하게 일치하며, 처음에 시작했던 복잡한 추상화와는 거리가 멉니다.
요약하자면 다음과 같습니다:

전체 파이프라인이 작동하는 모습을 확인하려면 다음 명령어를 실행하세요:

pip install -r requirements.txt

echo OPENAI_API_KEY='yourkey' > .env
...

다음은 시스템이 *"어느 도시의 인구가 가장 많습니까?"*라는 질문에 답하는 예시입니다.

도전 과제 (Challenges)

이제 고급 RAG 파이프라인의 내부 작동 원리를 파헤쳤으니, 이와 관련된 도전 과제들을 살펴보겠습니다.

  1. 질문 민감도 (Question sensitivity) - 우리가 이러한 시스템에서 관찰한 가장 큰 도전 과제는 질문 민감도입니다. LLM (Large Language Models)은 사용자 질문에 매우 민감하며, 파이프라인은 여러 사용자 질문에 대해 예기치 않게 실패합니다. 우리가 직면했던 몇 가지 실패 사례는 다음과 같습니다:
    • 부정확한 하위 질문 (Incorrect sub-questions) - LLM이 때때로 부정확한 하위 질문을 생성합니다. 예를 들어, *"어느 도시가 가장 많은 기술 기업을 보유하고 있습니까?"*라는 질문이 "토론토의 기술 기업 수는 얼마입니까?", "시카고의 기술 기업 수는 얼마입니까?" 등 대신, *"각 도시의 기술 기업은 무엇입니까?"*라는 질문을 5번(각 도시당 한 번씩) 생성하는 식입니다.
    • 부정확한 검색 함수 (Incorrect retrieval function) - *"애틀랜타와 토론토의 긍정적인 측면을 요약하세요."*라는 질문이 요약 검색 방법 (summary retrieval method) 대신 벡터 검색 함수 (vector retrieval function)를 사용하는 결과를 초래합니다.

우리는 각 질문에 대해 파이프라인이 작동하도록 만들기 위해 프롬프트 엔지니어링 (prompt engineering)에 상당한 노력을 기울여야 했습니다. 이는 견고한 (robust) 시스템을 구축하는 데 있어 중대한 도전 과제입니다.

이러한 동작을 검증하기 위해, 우리는 LlamaIndex의 Sub-question 쿼리 엔진을 사용하여 예제를 구현했습니다. 우리의 관찰 결과와 일치하게, 아래에 표시된 것처럼 시스템은 종종 잘못된 하위 질문을 생성하고 하위 질문에 대해 잘못된 검색 함수를 사용합니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 HN Design Systems의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0