RAG 개선 퀵스타트

RAG 개선 퀵스타트 (Improve RAG Quickstart)

improve_rag 템플릿은 실제 평가 데이터를 사용해서 다양한 RAG 접근 방식을 비교하는 방법을 보여줘요. naive(단일 검색)와 agentic(다단계 검색) RAG 모드를 포함해요. 프로젝트 생성부터 두 모드의 통과율 비교까지 진행할 수 있어요.

출처: 문서

본문

improve_rag 템플릿은 실제 평가 데이터를 사용해서 다양한 RAG 접근 방식을 비교하는 방법을 보여줘요. naive(단일 검색)와 agentic(다단계 검색) RAG 모드를 포함해요.

프로젝트 만들기

# uvx 사용 (설치 불필요)
uvx ragas quickstart improve_rag
cd improve_rag

# 또는 ragas 설치 후
ragas quickstart improve_rag
cd improve_rag

의존성 설치

uv sync

또는 pip으로:

pip install -e .

API 키 설정

export OPENAI_API_KEY="your-openai-key"

평가 실행

Naive RAG 모드 (기본값)

uv run python evals.py

Agentic RAG 모드

uv run python evals.py --agentic

Agentic 모드 요구 사항

Agentic 모드에는 openai-agents 패키지가 필요해요. 다음으로 설치해요.

pip install openai-agents

선택: MLflow 추적

LLM 호출의 상세 추적을 위해 실행 전에 MLflow를 시작해요.

mlflow ui --port 5000

그런 다음 평가를 실행해요. 서버가 실행 중이면 트레이스가 MLflow로 자동 전송돼요.

프로젝트 구조

improve_rag/
├── README.md              # Project documentation
├── pyproject.toml         # Project configuration
├── rag.py                 # RAG implementation (naive & agentic)
├── evals.py               # Evaluation workflow
├── __init__.py            # Python package marker
└── evals/
    ├── datasets/          # Test datasets (hf_doc_qa_eval.csv)
    ├── experiments/       # Evaluation results
    └── logs/              # Evaluation logs

RAG 모드 이해하기

Naive RAG

naive 접근 방식은 단일 검색 단계를 수행해요.

  1. Query → BM25가 top-k 문서 검색
  2. Context → 검색된 문서가 컨텍스트 형성
  3. Generate → LLM이 컨텍스트에서 응답 생성
rag = RAG(llm_client=client, retriever=retriever, mode="naive")
result = await rag.query("What is the Diffusers library?")

장점:

  • 간단하고 빠름
  • 예측 가능한 지연 시간
  • 더 낮은 비용 (단일 LLM 호출)

단점:

  • 다른 용어가 있는 관련 문서를 놓칠 수 있음
  • 쿼리 개선 없음
  • 단일 검색 전략으로 제한

Agentic RAG

agentic 접근 방식은 에이전트가 검색을 제어하게 해요.

  1. Query → 에이전트가 질문 분석
  2. Search → 에이전트가 무엇을 검색할지 결정 (여러 검색 가능)
  3. Refine → 에이전트가 결과에 따라 검색 개선
  4. Generate → 에이전트가 최종 답변 합성
rag = RAG(llm_client=client, retriever=retriever, mode="agentic")
result = await rag.query("What command uploads an ESPnet model?")

장점:

  • 여러 검색 전략 시도 가능
  • 특정 기술 정보를 찾는 데 더 나음
  • 초기 결과에 따라 검색 적응

단점:

  • 더 높은 지연 시간 (여러 LLM 호출)
  • 더 높은 비용
  • 덜 예측 가능한 동작

평가 데이터셋

템플릿은 HuggingFace 문서에 대한 질문이 있는 hf_doc_qa_eval.csv를 포함해요.

Field Description
question HuggingFace 도구에 대한 기술 질문
expected_answer ground truth 답변

예제 질문:

  • "What is the default checkpoint used by the sentiment analysis pipeline?"
  • "What command is used to upload an ESPnet model?"
  • "What is the purpose of the Diffusers library?"

코드 이해하기

RAG 구현 (rag.py)

BM25Retriever

문서 검색에 BM25(Best Matching 25) 알고리즘을 사용해요.

