这篇回答一个反复出现的问题:为什么 AI 产品做完演示就停滞?答案是缺一套评测系统,而它是可以按方法论搭出来的。
最值得拿走的是三层评测的排序逻辑:单元测试便宜,每次代码变更都跑;模型与人工评测中等,按节奏跑,前提是先把轨迹日志和「看数据」的摩擦降到零;A/B 测试最贵,留给成熟产品。最容易出现误用的是两层:一是跳过单元测试直接上 LLM 评审,二是拿通用评测框架当答案——作者明确说通用框架不解决问题。
中文读者要读这篇,是因为「打地鼠」「vibe check」这些症状在国内团队同样普遍,而文中 Rechat 用数百条断言加 CI 仪表盘做评测的做法,不需要买任何新工具就能复刻。国内语境下还应补上:合成测试数据时用中文真实表达,别照搬英文模板。
读完做一件事:挑你产品的一个功能,写出三个场景和三条断言,接进 CI 跑起来。
—— FDEChina编辑部 · 犀利评审
本文介绍如何构建面向特定领域的 LLM 评测(evaluation)系统。
写作动机
我五年前开始与语言模型打交道,当时我领导的团队创建了 CodeSearchNet——GitHub Copilot 的前身。从那以后,我见过许多构建 LLM 产品的成功与失败路径。我发现失败的产品几乎共享同一个根因:没能建立稳健的评测系统。
本文最初写于我帮助各公司构建领域特定 AI 产品期间。我希望这些公司认真读完本文,能省下数千美元的咨询费。
本文概述我对「为 LLM 驱动的 AI 产品构建评测系统」这件事的思考。
快速迭代 == 成功
与软件工程一样,AI 项目的成败取决于你的迭代速度。你必须拥有覆盖以下三件事的流程与工具:
- 评估质量(例如:测试);
- 调试问题(例如:日志与数据检查);
- 改变系统行为(提示工程、微调、写代码)。
很多人只盯着第 3 件事,这让他们在做出演示之后就无法继续改进自己的 LLM 产品。¹ 把这三件事都做好,会形成一个把优秀 AI 产品与平庸产品区分开的良性循环(可视化见下图)。
如果你把评测流程理顺了,其余一切活动都会变容易。这非常像软件工程中的测试:前期投入不小,长期回报巨大。
为了让本文落到实处,我会完整走一遍一个案例研究——我们如何构建了一套能快速改进的系统。我会把重心放在评测上,因为它是最关键的组件。
案例研究:Lucy,一个房地产 AI 助手
Rechat 是一款 SaaS 应用,让房地产从业者完成各种任务:管理合同、搜索房源、制作创意素材、管理预约等等。Rechat 的核心理念是:所有事情都可以在一个地方完成,而不必在众多工具之间来回切换上下文。
Rechat 的 AI 助手 Lucy 是一个典型 AI 产品:一个会话式界面,让你不必再点击、输入和在软件里四处找功能。在 Lucy 的早期,提示工程带来了快速进展。但随着 Lucy 的功能面扩大,AI 的表现进入平台期。症状包括:
- 修好一种失败模式,别的失败模式又冒出来,像在打地鼠;
- 除了「凭感觉看看」(vibe check),对 AI 系统在各任务上的有效性缺乏可见性;
- 提示词膨胀成又长又难维护的庞然大物,试图覆盖大量边缘情况和示例。
问题:如何系统性地改进 AI?
为了打破平台期,我们为 Lucy 建立了一套以评测为中心的系统性改进方法。下图展示了我们的方法。
这张图是我尽力呈现的 AI 系统改进心智模型。实际过程是非线性的,会呈现出各种形态,未必长得和这张图一样。
下面我结合评测,讨论这套系统的各个组件。
评测的三个层级
严格、系统的评测是整个系统最重要的部分。这就是为什么图中「评测与数据策展(Eval and Curation)」被用黄色高亮在正中央。你应该把大部分时间花在让评测更稳健、更顺畅上。
有三个层级的评测需要考虑:
- 第 1 层:单元测试(Unit Tests);
- 第 2 层:模型评测与人工评测(Model & Human Eval,包含调试);
- 第 3 层:A/B 测试。
成本上第 3 层 > 第 2 层 > 第 1 层,这决定了你执行它们的节奏与方式。例如,我通常在每次代码变更时跑第 1 层评测,按固定节奏跑第 2 层,只在进行重大产品变更之后才跑第 3 层。另外,在进入基于模型的测试之前,先拿下大部分第 1 层测试会很有帮助,因为后者需要更多工作和时间来执行。
并没有一个严格公式规定何时引入哪一层测试。你要在快速获取用户反馈、管理用户感知与 AI 产品目标之间取得平衡——这与做一般产品时要做的平衡并无太大不同。
第 1 层:单元测试
LLM 的单元测试就是断言(assertion),就像你在 pytest 里写的那样。与一般单元测试不同的是,你要把这些断言组织成可以在单元测试之外使用的形式,比如数据清洗,以及模型推理期间的自动重试(用断言错误来纠偏)。关键在于:这些断言在开发应用时应当跑得快、跑得便宜,让你在每次代码变更时都能执行。如果想不出断言,就去仔细检查你的轨迹(trace)和失败模式。也别羞于让 LLM 帮你头脑风暴断言!
第 1 步:写有明确范围(scoped)的测试
思考单元测试最有效的方式,是把你的 LLM 的范围拆解成功能(feature)与场景(scenario)。例如,Lucy 的一个功能是查找房源,我们可以这样拆出场景:
功能:房源查找器(Listing Finder)
被测功能是一个函数调用,响应用户查找房源的请求,例如「请帮我找加州圣何塞 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')
}
返回给 LLM 的 CRM 结果中含有不应呈现给用户的字段,比如每条记录关联的 UUID。我们的提示词告诉 LLM 不要包含 UUID,再用一个简单的正则断言 LLM 的响应确实不含 UUID。
Rechat 有数百条这样的单元测试,并根据用户「考」AI 或产品演进时在数据中观察到的新失败持续更新。这些单元测试是你在迭代 AI 系统(提示工程、改进 RAG 等)时快速获得反馈的关键。很多人最终会「长大」到超出单元测试、转向其他层级的评测——但这一步绝不能跳过!
第 2 步:创建测试用例
要运行这些断言,你必须生成能触发所有待测场景的测试用例或输入。我经常用 LLM 合成这些输入;例如,下面是 Rechat 用来为「创建并查询联系人」功能生成合成输入的提示词:
写出 50 条不同的指令,内容是一位房地产经纪人可以让助手在 CRM 中创建联系人的话。
联系人细节可以包含姓名、电话、邮箱、伴侣姓名、生日、标签、公司、地址与职位。
每条指令都要配第二条指令,用于查找刚创建的联系人。
结果应为一个 JSON 代码块,每项只含一条字符串指令,例如:
[
["Create a contact for John ([email protected])",
"What's the email address of John Smith?"]
]
用上面的提示词,我们会生成类似这样的测试用例:
[
[
'Create a contact for John Smith ([email protected]) 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 [email protected], 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 [email protected].',
"What's the partner name of Susan Brown?"
],
...
]
对每个测试用例,我们先执行第一条用户输入创建联系人,再执行第二条查询取回该联系人。如果 CRM 没有恰好返回 1 条结果,说明创建或查询环节出了问题。我们也可以运行通用断言,比如验证响应中不含 UUID。你必须随着通过人工评测与调试观察到的数据,不断更新这些测试。关键在于:让这些测试尽可能有挑战性,同时真实代表用户与系统的交互。
你不必等生产数据才能测试系统。你可以对用户会如何使用产品做有依据的猜测并生成合成数据;也可以先让一小批用户使用产品,用他们的真实用法来改进你的合成数据生成策略。一个信号表明你写的测试和断言是好的:模型开始难以通过它们——这些失败模式会成为你日后可以用微调等技术解决的问题。
顺带一提:与传统单元测试不同,你不一定需要 100% 的通过率。通过率是一个产品决策,取决于你愿意容忍哪些失败。
第 3 步:定期运行并跟踪测试
编排第 1 层测试的方式有很多。Rechat 一直借助 CI 基础设施(如 GitHub Actions、GitLab Pipelines 等)来执行这些测试。不过,这个环节的工具还很初级,演进很快。
我的建议是:选择在你的技术栈中摩擦最小的编排方式。除了跟踪测试本身,你还需要跟踪测试结果随时间的变化,才能看出自己是否在进步。如果用 CI,你应该把指标连同测试/提示词的版本一起收集到 CI 系统之外,便于分析与跟踪。
我建议从简单开始,利用现有的分析系统来可视化测试结果。比如 Rechat 用 Metabase 跟踪 LLM 测试结果随时间的变化。在他们用 Metabase 搭建的仪表盘上,可以看到某个特定错误(黄色)在 Lucy 中被解决之前与之后的出现频率对比。
第 2 层:人工评测与模型评测
在第 1 层测试打好地基之后,你可以转向那些无法单靠断言验证的评测形式。进行人工评测与基于模型的评测,前提是先记录你的轨迹。
记录轨迹
轨迹(trace)是软件工程中由来已久的概念,指一段事件序列的日志,例如用户会话,或一个请求在分布式系统中的流转。换句话说,tracing 就是日志的逻辑分组。在 LLM 语境下,trace 通常指你与 LLM 的一次对话。比如:一条用户消息、一条 AI 回复、再来一条用户消息,就是一个 trace。
记录 LLM 轨迹的解决方案越来越多。² Rechat 用的是 LangSmith:它记录轨迹,并以人类可读的方式展示,还带一个交互式 playground 便于迭代提示词。有时记录轨迹需要给你的代码插桩(instrument)。Rechat 当时用的是 LangChain,它会自动把 trace 事件记录到 LangSmith。
我很喜欢 LangSmith——它不要求你使用 LangChain,直观易用。搜索、过滤、阅读轨迹是任何方案都必须具备的基本功能。我发现有些工具连这些基本功能都没做对!
看你的轨迹
你必须消除「看数据」这件事上的全部摩擦。这意味着要以领域特定的方式渲染轨迹。我经常发现,更好的做法是自己搭建数据查看与标注工具,把我需要的所有信息汇聚到一屏。以 Lucy 为例,我们需要看多种信息源(轨迹日志、CRM 等)才能理解 AI 做了什么——这正是需要消除的摩擦。在 Rechat 的案例里,这意味着加上这些信息:
- 当时在评测的是哪个工具(功能)与哪个场景;
- 该轨迹来自合成输入还是真实用户输入;
- 在不同「工具 × 场景」组合之间切换的过滤器;
- 当前记录在 CRM 与轨迹日志系统中的链接。
我为我做过的每个问题都搭过不同变体的这类工具。有时我甚至需要内嵌另一个应用,才能看到用户交互长什么样。另一个针对 Lucy 的设计选择:我们注意到很多失败都涉及 LLM 最终输出中的小错误(格式、内容等),于是决定让最终输出可被人工编辑,以便为微调策展和修复数据。
这类工具可以用 Gradio、Streamlit、Panel 或 Shiny 这样的轻量前端框架在一天之内搭出来。此外还有 Lilac 这类用 AI 对数据做语义搜索与过滤的工具,在调试时找出一组相似数据点极其好用。
我通常从把样本标注为「好/坏」开始。我发现打分数或更细粒度的评级,比二元标注更难管理。有一些进阶技术可以让人工评测更高效、更准确(比如主动学习、共识投票等),但我建议从简单的东西起步。最后,和单元测试一样,你应当组织并分析人工评测结果,评估自己是否在随时间进步。
正如后文所述,这些标注样本能度量系统质量、验证自动化评测,并为微调策展高质量合成数据。
该看多少数据?
我常被问该看多少数据。起步阶段,你应该看尽可能多的数据。我通常至少会读完所有测试用例生成的轨迹和用户产生的轨迹。看数据这件事永远不能停——天下没有免费的午餐。但随着时间推移,你可以更多地抽样,减轻负担。³
用 LLM 做自动化评测
很多厂商想卖给你「从此不需要人看数据」的工具。让人类定期评测至少一个样本的轨迹,是个好主意。我经常发现「正确性」在某种程度上是主观的,你必须把模型与人类对齐。
你应该跟踪基于模型的评测与人工评测之间的相关性,以决定可以在多大程度上依赖自动评测。此外,通过收集标注者解释其判断理由的评论(critique),你可以迭代评测模型,通过提示工程或微调让它与人类对齐。不过我更倾向于用提示工程做评测模型对齐。
我喜欢用 Excel 这类低技术方案来迭代「让基于模型的评测与人类对齐」。比如,针对另一个用例——一个自然语言查询生成器——我每隔几天就给同事 Phillip 发一份包含以下信息的电子表格让他评分:
- 模型响应(model response):LLM 做出的预测;
- 模型评论(model critique):由一个(通常更强的)LLM 撰写的、针对你原始 LLM 预测的评论;
- 模型结论(model outcome):评论模型给模型响应打的「好/坏」二元标签。
Phillip 然后填写他自己版本的同款信息——他的评论、结论和期望响应,每次 25-50 个例子。这些信息让我能迭代评论模型的提示词,让它随着时间与 Phillip 充分对齐。这件事也适合用电子表格这种低技术方式持续跟踪。
关于基于模型的评测的几条通用建议:
- 用你能负担得起的最强模型。要把一个东西评论好,往往需要高级的推理能力。相对于生产环境用的模型,评论输出时你常常可以接受更慢但更强的模型;
- 基于模型的评测是你更大问题中的一个元问题(meta-problem)。你必须维护一个小型评测系统来跟踪它的质量。我在这个阶段有时会微调一个模型(但我尽量不这么做);
- 把基于模型的评测器与人类对齐之后,你还必须继续定期做一致性练习,监控模型与人类的一致程度。
重要提示:把「一致率」当指标时要小心。在这个例子里,我们用模型与人类评测者之间的一致率(agreement),是因为我们的数据集大致均衡(约 50% 的样本是失败)。但在类别不均衡时,直接使用一致率通常不被推荐,而且会产生误导。更合适的做法是分别测量精确率(precision)与召回率(recall),以更准确地刻画你的评审员与人类的对齐程度。
做好一个评测模型,我最喜欢的副产品是:它的评论可以用来策展高质量合成数据,后面会提到。
第 3 层:A/B 测试
最后,做 A/B 测试总是有益的,它可以确保你的 AI 产品在驱动你期望的用户行为或结果。与其他类型的产品相比,LLM 产品的 A/B 测试没有太大不同。想深入学习 A/B 测试,我推荐阅读 Eppo 博客(由我曾经的同事创建,他们是 A/B 测试领域的顶尖高手)。
完全可以把这一层推迟到你足够确信 AI 产品适合展示给真实用户之后。这一层级的评测通常只适合更成熟的产品。
评测 RAG
除了把系统作为整体来评测,你也可以评测 AI 的子组件,比如 RAG。评测 RAG 超出了本文的范围,你可以在 Jason Liu 的文章中深入了解这个主题。
评测系统免费解锁的超能力
除了让你迭代得快,评测系统还解锁了微调与调试的能力,它们能把你的 AI 产品带上新台阶。
微调
Rechat 通过微调解决了很多单靠提示工程无法解决的失败模式。微调最适合学习语法(syntax)、风格与规则,而 RAG 这类技术则为模型提供上下文或最新事实。
微调 99% 的工作量在于组装覆盖你 AI 产品功能面的高质量数据。但如果你有像 Rechat 这样扎实的评测系统,你就已经拥有一台稳健的数据生成与策展引擎了!我会在未来的文章中展开微调流程。⁴
数据合成与策展
为了说明为什么一旦有了评测系统,数据策展与合成几乎是白送的,设想你想为前面提到的房源查找器创建更多微调数据。首先,你可以用 LLM 配合这样的提示词生成合成数据:
想象 Zillow 能解析自然语言。想出 50 种用户在上面搜索房源的方式。
使用真实的城市与社区名称。
你可以使用以下参数:
<出于保密省略>
输出应为 JSON 代码块数组。例如:
[
"Homes under $500k in New York"
]
这与生成测试用例的练习几乎一模一样!接下来,你可以用第 1 层与第 2 层测试,过滤掉未通过断言、或被评论模型判定为错误的不良数据。你也可以用现成的人工评测工具查看轨迹,为微调数据集策展轨迹。
调试
当你收到与 AI 产品相关的投诉或看到错误时,你应该能快速调试。如果你有一套稳健的评测系统,你已经拥有了:
- 一个可搜索、可过滤的轨迹数据库;
- 一套帮你标记错误与不良行为的机制(断言、测试等);
- 帮你找到错误根因的日志搜索与导航工具——根因可能是 RAG、代码 bug,或模型表现不佳;
- 针对错误做出修改并快速验证其效果的能力。
简而言之,评测所需的基础设施与调试所需的基础设施之间,存在着巨大的重叠。
结语
评测系统创造了一个让你快速迭代的飞轮。它几乎总是人们构建 AI 产品时卡住的地方。我希望这篇文章让你对如何构建自己的评测系统有了直觉。请记住以下要点:
- 消除「看数据」过程中的全部摩擦;
- 保持简单。别买花哨的 LLM 工具,先用好手头的东西;
- 如果你没有在看大量数据,你就是做错了;
- 不要依赖通用评测框架来度量你的 AI 质量,而要为你的问题创建专属的评测系统;
- 写大量测试,并频繁更新它们;
- LLM 可以用来打通评测系统的创建环节,例如:生成测试用例、编写断言、生成合成数据、评论与标注数据等;
- 把你的评测基础设施复用到调试与微调上。
如果你想系统掌握 AI 评测,我与 Shreya Shankar 合开了一门完整课程《AI Evals For Engineers & PMs》,课程会持续更新最新技术。
本文改编自我与 Emil Sedgh 和 Hugo Browne-Anderson 在 Vanishing Gradients 播客上的一次对话。感谢 Jeremy Howard、Eugene Yan、Shreya Shankar、Jeremy Lewi 与 Joseph Gleasure 审阅本文。
脚注
- 这并不是说人们懒惰。很多人只是不知道如何搭建评测系统,于是跳过了这些步骤。↩
- 例如 arize、humanloop、openllmetry 与 honeyhive。↩
- 一个合理的启发式:一直读日志,直到你感觉自己学不到新东西为止。↩
- 如果你等不及,我很快会开一门微调课程。↩
延伸阅读:如果你想动手搭建评测体系,推荐阅读站内 FDE 实践指南中的评测相关内容,以及 Agent 专题与 AI Coding 专题;想了解评测在交付流程中的位置,可看 FDE 项目生命周期。
本文由 FDEChina 团队翻译自原文,转载已注明出处;如需引用请以原文为准。