Haystack Evaluators 完全指南:用 9 大评估器量化 RAG 与 Agent 管线质量
2026/9/13 23:10:08 网站建设 项目流程

Haystack Evaluators 完全指南:用 9 大评估器量化 RAG 与 Agent 管线质量

【免费下载链接】haystackOpen-source AI orchestration framework for building context-engineered, production-ready LLM applications. Design modular pipelines and agent workflows with explicit control over retrieval, routing, memory, and generation. Built for scalable agents, RAG, multimodal applications, semantic search, and conversational systems.项目地址: https://gitcode.com/GitHub_Trending/ha/haystack

本篇技术指南聚焦开源 AI 编排框架 Haystack 2.19 的haystack.components.evaluators评估器组件集,系统讲解精确匹配、召回率、MRR、MAP、NDCG、SAS 语义相似度以及基于 LLM 的上下文相关性、忠实度与通用评估器的原理、参数、输出结构与实战用法。读完本文,你将掌握在 RAG 问答、检索排序与生成式评估场景中,如何为每个评估器构造输入、解读分数并接入 Pipeline 进行离线质量评测。

一、评估器概览:从零到一的量化评估体系

Haystack 将评估器设计为标准的 Pipeline 组件,统一通过@component装饰器注册,全部集中在 haystack/components/evaluators 目录下,并在init.py 中对外导出。从源码结构看,这 9 个评估器可分为两大类:

类别评估器依赖适用场景
无监督确定性指标AnswerExactMatchEvaluatorDocumentRecallEvaluatorDocumentMRREvaluatorDocumentMAPEvaluatorDocumentNDCGEvaluator无需外部服务检索质量、答案字面匹配
语义/生成式指标SASEvaluatorContextRelevanceEvaluatorFaithfulnessEvaluatorLLMEvaluatorSentence-Transformers 模型 / LLM答案语义相似度、上下文相关性、答案忠实度、自定义标准

其中ContextRelevanceEvaluatorFaithfulnessEvaluator都继承自LLMEvaluator(见 context_relevance.py 与 faithfulness.py),三者共享同一套"指令 + 少样本示例 + JSON 输出"的提示词模板机制,因此底层参数高度一致。

所有评估器的通用约定ground_truth_*(真实答案/文档)与predicted_*/retrieved_*(预测/检索结果)列表必须等长;输出字典通常同时包含score(全体平均分)与individual_scores(逐条分数)。

二、确定性检索与答案指标

2.1 AnswerExactMatchEvaluator:答案精确匹配

功能:逐条判断预测答案是否与任一真实答案完全相等(区分大小写的字符串精确比较)。结果在 0.0 到 1.0 之间,表示匹配比例。支持多条真实答案与多条预测答案输入。

用法示例(源自 answer_exact_match.py):

from haystack.components.evaluators import AnswerExactMatchEvaluator evaluator = AnswerExactMatchEvaluator() result = evaluator.run( ground_truth_answers=["Berlin", "Paris"], predicted_answers=["Berlin", "Lyon"], ) print(result["individual_scores"]) # [1, 0] print(result["score"]) # 0.5

源码级行为说明(answer_exact_match.py):

  • 输入长度不一致时抛出ValueError("The length of ground_truth_answers and predicted_answers must be the same.")
  • 使用zip(..., strict=True)逐对比较,命中记 1、未命中记 0;
  • score = sum(matches) / len(predicted_answers),即精确匹配比例。

局限性:该指标不做任何归一化、同义词处理或语义判断,两个意思相同但措辞不同的答案会被判为不匹配。它最适合答案高度标准化(如命名实体、专有名词)的场景。

2.2 DocumentRecallEvaluator:文档召回率(支持两种模式)