class BM25Retriever:
    def __init__(self, dataset_name="m-ric/huggingface_doc"):
        # HuggingFace 문서 로드
        # 더 나은 검색을 위해 청크로 분할
        # BM25 인덱스 생성

    def retrieve(self, query: str, top_k: int = 3):
        # top-k 가장 관련성 높은 문서 반환
RAG 클래스

두 모드 모두에 대한 통합 인터페이스:

class RAG:
    def __init__(self, llm_client, retriever, mode="naive"):
        self.mode = mode
        if mode == "agentic":
            self._setup_agent()

    async def query(self, question: str, top_k: int = 3):
        if self.mode == "naive":
            return await self._naive_query(question, top_k)
        else:
            return await self._agentic_query(question, top_k)

평가 스크립트 (evals.py)

correctness 메트릭은 모델 응답을 기대 답변과 비교해요.

correctness_metric = DiscreteMetric(
    name="correctness",
    prompt="""Compare the model response to the expected answer...
    Return 'pass' if correct, 'fail' if incorrect.""",
    allowed_values=["pass", "fail"],
)

커스터마이즈

지식 베이스 변경

HuggingFace 문서를 자신의 문서로 교체해요.

class CustomRetriever:
    def __init__(self, documents: list[str]):
        from langchain_community.retrievers import BM25Retriever
        self.retriever = BM25Retriever.from_texts(documents)

    def retrieve(self, query: str, top_k: int = 3):
        self.retriever.k = top_k
        return self.retriever.invoke(query)

다른 모델 사용

evals.py에서 모델을 변경해요.

# 더 나은 정확도를 위해 GPT-4 사용
rag = RAG(llm_client=client, retriever=retriever, model="gpt-4o")

# 또는 다른 프로바이더 사용
from anthropic import Anthropic
client = Anthropic()
# 참고: 비-OpenAI 클라이언트는 rag.py 수정이 필요할 수 있음

커스텀 메트릭 추가

추가 측면을 평가해요.

from ragas.metrics import NumericalMetric

completeness = NumericalMetric(
    name="completeness",
    prompt="""How complete is the response (1-5)?
    Question: {question}
    Expected: {expected_answer}
    Response: {response}
    Score:""",
    allowed_values=(1, 5),
)

# 실험에 추가
result = {
    **row,
    "correctness": correctness_score.value,
    "completeness": completeness.score(...).value,
}

에이전트 동작 수정

rag.py에서 agentic 검색 전략을 커스터마이즈해요.

def _setup_agent(self):
    @function_tool
    def retrieve(query: str) -> str:
        """커스텀 도구 설명..."""
        docs = self.retriever.retrieve(query, self.default_k)
        return "\n\n".join([doc.page_content for doc in docs])

    self._agent = Agent(
        name="Custom RAG Assistant",
        instructions="Your custom instructions...",
        tools=[retrieve]
    )

결과 비교

두 모드를 실행하고 비교해요.

# naive 모드 실행
uv run python evals.py
# 결과 saved to experiments/YYYYMMDD-HHMMSS_naiverag.csv

# agentic 모드 실행
uv run python evals.py --agentic
# 결과 saved to experiments/YYYYMMDD-HHMMSS_agenticrag.csv

결과 분석:

import pandas as pd

naive = pd.read_csv("evals/experiments/..._naiverag.csv")
agentic = pd.read_csv("evals/experiments/..._agenticrag.csv")

print(f"Naive pass rate: {(naive['correctness_score'] == 'pass').mean():.1%}")
print(f"Agentic pass rate: {(agentic['correctness_score'] == 'pass').mean():.1%}")

문제 해결

MLflow 경고

MLflow가 트레이스 실패에 대한 경고를 표시하면 다음 중 하나를 해요.

  1. MLflow 시작: mlflow ui --port 5000
  2. 또는 무시해도 됨 - 추적 없이도 평가는 여전히 작동해요

Agentic 모드가 작동하지 않음

agents 패키지가 있는지 확인해요.

pip install openai-agents

첫 실행이 느림

첫 실행은 HuggingFace 문서 데이터셋(약 300MB)을 다운로드해요. 이후 실행은 캐시된 데이터를 사용해요.

더 알아보기 (Learn more)