Ragas로 RAG 기반 질의응답용 합성 테스트 세트 생성하기

Ragas로 RAG 기반 질의응답용 합성 테스트 세트 생성하기 (Generating a Synthetic Test Set for RAG-Based Question Answering with Ragas)

이 튜토리얼에서는 Ragas의 테스트 세트 생성 모듈을 사용해서 RAG(Retrieval-Augmented Generation) 기반 질의응답 봇을 위한 합성 테스트 세트를 만들어요. 목표는 항공편 예약, 변경·취소, 수하물 정책, 예약 조회, 지연, 기내 서비스, 특별 지원 등 다양한 주제의 고객 질문에 답할 수 있는 Ragas Airline Assistant를 설계하는 것이에요.

출처: 문서

본문

이 튜토리얼에서는 Ragas의 테스트 세트 생성 모듈을 탐구해서 RAG 기반 질의응답 봇을 위한 합성 테스트 세트를 만들 거예요. 목표는 다음을 포함한 다양한 주제의 고객 질문에 답할 수 있는 Ragas Airline Assistant를 설계하는 것이에요.

  • 항공편 예약
  • 항공편 변경 및 취소
  • 수하물 정책
  • 예약 조회
  • 항공편 지연
  • 기내 서비스
  • 특별 지원

합성 데이터셋을 가능한 한 현실적이고 다양하게 만들기 위해 다양한 고객 페르소나를 만들 거예요. 각 페르소나는 서로 다른 여행자 유형과 행동을 나타내며, 종합적이고 대표성 있는 테스트 세트를 구축하는 데 도움을 줘요. 이 접근 방식은 RAG 모델의 효과성과 견고성을 철저히 평가할 수 있게 보장해요.

시작해볼게요!

문서 다운로드 및 로드

아래 명령을 실행해서 더미 Ragas Airline 데이터셋을 다운로드하고 LangChain으로 문서를 로드해요.

! git clone https://huggingface.co/datasets/vibrantlabsai/ragas-airline-dataset
from langchain_community.document_loaders import DirectoryLoader

path = "ragas-airline-dataset"
loader = DirectoryLoader(path, glob="**/*.md")
docs = loader.load()

LLM 및 임베딩 모델 설정

from ragas.llms import LangchainLLMWrapper
from ragas.embeddings import OpenAIEmbeddings
from langchain_openai import ChatOpenAI
import openai

generator_llm = LangchainLLMWrapper(ChatOpenAI(model="gpt-4o-mini"))
openai_client = openai.OpenAI()
generator_embeddings = OpenAIEmbeddings(client=openai_client, model="text-embedding-3-small")

Knowledge Graph 만들기

문서로 기본 knowledge graph를 만들어요.

from ragas.testset.graph import KnowledgeGraph
from ragas.testset.graph import Node, NodeType

kg = KnowledgeGraph()

for doc in docs:
    kg.nodes.append(
        Node(
            type=NodeType.DOCUMENT,
            properties={"page_content": doc.page_content, "document_metadata": doc.metadata}
        )
    )

kg

출력

KnowledgeGraph(nodes: 8, relationships: 0)

Transform 설정

이 튜토리얼에서는 노드로만 구성된 knowledge graph를 사용해 Single Hop Query 데이터셋을 만들어요. 그래프를 강화하고 쿼리 생성을 개선하기 위해 세 가지 핵심 transform을 적용해요.

  • Headline 추출: 언어 모델로 각 문서에서 명확한 섹션 제목을 추출해요 (예: flight cancellations.md에서 "Airline Initiated Cancellations"). 이 제목들은 특정 주제를 분리하고 집중된 질문 생성에 직접적인 컨텍스트를 제공해요.
  • Headline 분할: 추출된 headline을 기반으로 문서를 관리 가능한 하위 섹션으로 나눠요. 이는 노드 수를 늘리고 더 세분화되고 컨텍스트 특화된 쿼리 생성을 보장해요.
  • Keyphrase 추출: 핵심 주제 키프레이즈(예: 주요 좌석 정보)를 식별해서 의미적 시드 포인트로 사용하며, 생성되는 쿼리의 다양성과 관련성을 풍부하게 해요.
from ragas.testset.transforms import apply_transforms
from ragas.testset.transforms import HeadlinesExtractor, HeadlineSplitter, KeyphrasesExtractor

headline_extractor = HeadlinesExtractor(llm=generator_llm, max_num=20)
headline_splitter = HeadlineSplitter(max_tokens=1500)
keyphrase_extractor = KeyphrasesExtractor(llm=generator_llm)

transforms = [
    headline_extractor,
    headline_splitter,
    keyphrase_extractor
]

apply_transforms(kg, transforms=transforms)
Applying HeadlinesExtractor: 100%|██████████| 8/8 [00:00<?, ?it/s]
Applying HeadlineSplitter: 100%|██████████| 8/8 [00:00<?, ?it/s]
Applying KeyphrasesExtractor: 100%|██████████| 25/25 [00:00<?, ?it/s]

쿼리 생성을 위한 페르소나 구성

페르소나는 컨텍스트와 관점을 제공해서 생성되는 쿼리가 자연스럽고, 사용자 특화적이며, 다양하도록 보장해요. 쿼리를 다른 사용자 관점에 맞춤으로써 테스트 세트가 광범위한 시나리오를 다루게 돼요.

  • 첫 비행 승객 (First Time Flier): 초보자에게 명확한 지침이 필요한 사람들을 위해 상세하고 단계별 안내를 포함한 쿼리를 생성해요.
  • 단골 승객 (Frequent Flier): 경험이 많은 여행자를 위한 간결하고 효율성 중심의 쿼리를 생성해요.
  • 화난 비즈니스석 승객 (Angry Business Class Flier): 높은 기대와 즉각적인 해결 요구를 반영하는 비판적이고 긴급한 어조의 쿼리를 생성해요.