功能:计算检索文档对真实文档的召回率。每个问题可有多条真实文档和多条检索文档。构造函数__init__(mode=RecallMode.SINGLE_HIT, document_comparison_field="content")(document_recall.py)支持两个关键参数:

  • mode:召回计算模式,由枚举RecallMode定义(document_recall.py):
    • RecallMode.SINGLE_HIT"single_hit"):只要任一真实文档被检索到,该问题即得 1 分,否则 0 分——判断"是否召回",单条分数恒为 0 或 1;
    • RecallMode.MULTI_HIT"multi_hit"):按命中真实文档的比例计分,即命中去重真实文档数 / 真实文档总数
    • 传入字符串时由RecallMode.from_str()转换,未知模式抛出ValueError
  • document_comparison_field:文档比对字段,可选"content"(默认,比较doc.content)、"id"(比较doc.id)、或"meta.<key>"(比较元数据,支持嵌套如"meta.source.url"),这是四个文档类评估器共享的参数。

用法示例(源自 document_recall.py):

from haystack import Document from haystack.components.evaluators import DocumentRecallEvaluator evaluator = DocumentRecallEvaluator() # 默认 SINGLE_HIT result = evaluator.run( ground_truth_documents=[ [Document(content="France")], [Document(content="9th century"), Document(content="9th")], ], retrieved_documents=[ [Document(content="France")], [Document(content="9th century"), Document(content="10th century"), Document(content="9th")], ], ) print(result["individual_scores"]) # [1.0, 1.0] print(result["score"]) # 1.0

第二问的真实文档是"9th century""9th",检索结果中二者均出现,故multi_hit模式下得 1.0;若真实文档含三条而只召回两条,则multi_hit得 0.67、single_hit仍为 1.0。

源码级行为说明(document_recall.py):比对基于去重后的比较值集合_unique_comparison_values会忽略空字符串与None);若真实或检索一侧没有可比的比较值,会记录logger.warning并将该条分数置 0.0。

2.3 DocumentMRREvaluator:均值倒数排名

功能:MRR(Mean Reciprocal Rank)衡量首个相关文档在检索结果中的排名。对每个问题,取第一个命中真实文档的位置的倒数1 / (rank + 1),若完全未命中则为 0。

用法示例(源自 document_mrr.py):

from haystack import Document from haystack.components.evaluators import DocumentMRREvaluator evaluator = DocumentMRREvaluator() result = evaluator.run( ground_truth_documents=[ [Document(content="France")], [Document(content="9th century"), Document(content="9th")], ], retrieved_documents=[ [Document(content="France")], [Document(content="9th century"), Document(content="10th century"), Document(content="9th")], ], ) print(result["individual_scores"]) # [1.0, 1.0] print(result["score"]) # 1.0

第二问中"9th century"位于第 1 位(rank 0),倒数排名为1/(0+1)=1.0;若首条命中在位置 3(rank 2),则该项为1/3 ≈ 0.33。源码逻辑见 document_mrr.py:命中后立即break,只计算首个命中位置的倒数,最终score为所有问题的平均。

适用提示:MRR 只关心"第一个"相关文档,适合"找到一条答案即可"的问答检索;若关心所有相关文档的排序质量,应改用 MAP 或 NDCG。

2.4 DocumentMAPEvaluator:平均精度均值

功能:MAP(Mean Average Precision)衡量全部相关文档在检索结果中的排名质量。对每个问题先算 Average Precision(AP):遍历检索结果,每命中一条相关文档,就累加当前命中数 / 当前位置,最后除以相关文档总数;score为所有问题 AP 的均值。

用法示例(源自 document_map.py):

from haystack import Document from haystack.components.evaluators import DocumentMAPEvaluator evaluator = DocumentMAPEvaluator() result = evaluator.run( ground_truth_documents=[ [Document(content="France")], [Document(content="9th century"), Document(content="9th")], ], retrieved_documents=[ [Document(content="France")], [Document(content="9th century"), Document(content="10th century"), Document(content="9th")], ], ) print(result["individual_scores"]) # [1.0, 0.8333333333333333] print(result["score"]) # 0.9166666666666666

第二问的手工验算:检索结果第 1 位"9th century"命中 → 累加1/1;第 3 位"9th"命中 → 累加2/3;AP =(1 + 2/3) / 2 ≈ 0.8333。实现细节见 document_map.py,源码用uncredited_ground_truth_values列表做去重与"先到先得"扣减,避免重复文档重复计分。

