📘 **TELUS Agriculture & Consumer Goods** 如何通过 **Haystack Agents** 转变促销交易

教程:评估 RAG 管道


  • 级别:中级
  • 完成时间:15 分钟
  • 使用的组件: InMemoryDocumentStore, InMemoryEmbeddingRetriever, ChatPromptBuilder, OpenAIChatGenerator, DocumentMRREvaluator, FaithfulnessEvaluator, SASEvaluator
  • 先决条件: 您必须拥有来自 OpenAI 活跃账户的 API 密钥,因为本教程使用的是 OpenAI 的 gpt-4o-mini 模型:https://platform.openai.com/api-keys
  • 目标: 完成本教程后,您将学会如何使用 Haystack 提供的模型基础评估和统计指标来评估您的 RAG 管道。您还将了解 Haystack 集成了哪些其他评估框架。

概述

在本教程中,您将学习如何评估 Haystack 管道,特别是检索增强生成(RAG)管道。

  1. 您将首先构建一个基于 PubMed 数据的医学问题回答管道。
  2. 您将构建一个评估管道,该管道利用文档 MRR 和答案忠实度等指标。
  3. 您将运行您的 RAG 管道,并使用您的评估管道来评估输出。

Haystack 提供了多种评估器,它们可以执行两种类型的评估:

在本教程中,我们将使用这些评估技术中的一些来评估一个旨在回答 PubMed 数据问题的 RAG 管道。

🧑‍🍳 除了 Haystack 自有的评估指标外,您还可以集成多个评估框架。请参阅下面的集成和示例 👇

评估 RAG 流水线

RAG 管道最终由至少 2 个步骤组成

  • 检索
  • 生成

要评估一个完整的 RAG 管道,我们必须单独评估每个步骤,并评估整体。虽然在某些情况下,检索可以使用一些需要标签的统计指标进行评估,但对于生成步骤执行相同的操作并不容易。相反,我们通常依赖基于模型的指标来评估生成步骤,其中 LLM 被用作“评估器”。

Steps or RAG

📺 代码演示

准备 Colab 环境

安装 Haystack

使用 pip 安装 Haystack 和 datasets

%%bash

pip install haystack-ai
pip install "datasets>=2.6.1"
pip install "sentence-transformers>=4.1.0"

创建要评估的 RAG 管道

要评估 RAG 管道,我们需要一个 RAG 管道作为起点。因此,我们将首先创建一个问答管道。

💡 有关创建检索增强生成管道的完整教程,请参阅创建您的第一个带检索增强的 QA 管道教程

在本教程中,我们将使用一个标记的 PubMed 数据集,其中包含问题、上下文和答案。这样,我们就可以将上下文用作文档,并且我们还拥有一些评估指标所需的标记数据。

首先,让我们获取准备好的数据集并提取 all_documentsall_questionsall_ground_truth_answers

ℹ️ 数据集相当大,在本示例中我们使用了前 1000 行,但您可以根据需要增加此数量。

from datasets import load_dataset
from haystack import Document

dataset = load_dataset("vblagoje/PubMedQA_instruction", split="train")
dataset = dataset.select(range(1000))
all_documents = [Document(content=doc["context"]) for doc in dataset]
all_questions = [doc["instruction"] for doc in dataset]
all_ground_truth_answers = [doc["response"] for doc in dataset]

接下来,让我们构建一个简单的索引管道,并将 documents 写入 DocumentStore。这里,我们使用的是 InMemoryDocumentStore

InMemoryDocumentStore 是最容易入门的 DocumentStore。它不需要外部依赖,并且是小型项目和调试的不错选择。但它在大规模文档集合上的扩展性不太好,因此不适合生产系统。要了解 Haystack 支持的各种外部数据库,请参阅 DocumentStore 集成

from typing import List
from haystack import Pipeline
from haystack.components.embedders import SentenceTransformersDocumentEmbedder
from haystack.components.writers import DocumentWriter
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack.document_stores.types import DuplicatePolicy

document_store = InMemoryDocumentStore()

document_embedder = SentenceTransformersDocumentEmbedder(model="sentence-transformers/all-MiniLM-L6-v2")
document_writer = DocumentWriter(document_store=document_store, policy=DuplicatePolicy.SKIP)

indexing = Pipeline()
indexing.add_component(instance=document_embedder, name="document_embedder")
indexing.add_component(instance=document_writer, name="document_writer")

indexing.connect("document_embedder.documents", "document_writer.documents")

indexing.run({"document_embedder": {"documents": all_documents}})

现在我们的数据已准备就绪,我们可以创建一个简单的 RAG 管道。

在此示例中,我们将使用

import os
from getpass import getpass
from haystack.components.builders import AnswerBuilder, ChatPromptBuilder
from haystack.dataclasses import ChatMessage
from haystack.components.embedders import SentenceTransformersTextEmbedder
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.retrievers.in_memory import InMemoryEmbeddingRetriever

if "OPENAI_API_KEY" not in os.environ:
    os.environ["OPENAI_API_KEY"] = getpass("Enter OpenAI API key:")

template = [
    ChatMessage.from_user(
        """
        You have to answer the following question based on the given context information only.

        Context:
        {% for document in documents %}
            {{ document.content }}
        {% endfor %}

        Question: {{question}}
        Answer:
        """
    )
]