from ragas.testset.persona import Persona

persona_first_time_flier = Persona(
    name="First Time Flier",
    role_description="Is flying for the first time and may feel anxious. Needs clear guidance on flight procedures, safety protocols, and what to expect throughout the journey.",
)

persona_frequent_flier = Persona(
    name="Frequent Flier",
    role_description="Travels regularly and values efficiency and comfort. Interested in loyalty programs, express services, and a seamless travel experience.",
)

persona_angry_business_flier = Persona(
    name="Angry Business Class Flier",
    role_description="Demands top-tier service and is easily irritated by any delays or issues. Expects immediate resolutions and is quick to express frustration if standards are not met.",
)

personas = [persona_first_time_flier, persona_frequent_flier, persona_angry_business_flier]

Synthesizer를 사용한 쿼리 생성

Synthesizer는 강화된 노드와 페르소나를 쿼리로 변환하는 역할을 해요. 노드 속성(예: "entities" 또는 "keyphrases")을 선택하고, 페르소나·스타일·쿼리 길이와 짝지은 뒤, LLM을 사용해서 노드 내용을 기반으로 쿼리-답변 쌍을 생성하는 방식으로 이를 달성해요.

SingleHopSpecificQuerySynthesizer의 두 인스턴스를 사용해서 쿼리 분포를 정의해요.

  • Headlines 기반 Synthesizer – 추출된 문서 headline을 사용해서 특정 섹션을 참조하는 구조화된 질문을 생성해요.
  • Keyphrases 기반 Synthesizer – 핵심 개념 주변에 쿼리를 형성해서 더 광범위하고 주제적인 질문을 생성해요.

두 synthesizer는 동일하게 가중치가 부여되어(각각 0.5), 구체적 쿼리와 개념적 쿼리의 균형 잡힌 혼합을 보장하고 궁극적으로 테스트 세트의 다양성을 높여요.

from ragas.testset.synthesizers.single_hop.specific import (
    SingleHopSpecificQuerySynthesizer,
)

query_distibution = [
    (
        SingleHopSpecificQuerySynthesizer(llm=generator_llm, property_name="headlines"),
        0.5,
    ),
    (
        SingleHopSpecificQuerySynthesizer(
            llm=generator_llm, property_name="keyphrases"
        ),
        0.5,
    ),
]

테스트 세트 생성

from ragas.testset import TestsetGenerator

generator = TestsetGenerator(
    llm=generator_llm,
    embedding_model=generator_embeddings,
    knowledge_graph=kg,
    persona_list=personas,
)

이제 테스트 세트를 생성할 수 있어요.

testset = generator.generate(testset_size=10, query_distribution=query_distibution)
testset.to_pandas()
Generating Scenarios: 100%|██████████| 2/2 [00:00<?, ?it/s]
Generating Samples: 100%|██████████| 10/10 [00:00<?, ?it/s]

출력

user_input reference_contexts reference synthesizer_name
0 Wut do I do if my baggage is Delayed, Lost, or... [Baggage Policies\n\nThis section provides a d... If your baggage is delayed, lost, or damaged, ... single_hop_specifc_query_synthesizer
1 Wht asistance is provided by the airline durin... [Flight Delays\n\nFlight delays can be caused ... Depending on the length of the delay, Ragas Ai... single_hop_specifc_query_synthesizer
2 What is Step 1: Check Fare Rules in the contex... [Flight Cancellations\n\nFlight cancellations ... Step 1: Check Fare Rules involves logging into... single_hop_specifc_query_synthesizer
3 How can I access my booking online with Ragas ... [Managing Reservations\n\nManaging your reserv... To access your booking online with Ragas Airli... single_hop_specifc_query_synthesizer
4 What assistance does Ragas Airlines provide fo... [Special Assistance\n\nRagas Airlines provides... Ragas Airlines provides special assistance ser... single_hop_specifc_query_synthesizer
5 What steps should I take if my baggage is dela... [Baggage Policies This section provides a deta... If your baggage is delayed, lost, or damaged w... single_hop_specifc_query_synthesizer
6 How can I resubmit the claim for my baggage is... [Potential Issues and Resolutions for Baggage ... To resubmit the claim for your baggage issue, ... single_hop_specifc_query_synthesizer
7 Wut are the main causes of flight delays and h... [Flight Delays Flight delays can be caused by ... Flight delays can be caused by weather conditi... single_hop_specifc_query_synthesizer
8 How can I request reimbursement for additional... [2. Additional Expenses Incurred Due to Delay ... To request reimbursement for additional expens... single_hop_specifc_query_synthesizer
9 What are passenger-initiated cancelations? [Flight Cancellations Flight cancellations can... Passenger-initiated cancellations occur when a... single_hop_specifc_query_synthesizer

마무리 (Final Thoughts)

이 튜토리얼에서는 주로 single-hop 쿼리에 초점을 맞춰 Ragas 라이브러리로 테스트 세트 생성을 탐구했어요. 다음 튜토리얼에서는 multi-hop 쿼리를 다루면서 더 풍부한 테스트 세트 시나리오를 위해 이러한 개념을 확장할 거예요.