2.5 DocumentNDCGEvaluator:归一化折损累计增益

功能:NDCG(Normalized Discounted Cumulative Gain)同时考虑相关性与排名位置,是信息检索中最常用的排序质量指标之一。若真实文档带有score(相关性分数),NDCG 使用这些分数;否则假定所有真实文档的二元相关性为 1.0。

用法示例(源自 document_ndcg.py):

from haystack import Document from haystack.components.evaluators import DocumentNDCGEvaluator evaluator = DocumentNDCGEvaluator() result = evaluator.run( ground_truth_documents=[[Document(content="France", score=1.0), Document(content="Paris", score=0.5)]], retrieved_documents=[[Document(content="France"), Document(content="Germany"), Document(content="Paris")]], ) print(result["individual_scores"]) # [0.8869] print(result["score"]) # 0.8869

核心公式与源码实现(document_ndcg.py):

  • DCGcalculate_dcg):DCG = Σ relevance_i / log2(i + 2),其中i为 0 起始的排名;源码用relevant_value_to_score.pop(value)保证每个相关值最多计分一次,防止重复检索虚增分数;
  • IDCGcalculate_idcg):将真实文档的相关性分数降序排列后套用同一折损公式,得到"理想排序"下的最高可能 DCG;
  • NDCG = DCG / IDCG,当idcg > 0时有效,否则为 0;score为所有问题的 NDCG 均值。

输入校验validate_inputs,document_ndcg.py)会抛ValueError的情形:ground_truth_documentsretrieved_documents为空列表、两侧长度不一致、或某一问的真实文档中同时混有带分数与不带分数的文档(要求"要么全带、要么全不带")。

重要注意:MAP、MRR、NDCG 三个评估器均不主动归一化输入文档,官方建议在送入评估器前先用DocumentCleaner组件清洗并归一化文档内容,避免因空白、换行、大小写等差异导致比较失真。

三、语义与生成式评估

3.1 SASEvaluator:语义答案相似度

功能:SAS(Semantic Answer Similarity)基于 Hugging Face 预训练模型计算预测答案与真实答案的语义相似度,常用于 RAG 管线中评估生成答案质量。模型可以是Bi-Encoder(分别编码两段文本后计算余弦相似度)或Cross-Encoder(成对输入直接输出相似度),自动依据模型架构判断加载方式(sas_evaluator.py)。

构造参数(sas_evaluator.py):

参数默认值说明
model"sentence-transformers/paraphrase-multilingual-mpnet-base-v2"SentenceTransformers 语义相似度模型,可为模型名或本地路径
batch_size32每次编码的预测-标签对数量
deviceNone模型加载设备,None时自动选择
tokenSecret.from_env_var(["HF_API_TOKEN", "HF_TOKEN"], strict=False)Hugging Face 访问令牌(读取环境变量,非必填)

依赖说明:SASEvaluator 使用LazyImport惰性加载sentence-transformers,若未安装会提示Run 'pip install "sentence-transformers>=5.0.0"'(sas_evaluator.py)。

用法示例(源自 sas_evaluator.py):

from haystack.components.evaluators.sas_evaluator import SASEvaluator evaluator = SASEvaluator(model="cross-encoder/ms-marco-MiniLM-L-6-v2") evaluator.warm_up() # 首次使用时必须预热以加载模型 ground_truths = [ "A construction budget of US $2.3 billion", "The Eiffel Tower, completed in 1889, symbolizes Paris's cultural magnificence.", "The Meiji Restoration in 1868 transformed Japan into a modernized world power.", ] predictions = [ "A construction budget of US $2.3 billion", "The Eiffel Tower, completed in 1889, symbolizes Paris's cultural magnificence.", "The Meiji Restoration in 1868 transformed Japan into a modernized world power.", ] result = evaluator.run( ground_truths_answers=ground_truths, predicted_answers=predictions ) print(result["score"]) # 0.9999673763910929 print(result["individual_scores"]) # [0.9999765157699585, 0.999968409538269, 0.9999572038650513]

