手动评测LLM系统既繁琐又耗时,令人沮丧。如果你曾不得不循环遍历一组提示来逐一检查对应的LLM输出,那么你会很高兴了解到,本文将教你关于LLM评测的一切必要知识,以确保你和你的LLM应用的长久发展。
LLM评测指的是确保LLM输出符合人类期望的过程,这些期望可能涉及伦理和安全考量,也可能包括更实际的准则,如LLM输出的正确性和相关性。从工程角度看,这些LLM输出常以单元测试用例的形式出现,而评测标准则可封装为LLM评测指标。
讨论内容包括:
- LLM与LLM系统评测有何区别及其优势
- 离线评测,什么是LLM系统基准,如何构建评测数据集并选择合适的LLM评测指标(由LLM作为评判支持),以及常见陷阱
- 实时评测及其在改进离线评测基准数据集中的作用
- 现实世界中的LLM系统用例及评测方法,以 chatbotQA 和 Text-SQL 为例
让我们开始吧。
LLM 对比 LLM 系统评测
让我们明确一点:LLM(大型语言模型)特指经过训练以理解和生成人类语言的模型(例如 GPT-4),而LLM系统则指包含LLM本身及附加组件(如代理的功能工具调用、RAG 中的检索系统、响应缓存等)的完整配置,这些组件使得LLMs在实际应用中发挥作用,例如客户支持聊天机器人、自主销售代理和文本转 SQL 生成器。
然而,值得注意的是,LLM系统有时可能仅由LLM本身构成,ChatGPT 便是如此。以下是一个执行文本到 SQL 任务的基于 RAG 的LLM系统示例:
一个假设性的 Text-SQL 架构
由于 Text-SQL 的主要目标是为给定用户查询生成正确且高效的 SQL,用户查询通常首先通过检索流程从数据库模式中获取相关表,随后将其作为上下文通过 SQL 生成流程生成正确的 SQL。二者共同构成了一个基于 RAG 的LLM系统。
(注:从技术层面上讲,并非必须在生成前严格进行检索,但对于中等规模的数据库模式而言,执行检索有助于减少LLM的幻觉现象。)
评测一个LLM系统,因此并不像评测LLM本身那样直接。虽然LLMs和LLM系统都接收并生成文本输出,但由于LLM系统中可能有多个组件协同工作,这意味着你应该更细致地应用LLM评测指标来评测LLM系统的不同部分,以便更清晰地了解问题(或成功)出在哪里。
例如,你可以应用上下文召回指标来评测上述 Text-SQL 示例中的检索流程,以判断其是否能够检索出回答特定用户查询所需的所有必要表。
Contextual Recall 指标通常可用于评测检索流程
同样地,你也可以应用通过 G-Eval 实现的自定义 SQL 正确性指标,来评测生成管道是否基于检索到的前 K 个数据表生成了正确的 SQL。
自定义 SQL 正确性指标可用于评测 SQL 输出
总之,LLM系统由多个组件构成,这些组件有助于使LLM在执行其任务时更加高效,如 Text-SQL 示例所示,由于其复杂的架构,评测起来更为困难。
在下一节中,我们将探讨如何在开发阶段进行LLM系统评测(又称离线评测),包括快速生成大量测试用例以对LLM系统进行单元测试的方法,以及如何为特定组件选择合适的LLM评测指标。
离线评测:测试案例、评测数据集、LLM指标与基准
离线评测指的是在本地开发环境中对你的LLM系统进行评测或测试。设想在本地开发环境中运行评测,这可以是任何形式,从 Python 脚本、Colab/Jupyter 笔记本到部署到生产环境前在 Github Actions 上的 CI/CD 流水线。这让你能够量化地改进LLM系统架构,甚至迭代出适合LLM系统的最佳超参数集(比如每个组件中使用的LLM、提示模板、嵌入模型等)。
LLM 系统基准测试
一些工程师也将这种“基准测试”称为LLM系统,这完全没有错。基准测试LLM系统指的是在标准化评测数据集上,借助LLM评测指标,根据一组自定义标准量化LLM系统性能的过程,这正是离线评测的执行方式。以前文中的 Text-SQL 为例,用于基准测试我们LLM系统的指标将是上下文召回率和自定义 SQL 正确性指标,它们将基于一组用户查询和 SQL 输出(我们称之为测试用例)来量化 Text-SQL LLM系统的表现。
术语方面,以下是你需要了解的:
术语解析——你需要掌握的关键概念
- 基准测试由(通常为一个)评测数据集和LLM评测指标组成。
- 评测数据集由测试用例构成,这些用例将应用LLM评测指标进行衡量。
- 单个基准测试可以包含多个LLM评测指标,每个指标针对每个测试用例评测LLM系统的不同部分。
之后,你可以在本地开发环境中每次对LLM系统进行更改(例如切换至不同的检索架构或LLM提供商)时运行这些LLM系统基准测试,以检测性能上的任何破坏性变更,甚至可以在 CI/CD 流水线中运行这些基准测试来对LLM系统进行回归测试。
在进入下一部分之前,先透露一下如何通过开源LLM评测框架DeepEval以代码形式完成所有设置:
pip install deepeval
from deepeval.dataset import EvaluationDataset
from deepeval.metrics import ContextualRecallMetric
metric = ContextualRecallMetric(threshold=0.5)
dataset = EvaluateionDataset(test_cases=[...])
dataset.evaluate(metrics=[metric)
而对于那些希望立即开始评测的人,请查看 DeepEval 快速入门指南。
评测数据集与测试用例指南
评测数据集是测试用例的集合。评测数据集是测试用例的集合。没错,我并没有重复输入同一句话两次。
An LLM 测试用例
测试用例是一个简单的单元,它保存了用于对你的LLM系统进行单元测试的相关数据。以下是LLM测试用例包含的所有参数:
- 输入 — 你的LLM系统的输入数据。
- 实际输出 — 由你的LLM系统生成的文本响应。
- 预期输出 — 针对给定输入,你的LLM系统理想的响应内容。
- 检索上下文 — 在 RAG 管道/检索系统中检索到的文本块/文档。
- Context —— 预期输出所源自的理想文本块/文档。
关键在于:不同的评测指标需要在一个LLM测试用例中填充不同的参数。例如,无参考答案的相关性指标(稍后你会学到)仅需输入和实际输出,而基于参考答案的相关性指标则需要输入、实际输出和预期输出。
另一个例子可见于之前 Text-SQL 示例中使用的原始上下文召回指标。由于上下文召回评测的是你的检索系统能否检索到回答特定查询所需的所有相关文本块,因此你需要输入(即查询)和检索上下文(即检索到的相关文本块)。
以下是准备评测数据集时应遵循的一些快速规则:
- 从 50 到 100 个测试用例开始。你可以从头开始精心挑选这些用例,或者从生产数据中获取(如果你的LLM系统已经投入生产)。根据经验,这个数量最为合适,因为它足以揭示你LLM系统中的弱点,同时初始阶段也不会因数量过多而难以应对。
- 精心挑选那些最有可能在你决定评测LLM系统的任何标准上失败的测试用例。
- 实际输出无需预先计算,特别是如果你希望对LLM系统进行的每次更改都进行回归测试。
- 用预期输出填充测试用例。如LLM指标部分所述,基于参考的指标能提供更准确的结果,这就是为什么需要预期输出的原因。
尽管我已强调为何准备带有预期输出的测试用例至关重要,但这绝非易事,尤其是面对 50 至 100 个测试用例时。目前,为你的LLM系统基准测试构建评测数据集主要有两种方法:
- 人工标注——这种方法直接明了,雇佣专人坐下来准备 100 个测试用例。若你的LLM系统已投入生产环境,还可从生产数据中筛选测试用例。
- 合成数据生成——稍显复杂,改用LLMs来生成 100 个测试用例。
我本愿详细撰写如何在 Upwork 上雇人的步骤指南,但本文我将转而探讨利用LLMs进行合成数据生成。使用LLMs生成合成数据的过程包括向LLM提供上下文(没错,就是上文概述的LLM测试用例中的相同上下文),并基于给定上下文生成相应的输入及预期输出。
例如,在 Text-SQL 应用场景中,一个优秀的合成数据生成器应能:
- 随机(为评测数据集增添多样性)选择数据库模式中的不同数据表,并将其作为测试用例的上下文。
- 生成用户查询作为测试用例的输入。
- 根据测试用例的上下文和输入生成预期输出。
- 重复此步骤,直到获得一个大小合理的评测数据集。
然而,你还需要不断优化测试用例的输入,使其更加贴近现实或难以与人工标注的数据集区分开来。这一过程被称为“进化”,这是一种用于提升生成合成数据真实性的技术,最初由微软在 Evol-Instruct 论文中提出。
实际上,如果你对合成数据生成的工作原理感兴趣,这里有一篇关于如何构建自己的合成数据生成器的精彩文章(涉及LLMs);但如果你想要一个已经过生产验证且开源的工具,这里有一个通过 DeepEval 使用LLMs快速生成合成数据的方法。
from deepeval.dataset import EvaluationDataset
dataset = EvaluationDataset()
dataset.generate_goldens_from_docs(
document_paths=['example.pdf'],
include_expected_output=True,
max_goldens_per_document=5
)
请注意,在 DeepEval 中我们生成的是“goldens”,这本质上是没有实际输出的测试用例。这意味着在评测时,你需要运行你的LLM系统为每个 golden 生成实际输出,使其成为有效的LLM测试用例。
LLM 指标
LLM 评测指标用于帮助自动化评测LLM 系统的过程。当然,你可以让人工评测员为你评测LLM 系统,但那样你就又回到了低效的直觉检查LLM 输出的老路上。所以问题是,我该如何构建自己的LLM 评测指标,或者我应该为我的LLM 系统使用哪些LLM 评测指标?
在我之前的一篇文章中,我详细讨论了关于LLM评测指标你需要了解的一切。简而言之,传统指标如 BERT、ROUGE 和 n-gram 并不适用,因为LLM的输出对于统计方法或非LLM模型来说过于复杂,难以评测。因此,解决方案是采用LLMs即裁判的方法。
LLM即裁判是指利用LLMs来为测试用例打分。起初你可能会持怀疑态度,但研究表明,使用LLMs来评测LLMs是我们能达到最接近人类相关性判断的方式。
更高的 Spearman 和 Kendall-Tau 相关性表示与人类判断更高的一致性。
此外,诸如 G-Eval 等技术,通过提示缩小测试案例中待评测文本的规模,或利用 QAG(问答生成)更数学化地计算每个测试案例的指标分数,有助于LLMs生成更符合人类预期的评分。
以下是LLM系统最常用的LLM评测指标列表,每个指标评测LLM系统的不同部分:
- 正确性
- 答案相关性
- 忠实度
- 相似性
- 连贯性
- 上下文召回
- 上下文相关性
- 上下文精确度
- 偏见
- 毒性
(DeepEval 开箱即用地支持每一项指标,你应查阅文档以详细了解每个单独指标及其适用场景。)
例如,以下是如何在代码中实现自定义LLM作为评判标准的“正确性”指标:
from deepeval.metrics import GEval
from deepeval.test_case import LLMTestCaseParams
correctness_metric = GEval(
name="Correctness",
criteria="Determine whether the actual output is factually correct based on information in the expected output.",
evaluation_params=[
LLMTestCaseParams.ACTUAL_OUTPUT,
LLMTestCaseParams.EXPECTED_OUTPUT
]
)
在开发过程中进行评测时,你还应致力于使用基于参考的指标。基于参考的指标是指那些根据测试用例中标记的、理想的、预期的输出来打分的指标。以答案相关性指标为例,它既可以作为无参考指标,也可以作为基于参考的指标:
无参考与基于参考的答案相关性指标
虽然你确实可以通过使用LLM来计算答案相关性指标分数,以评测LLM输出与相应输入的相关性,但更好的方法是拥有预期输出并将其与生成的LLM输出进行比较。这是因为无参考指标通常有一个“更宽松”的评分标准,因此LLM计算出的指标分数在基准测试中同一组测试案例下,相比基于参考的指标更容易波动。换句话说,基于参考的指标更为可靠。
当然,策划评测数据集并为每个测试案例填充预期输出需要更多时间和精力,但通过 DeepEval 支持了数百个LLM评测用例后,我可以肯定地说,这确实有助于更准确地测试LLM系统。
好消息是,在下一节中,我将展示如何通过使用LLM生成合成数据集/测试用例来半自动化这一流程。
基准测试
- 对于LLM系统而言(即便是像 Text-SQL 这样的特定用例),不存在标准的LLM评测指标,因为指标取决于LLM系统的具体架构,而任何单一用例都没有标准架构。
- 对于给定的用例,没有标准的测试用例/评测数据集集。例如,在 Text-SQL 用例中,由于用户查询和测试用例中的黄金 SQL 输出会有所不同,你需要为两种不同的数据库模式准备两套不同的评测数据集。
趁我还没忘记,这里是如何通过代码使用答案相关性指标来对你的LLM系统进行基准测试的方法:
from deepeval.dataset import EvaluationDataset
from deepeval.test_case import LLMTestCase
from deepeval.metrics import AnswerRelevancyMetric
test_case = LLMTestCase(
input="Why did the chicken cross the road?",
actual_output="Quite frankly, I don't want to know..."
)
metric = AnswerRelevancyMetric()
dataset = EvaluationDataset(test_cases=[test_case])
dataset.evaluate(metrics=[metric])
离线评测中的常见陷阱
一个人可能犯的最大错误,就是假设自己的基准数据集“足够好”,并且从不随时间推移去改进它。改进基准数据集至关重要,因为要让基准有意义,它应当始终反映你LLM应用程序中最新的漏洞情况。
在下一部分,我将展示随着你的LLM系统投入生产,如何随时间推移改进基准评测数据集。
实时评测
(如果你的LLM系统尚未投入生产,这部分对你来说可能为时过早)
离线评测对于迭代非常有用,但它受限于基准数据集的全面性。虽然你可以通过人工标注员或数据合成器基于知识库中的数据来策划更多测试用例,但必须将生产数据纳入基准数据集,以模拟真实用户如何与你的LLM应用程序互动。
生产数据指的是你的LLM应用程序在实时生产环境中接收和生成的输入与响应。但这里存在一个问题:你很可能没有时间和资源去逐一检查生产中生成的每一个LLM响应,以确定哪些应加入评测数据集。
想象这样一个场景:你的LLM应用在生产环境中每月生成 5 万条LLM响应。很可能你无法在不崩溃的情况下逐一检查所有响应。于是你可能选择随机抽样 10%的生成响应进行人工复查,这依然是一项极其繁重的任务。正因如此,实时评测显得尤为重要。
实时评测能让你轻松识别生产环境中最可能不尽如人意的响应。与其随机抽样生产环境中 10%的响应,一个强大的实时评测基础设施可以让你筛选出在特定标准上失败的LLM响应。它帮助人类评测者以更高效的方式利用生产数据提升你的LLM系统基准。
LLM指标,在生产环境中
在之前的LLM指标部分,我们强调了开发中的指标应基于参考(即通过测试用例上的预期输出进行评测),因为基于参考的指标凭借更严格的评分标准,有助于使基准分数更为可靠。
然而,基于参考的指标无法在生产环境中执行,原因很简单:每个生成的LLM响应都没有预期输出。因此,我们将转而采用无参考指标。以下是一个无参考答案相关性指标的示例(我们最初在之前的LLM指标部分将其作为基于参考的指标引入):
无参考答案相关性度量
其思路是选择一个或多个无参考指标,用它来评测每个收到的LLM响应,并利用这些指标分数来决定应将哪个LLM响应加入以扩充现有的基准数据集。
最后,若你寻求一站式解决方案以在云端运行实时评测并管理基准测试,不妨尝试 Confident AI。它已与 DeepEval 完全集成,支持合成数据生成、几乎涵盖所有LLM评测指标,并拥有专为生产环境中监控LLM响应而设计的完整基础设施,可执行实时评测。
应用场景示例
总结一下,我为新兴LLM系统用例准备了两个简单的离线LLM评测示例。每个示例,我们都将按照以下步骤进行:
- 为你的基准数据集生成合成测试用例
- 选择相关的LLM评测指标
- 运行基准测试
Chatbot QA
聊天机器人问答(QA)本质上是一个基于聊天的信息搜索引擎,但与 ChatGPT 不同,因为它不具备对话功能。它最常用于快速搜索知识库中的信息,采用基于 RAG 的方法,首先通过在包含知识库解析和索引信息的向量存储中执行向量搜索来检索相关信息,然后将这些信息输入你的LLM,以生成针对用户查询的答案:
一个假设的chatbot QA架构
(注:此图表与 Text-SQL 的图表几乎相同,因为两种用例都是基于LLM系统的简化 RAG 实现)
第一步:假设我们已经拥有几份代表知识库的 PDF 文档,如 knowledge_1.pdf、knowledge_2.pdf 等,我们可以从这些文档中为聊天机器人问答应用生成合成测试用例:
from deepeval.synthesizer import Synthesizer
synthesizer = Synthesizer()
goldens = synthesizer.generate_goldens_from_docs(
document_paths=[
'knowledge_1.pdf',
'knowledge_1.pdf',
'knowledge_1.pdf',
'knowledge_1.pdf',
'knowledge_1.pdf',
'knowledge_1.pdf'
],
max_goldens_per_document=15,
include_expected_output=True
)
步骤二:既然我们已经生成了一些合成数据,接下来可以定义评测指标。本例中,我们将仅使用两个指标:正确性和上下文召回率。
from deepeval.metrics import GEval, ContextualRecallMetric
from deepeval.test_case import LLMTestCaseParams
contextual_recall = ContextualRecallMetric(threshold=0.6)
correctness = GEval(
name="Correctness",
criteria="Determine whether the actual output is factually correct based on the expected output.",
evaluation_params=[
LLMTestCaseParams.ACTUAL_OUTPUT,
LLMTestCaseParams.EXPECTED_OUTPUT
],
threshold=0.6
)
G-Eval 正确性指标用于比较实际输出与预期输出在事实准确性上的差异,而上下文召回率则评测检索上下文是否包含生成给定输入对应预期输出所需的全部信息。另请注意,我们已将每个指标的通过阈值设为 0.6,这意味着只有当两个指标得分均大于或等于 0.6 时,测试用例方可通过。
附:你应向上滚动并重新查看聊天机器人问答流程图,以了解每项指标评测的是LLM系统中的哪一部分。
第三步:准备好评测数据集和指标后,我们就可以运行基准测试了。虽然我们不会实际实现一个聊天机器人问答系统,但假设我们有一个名为 run_chatbot_qa() 的假设函数,它能返回生成的响应及用于生成响应的检索节点:
llm_output, retrieved_nodes = run_chatbot_qa("A user query")
运行基准测试的第一步,是将第一步生成的黄金标准数据转换为可供评测的测试用例:
from deepeval.test_case import LLMTestCase
from deepeval.dataset import EvaluationDataset
...
test_cases = []
for golden in goldens:
query = golden.input
llm_output, retrieved_nodes = run_chatbot_qa(query)
test_case = LLMTestCase(
input=query,
actual_output=llm_output,
retrieval_context=retrieved_nodes,
expected_output=golden.expected_output
)
test_cases.append(test_case)
dataset = EvaluationDataset(test_cases=test_cases)
最后,通过在你定义的两个指标上执行数据集来运行你的基准测试:
...
dataset.evaluate(metrics=[correctness, contextual_recall])
毕竟这并不那么困难,对吧?
Text-SQL
回到原点,Text-SQL 是一个应用场景,其中LLM系统生成相关 SQL 查询以回答数据分析问题。例如,一个数据分析问题可能是“上周有多少用户注册”?
我们将复用本文开头相同的 Text-SQL 架构图:
假设性的 Text-SQL 架构再次
步骤 1:在此合成数据生成步骤中,我们将使用数据库模式中的数据表生成合成黄金数据。
from deepeval.synthesizer import Synthesizer, UseCase
table1 = """CREATE TABLE Students (
StudentID INT PRIMARY KEY,
FirstName VARCHAR(50),
LastName VARCHAR(50),
Email VARCHAR(100) UNIQUE,
DateOfBirth DATE,
Gender CHAR(1),
Address VARCHAR(200),
PhoneNumber VARCHAR(15)
);"""
table2 = """CREATE TABLE Courses (
CourseID INT PRIMARY KEY,
CourseName VARCHAR(100),
TeacherID INT,
Credits INT,
DepartmentID INT,
FOREIGN KEY (TeacherID) REFERENCES Teachers(TeacherID),
FOREIGN KEY (DepartmentID) REFERENCES Departments(DepartmentID)
);"""
table3 = """CREATE TABLE Enrollments (
EnrollmentID INT PRIMARY KEY,
StudentID INT,
CourseID INT,
EnrollmentDate DATE,
Grade CHAR(2),
FOREIGN KEY (StudentID) REFERENCES Students(StudentID),
FOREIGN KEY (CourseID) REFERENCES Courses(CourseID)
);"""
table4 = """CREATE TABLE Teachers (
TeacherID INT PRIMARY KEY,
FirstName VARCHAR(50),
LastName VARCHAR(50),
Email VARCHAR(100) UNIQUE,
DepartmentID INT,
FOREIGN KEY (DepartmentID) REFERENCES Departments(DepartmentID)
);"""
synthesizer = Synthesizer()
goldens = synthesizer.generate_goldens(
contexts=contexts,
use_case=UseCase.TEXT2SQL,
max_goldens_per_context=15
)
步骤 2:我们将使用自定义 SQL 正确性指标和上下文召回指标:
from deepeval.metrics import ContextualRecallMetric
contextual_recall = ContextualRecallMetric(threshold=0.5)
sql_correctness = GEval(
name="SQL Correctness",
evaluation_steps=[
"Check the `actual output` for SQL syntax errors.",
"Verify that the `actual output` SQL is compatible with the schema in the `retrieval context`, ensuring correct usage of tables and columns.",
"Execute the `actual output` SQL and ensure the results precisely match the `expected output`.",
"Confirm that the `actual output` SQL is indeed relevant to the `input` user query.",
],
evaluation_params=[
LLMTestCaseParams.INPUT,
LLMTestCaseParams.ACTUAL_OUTPUT,
LLMTestCaseParams.EXPECTED_OUTPUT,
LLMTestCaseParams.RETRIEVAL_CONTEXT
],
)
类似于聊天机器人 QA 中使用的指标,SQL 正确性和上下文召回率指标分别评测生成器和检索流程。
步骤 3:再次假设我们拥有另一个名为 run_text_2_sql() 的假设函数,它返回生成的 SQL 查询及用于 SQL 生成的检索表:
sql_output, retrieved_tables = run_text_2_sql("How many users signed up last week?")
运行基准测试的第一步,是将第一步生成的黄金标准数据转换为可供评测的测试用例:
from deepeval.test_case import LLMTestCase
from deepeval.dataset import EvaluationDataset
...
test_cases = []
for golden in goldens:
query = golden.input
sql_output, retrieved_tables = run_text_2_sql(query)
test_case = LLMTestCase(
input=query,
actual_output=sql_output,
retrieval_context=retrieved_tables,
expected_output=golden.expected_output
)
test_cases.append(test_case)
dataset = EvaluationDataset(test_cases=test_cases)
最后,通过在你定义的两个指标上执行数据集来运行基准测试
...
dataset.evaluate(metrics=[sql_correctness, contextual_recall])
结论
在这篇长文中,我们学习了LLMs与LLM系统之间的区别,以及如何对它们进行不同的评测。
我们还了解了什么是离线评测,包括使用自定义数据集和指标进行基准测试以回归测试LLM系统的概念,以及 DeepEval 如何在整个评测生命周期中提供帮助。我们也看到了随时间改进基准数据集的重要性,以及生产环境中的实时评测如何发挥作用。最后,我们探讨了两个突出的LLM应用用例,如聊天机器人问答和 Text-SQL,以及如何对它们进行评测。