AI知识库 AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


避免LLM产品滑铁卢:揭示构建强大评估体系的成功密钥
浏览次数: 1560
赋予动机
五年前,我带领团队创建了CodeSearchNet——GitHub CoPilot的前身,自此开始了与语言模型的工作。在此期间,我目睹了许多构建LLM产品的成功与失败案例。我发现,几乎所有的失败产品都源于一个共同的根本原因:未能建立健壮的评估体系
如今,作为一名独立顾问,我致力于协助企业开发领域特定的人工智能产品,期望通过详读本文,企业能够节省数以千计的咨询费用。尽管我乐于盈利,但我更不愿看到人们反复犯同样的错误。
本文将阐述我对构建基于LLMs的AI产品评估系统的思考。
快速迭代即成功
如同软件工程,AI项目的成功取决于迭代速度。为此,必须具备以下流程和工具:
  1. 评估质量(如:测试)。
  2. 调试问题(如:日志记录与数据检查)。
  3. 改变系统行为或机制(如:提示工程、微调、编写代码)。
许多人仅关注上述第3点,这使得他们的LLM产品无法超越演示阶段妥善进行上述三项活动,将形成良性循环,使优秀AI产品从平庸中脱颖而出(下图对该循环进行了可视化展示)。
若能优化评估流程,其他所有活动都将变得轻松。这与软件工程中前期投入虽大,但长期来看测试带来巨大回报的情形极为相似。
为使本文更具现实意义,我将通过一个案例研究来说明如何构建一套实现快速改进的系统。我将主要聚焦于评估环节,因其最为关键。
案例研究:Lucy——房地产 AI 助手
Rechat 是一款SaaS应用程序,专为房地产专业人士设计,可完成合同管理、房源搜索、创意资产制作、预约安排等多种任务。Rechat的理念在于,用户在一个平台上即可完成所有操作,无需在多个工具间频繁切换上下文。
Rechat 的 AI 助手 Lucy是一个典型的AI产品:通过对话界面,用户无需点击、输入和浏览软件,即可完成所需操作。在Lucy的早期开发阶段,通过提示工程(prompt engineering)取得了快速进展。然而,随着Lucy功能范围的扩大,AI性能逐渐陷入停滞,具体表现为:
  1. 解决一个失效模式后,又出现其他失效模式,犹如打地鼠游戏。
  2. 除基本的“氛围检测”外,对于AI系统在各项任务中的整体效果缺乏深入了解。
  3. 提示内容逐渐膨胀为冗长且难以驾驭的形式,试图涵盖众多边缘情况和示例。





问题:如何系统性地提升AI性能?





为打破这一停滞局面,我们围绕评估构建了一套针对Lucy的系统化改进方法如下图所示,该方法概述了我们的思路。
此图是我对提升AI系统性能思维模型的最佳呈现尝试。实际上,这一过程是非线性的,可能呈现出多种形态,与图示不尽相同。
接下来,我将结合评估的背景,讨论该系统各组成部分。
评估类型
严谨且系统的评估是整个体系中最重要的一环,因此在图中,“评估与筛选”部分以黄色高亮显示于中心位置。应将大部分精力投入到构建更为稳健、高效的评估流程上。
评估涉及三个层级:
  1. 第一级:单元测试
  2. 第二级:模型与人工评估(包括调试)
  3. 第三级:A/B测试
第三级的成本高于第二级,第二级又高于第一级。这一成本差异决定了各级评估的执行频率与方式。例如,我通常在每次代码变更时运行第一级评估,按照固定周期进行第二级评估,并仅在产品有重大更新时进行第三级评估。此外,在开始基于模型的测试前,先通过大量第一级测试也是有益的,因为后者需要更多时间和工作量来执行。
何时引入各级别测试并无严格公式。需在获取用户反馈的时效性、管理用户感知以及AI产品的目标之间找到平衡,这与一般产品开发中的权衡并无太大区别。
1
第一级:单元测试