源码级行为说明(sas_evaluator.py):

  • 预测数与标签数不一致、或预测答案含None时抛ValueError;空预测列表返回{"score": 0.0, "individual_scores": [0.0]}
  • Cross-Encoder 路径:将预测-标签组成句子对,用model.predict(..., convert_to_numpy=True)打分;若原始分数大于 1(非归一化 logits),自动用expit(sigmoid)归一化到 0~1;
  • Bi-Encoder 路径:分别编码两侧文本,用util.cos_sim逐对计算余弦相似度;
  • 最终score = np_mean(similarity_scores)

3.2 LLMEvaluator:通用 LLM 评估器

功能:基于提示词(含指令与少样本示例)让 LLM 对输入做自定义评估。输入列表由用户按需定义(对应期望指标),输出为字典,results键下是逐条评估结果,每条是"用户自定义键 + 0(FALSE)/ 1(TRUE)"的字典。默认使用 OpenAI,需要环境变量OPENAI_API_KEY;也可通过chat_generator参数替换为任意实现了ChatGenerator协议的生成器。

用法示例(源自 llm_evaluator.py):

from haystack.components.evaluators import LLMEvaluator evaluator = LLMEvaluator( instructions="Is this answer problematic for children?", inputs=[("predicted_answers", list[str])], outputs=["score"], examples=[ {"inputs": {"predicted_answers": "Damn, this is straight outta hell!!!"}, "outputs": {"score": 1}}, {"inputs": {"predicted_answers": "Football is the most popular sport."}, "outputs": {"score": 0}}, ], ) predicted_answers = [ "Football is the most popular sport with around 4 billion followers worldwide", "Python language was created by Guido van Rossum.", ] results = evaluator.run(predicted_answers=predicted_answers) print(results) # {'results': [{'score': 0}, {'score': 0}]}

构造参数详解(llm_evaluator.py):

参数必填说明
instructions评估指令,应为可用 yes/no 回答的关于输入的提问
inputs期望接收的输入(即 Pipeline 输入连接),每个为(输入名, 类型)元组,类型必须是 list
outputs评估结果输出名,对应输出字典中的键
examples少样本示例,每条是含"inputs""outputs"两个字典键的字典
progress_bar是否显示评估进度条,默认True
raise_on_failureAPI 调用失败时是否抛异常,默认TrueFalse时记录 warning 并把该条结果置为None
chat_generator自定义 LLM;不传时使用OpenAIChatGenerator(generation_kwargs={"response_format": {"type": "json_object"}, "seed": 42})

JSON 输出要求:无论使用哪个 LLM,都必须配置为返回 JSON 对象。以OpenAIChatGenerator为例,需在generation_kwargs中传入{"response_format": {"type": "json_object"}}

提示词模板机制prepare_template,llm_evaluator.py)自动拼装为固定格式:

Instructions: <instructions> Generate the response in JSON format with the following keys: <list of output keys> Consider the instructions and the examples below to determine those values. Examples: Inputs: <example inputs JSON> Outputs: <example outputs JSON> Inputs: {"input_name": "{{ input_name }}"} Outputs:

该模板与PromptBuilder配合(self.builder = PromptBuilder(template=template)),运行时逐条渲染输入。run方法的执行链路(llm_evaluator.py):校验输入 → 将多个输入列表按位置 zip 成逐条字典 → 循环调用生成器 → 用_parse_dict_from_json解析 JSON 并核对输出键 → 汇总resultsmeta(OpenAI 响应含meta键时会附带元数据)。同步run与异步run_async双接口均已实现。

序列化支持to_dict会将inputs中的类型序列化为字符串、chat_generator序列化为子组件字典;from_dict反序列化时通过deserialize_type还原类型、deserialize_chatgenerator_inplace还原生成器(llm_evaluator.py),因此 LLMEvaluator 可无缝嵌入 YAML Pipeline 描述文件。

3.3 ContextRelevanceEvaluator:上下文相关性

功能:判断给定上下文(contexts)对回答问题是否相关。LLM 先把上下文拆分为多条陈述,再逐条判断"该陈述是否有助于回答问题";每条上下文得二元分数 1 或 0,并输出相关陈述列表与全部输入对的平均分。