rag_pipeline = Pipeline()
rag_pipeline.add_component(
    "query_embedder", SentenceTransformersTextEmbedder(model="sentence-transformers/all-MiniLM-L6-v2")
)
rag_pipeline.add_component("retriever", InMemoryEmbeddingRetriever(document_store, top_k=3))
rag_pipeline.add_component("prompt_builder", ChatPromptBuilder(template=template))
rag_pipeline.add_component("generator", OpenAIChatGenerator(model="gpt-4o-mini"))
rag_pipeline.add_component("answer_builder", AnswerBuilder())

rag_pipeline.connect("query_embedder", "retriever.query_embedding")
rag_pipeline.connect("retriever", "prompt_builder.documents")
rag_pipeline.connect("prompt_builder.prompt", "generator.messages")
rag_pipeline.connect("generator.replies", "answer_builder.replies")
rag_pipeline.connect("retriever", "answer_builder.documents")

提问

在提问时,请使用管道的 run() 方法。确保将问题提供给所有需要它的组件。在这种情况下,这些是 query_embedderprompt_builderanswer_builder

question = "Do high levels of procalcitonin in the early phase after pediatric liver transplantation indicate poor postoperative outcome?"

response = rag_pipeline.run(
    {
        "query_embedder": {"text": question},
        "prompt_builder": {"question": question},
        "answer_builder": {"query": question},
    }
)
print(response["answer_builder"]["answers"][0].data)

评估管道

在本教程中,让我们使用以下指标来评估管道:

首先,让我们实际运行 RAG 管道并处理一组问题,并确保我们拥有这些问题的真实标签(答案和文档)。让我们从 25 个随机问题和标签开始👇

📝 一些说明:

  1. 有关可用指标的完整列表,请查看Haystack 评估器
  2. 在我们的数据集中,对于每个示例问题,我们有 1 个真实文档作为标签。但是,在某些情况下,可能会提供多个真实文档作为标签。您会注意到,这就是为什么我们为每个问题提供一个 ground_truth_documents 列表。
import random

questions, ground_truth_answers, ground_truth_docs = zip(
    *random.sample(list(zip(all_questions, all_ground_truth_answers, all_documents)), 25)
)

接下来,让我们运行管道,并确保跟踪管道返回的答案以及它检索到的文档。

rag_answers = []
retrieved_docs = []

for question in list(questions):
    response = rag_pipeline.run(
        {
            "query_embedder": {"text": question},
            "prompt_builder": {"question": question},
            "answer_builder": {"query": question},
        }
    )
    print(f"Question: {question}")
    print("Answer from pipeline:")
    print(response["answer_builder"]["answers"][0].data)
    print("\n-----------------------------------\n")

    rag_answers.append(response["answer_builder"]["answers"][0].data)
    retrieved_docs.append(response["answer_builder"]["answers"][0].documents)

虽然每个评估器都是可以在 Haystack 中单独运行的组件,但也可以将它们添加到管道中。这样,我们就可以构建一个包含所有所需评估指标的 eval_pipeline 来评估我们的管道。

from haystack.components.evaluators.document_mrr import DocumentMRREvaluator
from haystack.components.evaluators.faithfulness import FaithfulnessEvaluator
from haystack.components.evaluators.sas_evaluator import SASEvaluator

eval_pipeline = Pipeline()
eval_pipeline.add_component("doc_mrr_evaluator", DocumentMRREvaluator())
eval_pipeline.add_component("faithfulness", FaithfulnessEvaluator())
eval_pipeline.add_component("sas_evaluator", SASEvaluator(model="sentence-transformers/all-MiniLM-L6-v2"))

results = eval_pipeline.run(
    {
        "doc_mrr_evaluator": {
            "ground_truth_documents": list([d] for d in ground_truth_docs),
            "retrieved_documents": retrieved_docs,
        },
        "faithfulness": {
            "questions": list(questions),
            "contexts": list([d.content] for d in ground_truth_docs),
            "predicted_answers": rag_answers,
        },
        "sas_evaluator": {"predicted_answers": rag_answers, "ground_truth_answers": list(ground_truth_answers)},
    }
)

构建评估报告

运行评估管道后,我们还可以创建完整的评估报告。Haystack 提供了 EvaluationRunResult,我们可以使用它来显示 aggregated_report 👇

from haystack.evaluation.eval_run_result import EvaluationRunResult

inputs = {
    "question": list(questions),
    "contexts": list([d.content] for d in ground_truth_docs),
    "answer": list(ground_truth_answers),
    "predicted_answer": rag_answers,
}

evaluation_result = EvaluationRunResult(run_name="pubmed_rag_pipeline", inputs=inputs, results=results)
evaluation_result.aggregated_report()

额外:您还可以查看包含数据集中每个样本分数(scores)的详细报告,我们将选择输出格式为 DataFrame。

results_df = evaluation_result.detailed_report(output_format="df")
results_df

将我们的评估结果作为 DataFrame 非常有用。例如,在下面,我们可以使用 pandas DataFrame 过滤结果,以获取语义答案相似度(sas_evaluator)排名前 3 的以及排名最低的 3 个结果👇

import pandas as pd

top_3 = results_df.nlargest(3, "sas_evaluator")
bottom_3 = results_df.nsmallest(3, "sas_evaluator")
pd.concat([top_3, bottom_3])

下一步

🎉 恭喜!您已经学会了如何使用基于模型的评估框架来评估 RAG 管道,并且无需任何标记工作。

如果您喜欢这个教程,您可能还会喜欢

要及时了解最新的 Haystack 开发动态,您可以订阅我们的新闻通讯。感谢您的阅读!