跳转到内容

使用 Ragas 为基于 RAG 的问答生成合成测试集

概述

在本教程中,我们将探讨 Ragas 中的测试集生成模块,为一个基于检索增强生成 (RAG) 的问答机器人创建一个合成测试集。我们的目标是设计一个 Ragas 航空公司助手,能够回答客户关于各种主题的查询,包括

  • 航班预订
  • 航班变更和取消
  • 行李政策
  • 查看预订
  • 航班延误
  • 机上服务
  • 特殊协助

为了确保我们的合成数据集尽可能真实和多样化,我们将创建不同的客户角色。每个角色将代表不同的旅行者类型和行为,帮助我们构建一个全面且具代表性的测试集。这种方法确保了我们可以彻底评估 RAG 模型的有效性和稳健性。

让我们开始吧!

下载并加载文档

运行以下命令以下载 Ragas 航空公司的虚拟数据集,并使用 LangChain 加载文档。

! git clone https://hugging-face.cn/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")

创建知识图谱

用文档创建一个基础知识图谱

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)

设置转换

在本教程中,我们使用一个仅由节点构建的知识图谱来创建单跳查询数据集。为了增强我们的图谱并改善查询生成,我们应用了三个关键的转换

  • 标题提取: 使用语言模型从每个文档中提取清晰的章节标题(例如,从 flight cancellations.md 中提取“航空公司发起的取消”)。这些标题隔离了特定主题,并为生成有针对性的问题提供了直接的上下文。
  • 标题拆分: 根据提取的标题将文档划分为易于管理的小节。这增加了节点数量,并确保了更细粒度、特定于上下文的查询生成。
  • 关键词提取: 识别核心主题关键词(例如关键座位信息),这些关键词作为语义种子点,丰富了生成查询的多样性和相关性。

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]

为查询生成配置角色

角色提供了上下文和视角,确保生成的查询自然、针对特定用户且多样化。通过根据不同用户视角定制查询,我们的测试集覆盖了广泛的场景

  • 首次乘机者: 生成包含详细、分步指导的查询,以满足需要清晰说明的新手。
  • 常旅客: 为经验丰富的旅行者生成简洁、注重效率的查询。
  • 愤怒的商务舱乘客: 产生带有批评性、紧急语气的查询,以反映高期望和要求立即解决的需求。
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]

使用合成器生成查询

合成器负责将丰富的节点和角色转换为查询。它们通过选择一个节点属性(例如“实体”或“关键词”),将其与角色、风格和查询长度配对,然后使用 LLM 根据节点内容生成查询-答案对来实现这一目标。

使用两个 SingleHopSpecificQuerySynthesizer 实例来定义查询分布

  • 基于标题的合成器 – 使用提取的文档标题生成查询,从而产生引用特定章节的结构化问题。
  • 基于关键词的合成器 – 围绕关键概念构建查询,生成更广泛、主题性的问题。

两种合成器的权重相同(各 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 如果我的行李延误、丢失或... [行李政策\n\n本节提供了一个详...] 如果您的行李延误、丢失或损坏,... single_hop_specifc_query_synthesizer
1 航空公司在...期间提供什么帮助... [航班延误\n\n航班延误可能由...] 根据延误的时长,Ragas 航... single_hop_specifc_query_synthesizer
2 在...的背景下,步骤1:检查票价规则是什么... [航班取消\n\n航班取消可...] 步骤1:检查票价规则包括登录到... single_hop_specifc_query_synthesizer
3 我如何通过 Ragas ...在线访问我的预订... [管理预订\n\n管理您的预订...] 要通过 Ragas 航空公司在线访问您的预订... single_hop_specifc_query_synthesizer
4 Ragas 航空公司为...提供什么协助... [特殊协助\n\nRagas 航空公司提供...] Ragas 航空公司提供特殊协助服务... single_hop_specifc_query_synthesizer
5 如果我的行李延误,我应该采取哪些步骤... [行李政策 本节提供了详细...] 如果您的行李在...时延误、丢失或损坏... single_hop_specifc_query_synthesizer
6 我如何重新提交我的行李问题的索赔... [行李的潜在问题及解决方案...] 要重新提交您的行李问题的索赔,... single_hop_specifc_query_synthesizer
7 航班延误的主要原因是什么以及如何... [航班延误 航班延误可能由...] 航班延误可能由天气条件引起... single_hop_specifc_query_synthesizer
8 我如何申请报销额外费用... [2. 因延误产生的额外费用...] 要申请报销额外费用... single_hop_specifc_query_synthesizer
9 什么是乘客发起的取消? [航班取消 航班取消可以...] 乘客发起的取消是指当... single_hop_specifc_query_synthesizer

结语

在本教程中,我们探讨了使用 Ragas 库进行测试集生成,主要关注单跳查询。在我们即将发布的教程中,我们将深入研究多跳查询,将这些概念扩展到更丰富的测试集场景中。