用法示例(源自 context_relevance.py):

from haystack.components.evaluators import ContextRelevanceEvaluator questions = ["Who created the Python language?", "Why does Java needs a JVM?", "Is C++ better than Python?"] contexts = [ [("Python, created by Guido van Rossum in the late 1980s, is a high-level general-purpose programming " "language. Its design philosophy emphasizes code readability, and its language constructs aim to help " "programmers write clear, logical code for both small and large-scale software projects.")], [("Java is a high-level, class-based, object-oriented programming language that is designed to have as few " "implementation dependencies as possible. The JVM has two primary functions: to allow Java programs to run" "on any device or operating system (known as the 'write once, run anywhere' principle), and to manage and " "optimize program memory.")], [("C++ is a general-purpose programming language created by Bjarne Stroustrup as an extension of the C " "programming language.")], ] evaluator = ContextRelevanceEvaluator() result = evaluator.run(questions=questions, contexts=contexts) print(result["score"]) # 0.67 print(result["individual_scores"]) # [1, 1, 0] print(result["results"]) # [{'relevant_statements': ['Python, created by Guido van Rossum in the late 1980s.'], 'score': 1.0}, ...]

构造参数(context_relevance.py,与FaithfulnessEvaluatorLLMEvaluator一致):

  • examples:可选少样本示例,格式为{"inputs": {"questions": ..., "contexts": ...}, "outputs": {"relevant_statements": [...]}},不传则使用内置默认示例;
  • progress_bar:是否显示进度条,默认True
  • raise_on_failure:API 调用失败时是否抛异常,默认True
  • chat_generator:自定义 LLM(需配置为返回 JSON),默认使用 OpenAI JSON 模式。

输入输出run):questions为问题列表,contexts为"每个问题对应一组上下文"的嵌套列表。返回score(所有问题的平均上下文相关分)与results(每条上下文含relevant_statementsscore的字典列表)。该方法内部使用component.set_input_types动态声明输入类型(questions: list[str]contexts: list[list[str]]),并通过validate_input_parameters校验输入长度一致性。

3.4 FaithfulnessEvaluator:答案忠实度

功能:判断生成答案中的每条陈述能否从给定上下文中推断出来,用于检测 LLM 幻觉。LLM 先将答案拆分为多条陈述,逐条判断是否被上下文支持;最终分数为该答案中"可推断陈述"的比例(0.0~1.0)。

用法示例(源自 faithfulness.py):

from haystack.components.evaluators import FaithfulnessEvaluator questions = ["Who created the Python language?"] contexts = [ [("Python, created by Guido van Rossum in the late 1980s, is a high-level general-purpose programming " "language. Its design philosophy emphasizes code readability, and its language constructs aim to help " "programmers write clear, logical code for both small and large-scale software projects.")], ] predicted_answers = [ "Python is a high-level general-purpose programming language that was created by George Lucas." ] evaluator = FaithfulnessEvaluator() result = evaluator.run(questions=questions, contexts=contexts, predicted_answers=predicted_answers) print(result["individual_scores"]) # [0.5] print(result["score"]) # 0.5 print(result["results"]) # [{'statements': ['Python is a high-level general-purpose programming language.', # 'Python was created by George Lucas.'], # 'statement_scores': [1, 0], # 'score': 0.5}]

示例中答案被拆成两句:"Python is a high-level general-purpose programming language."(可推断,1 分)与 "Python was created by George Lucas."(不可推断,0 分——上下文说的是 Guido van Rossum),忠实度 0.5,有效暴露了模型把创始人"替换"成 George Lucas 的幻觉。

构造参数与输出__init__参数与ContextRelevanceEvaluator完全一致(examples格式为{"inputs": {"questions", "contexts", "predicted_answers"}, "outputs": {"statements", "statement_scores"}})。run接收questionscontexts(嵌套列表)、predicted_answers,返回:

  • score:所有答案的平均忠实度;
  • individual_scores:每条答案的忠实度列表;
  • results:每条答案的statements(陈述列表)、statement_scores(逐句支持情况)与score