针对LLMs的单元测试类似于使用pytest编写的断言。与常规单元测试不同,这些断言应组织得当,以便在单元测试之外的场景中使用,如数据清洗和模型推理期间的自动重试(利用断言错误进行调整)。关键在于,随着应用开发,这些断言应运行快速且成本低廉,以便每次代码变更时都能运行。如果难以构思断言,应仔细审查跟踪信息和失效模式。同时,不要犹豫使用LLM帮助你生成断言!

步骤 1:编写范围明确的测试

思考单元测试最有效的方法是将LLM的范围分解为特征和场景。例如,Lucy的一项特征是查找房地产房源,可进一步细分为以下场景:
特性:房源查找器
待测试的特性是响应用户查找房地产房源请求的函数调用。例如,“请查找加利福尼亚州圣何塞市内卧室数量超过3个、价格低于200万美元的房源。”
LLM将此请求转化为针对CRM运行的查询。断言随后验证返回预期数量的结果。在我们的测试套件中,我们有三个用户输入触发以下每个场景,进而执行相应的断言(以下为简化示例,旨在说明):
场景
断言
只有一个房源匹配用户查询
len(listing_array) == 1
多个房源匹配用户查询
len(listing_array) > 1
没有房源匹配用户查询
len(listing_array) == 0
还有一些不针对特定特性的通用测试。例如,以下是一个确保输出中未提及UUID的通用测试代码:
const noExposedUUID = message => { // 移除双花括号内的所有文本 const sanitizedComment = message.comment.replace(/\{\{.*?\}\}/g, '')
// 搜索暴露的UUID const regexp = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/ig const matches = Array.from(sanitizedComment.matchAll(regexp)) expect(matches.length, 'Exposed UUIDs').to.equal(0, 'Exposed UUIDs found')}
CRM返回给LLM的结果包含不应向用户显示的字段,如与条目关联的UUID。我们的LLM提示告诉LLM不要包含UUID。我们使用简单的正则表达式断言LLM响应中不包含UUID。
Rechat拥有数百个此类单元测试。根据用户挑战AI或产品演进过程中观察到的新失效模式,我们会持续更新它们这些单元测试对于快速获取反馈至关重要,尤其是在对AI系统(如提示工程、改进RAG等)进行迭代时。许多人在产品成熟后逐渐不再依赖单元测试,转而采用其他级别的评估,但务必不要跳过这一步!

步骤 2:创建测试用例

要测试这些断言,必须生成触发所有期望测试场景的测试用例或输入。我经常利用LLM来合成生成这些输入;例如,以下是一个Rechat用于为创建和检索联系人功能生成合成输入的提示:
编写50条不同的指令,让房地产经纪人指示其助手在CRM中创建联系人。联系人详情可以包括姓名、电话、邮箱、配偶姓名、生日、标签、公司、地址和职务。
对于每条指令,您需要生成第二条指令,用于查找已创建的联系人。
结果应为仅包含一条作为指令的字符串的JSON代码块,如下所示:
[ ["Create a contact for John (johndoe@apple.com)", "What's the email address of John Smith?"]]
使用上述提示,我们生成如下测试用例:
[ [ 'Create a contact for John Smith (johndoe@apple.com) with phone number 123-456-7890 and address 123 Apple St.', 'What\'s the email address of John Smith?' ], [ 'Add Emily Johnson with phone 987-654-3210, email emilyj@email.com, and company ABC Inc.', 'What\'s the phone number for Emily Johnson?' ], [ 'Create a contact for Tom Williams with birthday 10/20/1985, company XYZ Ltd, and job title Manager.', 'What\'s Tom Williams\' job title?' ], [ 'Add a contact for Susan Brown with partner name James Brown, and email susanb@email.com.', 'What\'s the partner name of Susan Brown?' ], ...]
对于每一个测试用例,我们先执行第一条用户输入来创建联系人,然后执行第二条查询来获取该联系人。如果CRM未能返回恰好一个结果,那么我们知道在创建或获取联系人时存在问题。我们还可以运行诸如验证响应中不包含UUID之类的通用断言。随着通过人工评估和调试观察数据,必须不断更新这些测试。关键是既要尽可能模拟用户与系统的交互,又要使其具有挑战性。
无需等待生产数据来测试您的系统。您可以根据对用户如何使用产品的合理推测来生成合成数据。您也可以允许一小部分用户使用您的产品,通过他们的使用情况来完善您的合成数据生成策略。一个表明您编写了良好测试和断言的信号是,当模型难以通过这些测试时——这些失效模式会成为您日后可以通过微调等技术解决的问题。
顺带一提,与传统的单元测试不同,您不一定需要达到100%的通过率。您的通过率是一个产品决策,取决于您愿意容忍哪些失败情况。

步骤3:定期运行并跟踪您的测试

有多种方法可以编排一级测试。Rechat一直在利用CI基础设施(如GitHub Actions、GitLab Pipelines等)来执行这些测试。然而,这一工作流程环节的工具尚处于起步阶段且发展迅速。
我的建议是,编排那些在技术栈中产生最少摩擦的测试。除了跟踪测试本身,还需要随着时间推移跟踪测试结果,以便了解是否取得了进展。如果您使用CI,应在CI系统之外收集测试/提示版本的指标,以便于分析和追踪。
我建议从简单开始,利用现有的分析系统来可视化测试结果。例如,Rechat使用Metabase来跟踪其LLM测试结果随时间的变化。以下是Rechat使用Metabase构建的一个仪表板的截图:
此截图展示了Lucy在我们修复特定错误之前(左)与之后(右)该错误出现的频率(以黄色显示)
2
第二级:人工与模型评估

在建立了坚实的第一级测试基础后,可以转向其他仅靠断言无法测试的验证形式。进行人工与模型评估的前提是记录跟踪信息。

记录跟踪信息

跟踪是软件工程中已存在一段时间的概念,是对一系列事件(如用户会话或分布式系统中请求流)的记录。换句话说,跟踪是对日志的一种逻辑分组。在LLMs的背景下,跟踪通常指与LLM进行的对话。例如,用户消息、随后的AI回复、再接着的另一用户消息,就是一个跟踪示例。
记录LLM跟踪信息的解决方案正在不断增加。Rechat使用LangSmith来记录跟踪信息,它允许以人类可读的方式查看跟踪,并提供交互式沙盒以迭代提示。有时,记录跟踪信息需要对代码进行插桩。在这种情况下,Rechat使用LangChain,它会自动为您将跟踪事件日志记录到LangSmith。以下是其外观的截图:
我喜欢LangSmith——它并不强制您使用LangChain,而且直观易用。无论选择何种解决方案,搜索、过滤和阅读跟踪都是必不可少的功能。我发现一些工具并未正确实现这些基本功能!

查看跟踪信息

必须消除查看数据过程中的所有障碍。这意味着以领域特定的方式呈现跟踪信息。我经常发现,最好自己构建数据查看与标注工具,以便在一个屏幕上集中所有所需信息。在Lucy的例子中,我们需要查看多种信息源(跟踪日志、CRM等),以理解AI的行为。这正是需要消除的摩擦类型。对于Rechat而言,这意味着添加如下信息:
  1. 正在评估的工具(功能)与场景。
  2. 跟踪信息源自合成输入还是真实用户输入。
  3. 在不同工具与场景组合之间导航的过滤器。
  4. 当前记录与CRM及跟踪日志系统的链接。
针对我所处理的每个问题,我都构建了该工具的不同版本。有时,甚至需要嵌入另一个应用程序来查看用户交互情况。以下是用于评估Rechat跟踪信息的工具截图:
另一个特定于Lucy的具体设计选择是,我们注意到许多失败案例涉及LLM最终输出中的小错误(格式、内容等)。因此,我们决定让人类可以编辑最终输出,以便我们可以对数据进行筛选与修正,以供微调使用。
这些工具可以使用轻量级前端框架(如Gradio、Streamlit、Panel或Shiny)在不到一天的时间内构建。上述工具就是使用Python版Shiny构建的。此外,还有像 Lilac 这样的工具,它利用AI进行语义化的数据搜索与过滤,这对于调试问题时寻找一组相似数据点非常方便。
我通常从标记示例为好或坏开始。我发现,分配分数或更精细的评级比二元评级更难管理。虽然有一些高级技术可以使人工评估更高效或准确(如,[主动学习]、[共识投票]等),但我建议从简单的方法开始。最后,与单元测试一样,您应该组织并分析人工评估结果,以评估随时间是否有进步。
如后面所述,这些已标记示例用于衡量系统质量、验证自动化评估,并为微调提供高质量的合成数据。

应查看多少数据?

我经常被问及应查看多少数据。刚开始时,应尽可能多地查看数据。通常至少阅读由所有测试用例和用户生成的跟踪信息。永远不能停止查看数据,因为天下没有免费的午餐。然而,随着时间推移,可以对数据进行更多的抽样,从而减轻负担。

带 LLM 的自动评估

许多供应商试图向您推销声称能消除人工查看数据需求的工具。定期让人类至少对样本跟踪信息进行评估是个好主意。我发现“正确性”在某种程度上具有主观性,必须使模型与人类判断保持一致。
您应追踪基于模型的评估与人工评估之间的关联度,以决定多大程度上可依赖自动评估。此外,通过收集标注员解释其决策原因的反馈,您可以通过对评估模型进行提示工程(prompt engineering)或微调来使其与人类判断对齐。不过,我个人倾向于采用提示工程来调整评估模型。
我喜欢使用诸如Excel之类的低技术解决方案来迭代调整基于模型的评估与人工评估的一致性。例如,每隔几天我会给同事菲利普发送一个电子表格,用于评估涉及自然语言查询生成器的不同应用场景。该电子表格包含以下信息:
  • 模型响应:这是LLM做出的预测。
  • 模型批评:这是(通常更为强大的)LLM对原始LLM预测所写的批评。
  • 模型结果:这是批评模型赋予“好”或“坏”的二元标签。
随后,菲利普填写他自己的版本相同信息——即他的批评、结果以及对每次25至50个示例的期望响应(以下以“phillip_”前缀开头的列所示):
这些信息使我能够逐步调整批评模型的提示,使其随着时间推移与菲利普的意见充分一致。在一个电子表格中以低技术手段记录这一过程也很简单:
这是一张截图,展示了我们在尝试将基于模型的评估与人类评估者对齐时的记录情况。
关于基于模型评估的一般建议:
  1. 使用最强大的模型:在预算允许范围内尽可能选用最强大的模型。对输出进行有效批评往往需要高级推理能力。在评估阶段,相对于生产环境中使用的模型,您可以选择速度较慢但功能更强大的模型来进行批判分析。
  2. 视模型评估为更大问题中的元问题:您必须维护一个微型评估系统来监控其质量。有时我在这个阶段会对模型进行微调(尽管我尽量避免这样做)。
  3. 持续监测模型与人类一致性:在将基于模型的评估器与人类评估标准校准一致后,必须继续定期进行练习,以监控模型与人类意见的一致性。
创建优秀评估模型过程中我最喜欢的一点是,其提供的批评意见可用于精选高质量合成数据,这一点我将在后面进一步讨论。
3
第 三 级:A/B 测试

最后,进行A/B测试始终是明智之举,以确保您的AI产品能够驱动您期望的用户行为或结果。与其它类型产品相比,LLMs的A/B测试并无太大区别。如果您想了解更多关于A/B测试的信息,我推荐阅读Eppo博客(由我曾共事过的、在A/B测试方面堪称明星的同事创建)。
在您确信AI产品适合向真实用户展示并准备充分之前,推迟到这一阶段并无不妥。这种级别的评估通常只适用于更成熟的产品。
4
评估 RAG

除了评估整个系统外,您还可以评估AI的子组件,比如RAG。评估RAG超出了本文范围,但您可以在 Jason Liu 的帖子中的文章中了解更多相关内容。
评估系统开启免费超能力
除了加快迭代速度,评估系统还解锁了微调和调试的能力,可将您的AI产品提升到新的层次。
1
微调

Rechat通过微调解决了许多仅凭提示工程无法解决的失效模式。微调最适合学习语法、风格和规则,而诸如RAG等技术则为模型提供上下文或最新事实。
微调涉及的99%劳动是组装覆盖AI产品范围的高质量数据。然而,如果您有一个像Rechat那样坚实的评估系统,就已经拥有了强大的数据生成和筛选引擎!我将在未来的文章中更详细地探讨微调过程。

数据合成与筛选

为了说明为何一旦拥有评估系统,数据筛选与合成几乎可以“免费”获得,试想一个场景:您希望为前面提到的房源查找器生成额外的微调数据。首先,您可以使用LLMs,通过如下类似提示来生成合成数据:
设想Zillow能解析自然语言。设想出用户在该平台搜索房源的50种不同方式。使用实际的城市和社区名称。
您可以使用以下参数(此处省略以保护机密性):
输出应为一个JSON代码块数组,例如:
[ "纽约市售价50万美元以下的住宅"]
这与生成测试案例的练习几乎相同!随后,您可以运用第一级和第二级测试来过滤掉未能通过断言或被批评模型判断为错误的不理想数据。同时,您也可以利用现有的人工评估工具查看轨迹,为微调数据集筛选合适的轨迹。
2
调试

当您收到关于AI产品的投诉或发现相关错误时,应当能够快速进行调试。若拥有一个强大的评估系统,您已具备以下条件:
  • 一个可供搜索与筛选的轨迹数据库。
  • 一套有助于标记错误及不良行为的机制(如断言、测试等)。
  • 能够帮助定位错误根源的日志搜索与导航工具。错误可能源自RAG、代码中的bug,或是模型性能欠佳。
  • 针对错误作出调整并快速验证其效果的能力。
简而言之,构建评估系统所需的基础架构与调试之间存在极大的重叠。
结论
评估系统创造出一个飞轮效应,使您能够迅速迭代产品。这往往是人们在开发AI产品时遇到瓶颈的地方。希望本文能为您提供构建评估系统的直觉指导。以下是几点关键要点:
  • 消除查看数据的所有阻力:确保数据访问无碍,易于分析。
  • 保持简洁:无需购买复杂的LLM工具,先充分利用现有资源。
  • 若未大量审视数据,方法即有误:深入且广泛地观察数据是正确评估的前提。
  • 不要依赖通用评估框架衡量AI质量:针对具体问题定制专属评估系统。
  • 编写大量测试,并定期更新:确保测试覆盖度广且紧跟产品变化。
  • 利用LLMs助力构建评估系统:如用于生成测试案例、编写断言、生成合成数据、批判与标注数据等。
  • 复用评估基础设施进行调试与微调:将评估系统作为调试工具及微调数据集构建的基础。


END











Lilac:https://www.lilacml.com/
natural language query generator:https://www.honeycomb.io/blog/introducing-query-assistant
Eppo blog:https://www.geteppo.com/blog
Jason Liu:https://jxnl.github.io/blog/writing/2024/02/28/levels-of-complexity-rag-applications/

联系我们

售前咨询
186 6662 7370
产品演示
185 8882 0121

微信扫码

与创始人交个朋友

回到顶部

 
扫码咨询