典型用法:将 RAG 检索到的上下文与生成答案同时送入该评估器,即可量化"答案是否忠于检索证据",是 RAG 幻觉检测的核心组件。

四、评估器校验机制与序列化设计

输入校验:四类校验贯穿所有评估器——

  • validate_init_parametersLLMEvaluator系列):校验inputs必须是(名称, list 类型)元组列表、outputs必须是字符串列表、examples必须是含"inputs"/"outputs"字符串键字典的列表,违规即抛ValueError
  • validate_input_parameters:校验所有期望输入均已提供、且均为等长列表;
  • is_valid_json_and_has_expected_keys/_parse_dict_from_json:校验 LLM 输出是合法 JSON 且含期望键——raise_on_failure=True时抛ValueErrorFalse时发出 warning 并返回False(对应条目记为None);
  • 文档类评估器的长度一致性校验(如 answer_exact_match.py、document_ndcg.py)。

序列化AnswerExactMatchEvaluatorSASEvaluator通过default_to_dict/default_from_dict实现轻量序列化;LLMEvaluator家族额外处理了 tuple 类型(转成[name, serialized_type]列表存储)与内嵌chat_generator的递归序列化。这意味着整个评估器集都能与 Pipeline YAML 编组 体系协同,评估流程可持久化为配置文件。

五、在 Pipeline 中编排评估流程

评估器本质是标准 Haystack 组件,可直接连接进 Pipeline。以 RAG 离线评估为例,可将检索器输出接到文档类评估器、生成器输出接到语义/生成类评估器:

from haystack import Document, Pipeline from haystack.components.evaluators import DocumentRecallEvaluator, SASEvaluator pipeline = Pipeline() pipeline.add_component("recall", DocumentRecallEvaluator(mode="multi_hit")) pipeline.add_component("sas", SASEvaluator(model="sentence-transformers/paraphrase-multilingual-mpnet-base-v2")) pipeline.add_component("sas_warm_up", ...) # 注意 SASEvaluator 需在 run 前 warm_up result = pipeline.run({ "recall": { "ground_truth_documents": [[Document(content="France")]], "retrieved_documents": [[Document(content="France"), Document(content="Germany")]], }, "sas": { "ground_truth_answers": ["The capital of France is Paris."], "predicted_answers": ["Paris is the capital of France."], }, }) print(result["recall"]["score"]) # 1.0 print(result["sas"]["score"]) # 0.0x(语义相似但措辞不同,显著高于字面匹配)

实践建议

  • 检索排序评估优先组合DocumentRecallEvaluator(覆盖)+DocumentMRREvaluator(首命位置)+DocumentNDCGEvaluator(排序质量);
  • 答案质量评估组合AnswerExactMatchEvaluator(字面)+SASEvaluator(语义)+FaithfulnessEvaluator(幻觉检测)+ContextRelevanceEvaluator(检索上下文相关性);
  • LLM 类评估器务必先完成warm_up(),并为自定义chat_generator配置 JSON 输出格式;
  • 送入文档类评估器前先经DocumentCleaner归一化,避免格式差异导致误判。

六、深入阅读

  • 评估器源码:haystack/components/evaluators(含answer_exact_match.pydocument_recall.pydocument_mrr.pydocument_map.pydocument_ndcg.pysas_evaluator.pyllm_evaluator.pycontext_relevance.pyfaithfulness.py
  • 组件导出入口:haystack/components/evaluators/init.py
  • 评估结果数据类:haystack/evaluation/eval_run_result.py
  • 文档归一化组件:haystack/components/preprocessors 下的DocumentCleaner
  • 官方 API 参考:docs-website 中的 evaluators_api.md(本文档即其 2.19 版本,其余版本位于 reference_versioned_docs 与 reference/haystack-api)

【免费下载链接】haystackOpen-source AI orchestration framework for building context-engineered, production-ready LLM applications. Design modular pipelines and agent workflows with explicit control over retrieval, routing, memory, and generation. Built for scalable agents, RAG, multimodal applications, semantic search, and conversational systems.项目地址: https://gitcode.com/GitHub_Trending/ha/haystack

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询