1. 为什么我要用 Claude 来设计 eval
第一次听到“用 Claude 设计 eval,再一轮轮把分数提上去”这个说法时,我脑子里冒出来的第一个念头是:这不就是让模型自己出题考自己吗?听起来有点自娱自乐。但真正动手跑过几轮之后,我发现这套思路其实非常务实,甚至可以说是目前做 AI 应用迭代最省力的一条路径。
先把话说清楚:这里的eval不是学术意义上的 benchmark,而是你自己业务场景下的一套评分标准加测试集。它要回答的问题很具体——我改了一版 prompt、换了一个模型、调了一组参数,效果到底是变好了还是变差了?如果没有 eval,你只能靠“感觉好像好一点”来判断,这种判断在迭代三五轮之后基本就失效了,因为你会记不清上一版到底长什么样。
hillclimb这个词直译是“爬山”,在优化领域指的是沿着当前最优方向小步前进,每一步都要求分数不下降。放到 eval 迭代里,就是:先有一个基线分数,然后每次只改一个变量,跑完 eval 看分数,涨了就保留,跌了就回滚。听起来很笨,但它是最不容易翻车的方法。
那 Claude 在里面扮演什么角色?我的用法是把它当成一个“出题人 + 阅卷人 + 改卷人”的三合一助手。出题,是让它根据我的业务描述生成测试用例;阅卷,是让它按照我定义的评分维度给回答打分;改卷,是让它分析低分案例,告诉我问题出在哪、下一轮该往哪个方向改。这三件事如果全靠人工做,一个中等规模的 eval 集(比如 100 条)跑一轮就要大半天,而用 Claude 辅助,半小时内就能拿到结构化的分析结果。
这套方法适合谁?我觉得三类人最需要:一是正在做 AI 应用但还没建立 eval 体系的开发者;二是已经有 eval 但分数卡住不动、不知道怎么继续提的人;三是想系统学习 prompt 工程和模型评估的爱好者。哪怕你只是用 Claude 写写文案、做做总结,这套思路也能帮你把“哪个版本更好”这件事从玄学变成可量化的判断。
需要提前说明的是,下面讲的所有操作细节,都是基于我自己的实践总结出来的常见做法,不是官方文档的照搬。Claude 的 API 和界面一直在变,具体参数以你实际使用的版本为准,但底层的思路是通用的。
2. 整体设计思路:把 eval 当成一个可迭代的产品
2.1 先想清楚 eval 要衡量什么
很多人一上来就开始写测试用例,写了五十条之后发现根本没法打分,因为标准不统一。我的经验是,动手之前先花二十分钟把“评分维度”定下来。所谓评分维度,就是你到底在乎回答的哪些方面。
举个我实际做过的例子。我当时在做一个技术文档问答助手,用户问一个问题,助手要从文档里找答案并组织成自然语言。我在乎的维度有三个:准确性(答案和文档是否一致,有没有编造)、完整性(有没有漏掉关键步骤)、可读性(表达是否通顺、结构是否清晰)。这三个维度不是拍脑袋想的,而是从用户反馈里提炼出来的——用户抱怨最多的就是“答非所问”“漏步骤”“看不懂”。
维度定好之后,每个维度给一个 1 到 5 分的评分标准。这里有个坑:不要用“好/中/差”这种模糊描述,要写成可判断的具体条件。比如准确性这一维,5 分是“答案完全来自文档且无编造”,3 分是“主体正确但有轻微表述偏差”,1 分是“出现文档中不存在的信息”。标准写得越具体,Claude 打分时的一致性就越高。
提示:评分维度不要超过五个。维度太多会导致打分时顾此失彼,而且总分计算会变得很复杂。三个维度是最舒服的区间。
2.2 为什么选择让 Claude 来打分
有人会问,打分这种事为什么不让规则来做?比如关键词匹配、字符串相似度。原因是自然语言的“好”很难用规则穷举。一个回答可能用词和标准答案完全不同,但意思完全正确;另一个回答可能关键词全中,但逻辑是错的。规则打分在这两种情况下都会误判。
Claude 这类模型做打分,优势在于它能理解语义。你给它一段评分标准和一个回答,它能给出接近人类判断的分数,而且比人类快得多、稳定得多。当然它也有缺点,后面会专门讲怎么控制它的“打分漂移”。
我实测下来,用 Claude 打分和人工打分的吻合度大概在 80% 到 90% 之间,剩下的差异主要集中在边界案例上。对于迭代优化来说,这个精度完全够用了,因为你要看的是趋势——这一版比上一版高了 0.3 分,这个信号是可信的。
2.3 hillclimb 的迭代节奏怎么定
hillclimb 的核心是“小步快跑”。我给自己定的规矩是:每轮只改一个变量。这个变量可以是一条 prompt 的措辞、一个 few-shot 示例、一个温度参数,但不能同时改三个。同时改多个变量,分数涨了你也不知道是哪个起了作用,分数跌了更不知道回滚哪个。
一轮的完整流程是这样的:先跑基线 eval 拿到分数,然后针对上一轮分析出的最弱环节做一处修改,再跑一次 eval,对比分数。如果涨了,保留修改,进入下一轮;如果跌了,回滚,换一个方向再试。听起来很慢,但每一轮都是有效积累,不会白跑。
我一般会把每轮的分数、修改内容、分析结论记在一个表格里。这个表格后来成了我最值钱的东西,因为它记录了哪些方向有效、哪些方向是死胡同。下次做类似项目时,直接翻这个表就能少走很多弯路。
3. 核心细节解析:eval 集怎么建、分怎么打
3.1 用 Claude 生成测试用例的正确姿势
让 Claude 生成测试用例,最忌讳的是只说一句“帮我生成 50 条测试问题”。这样出来的问题要么太泛,要么重复,要么难度分布不合理。我的做法是给 Claude 一个结构化的指令,包含四个要素:场景描述、问题类型分布、难度分布、输出格式。
场景描述就是告诉它这个助手是干什么的、面向什么用户。问题类型分布是指你要覆盖哪些类别,比如事实查询、步骤操作、对比分析、边界情况。难度分布是指简单、中等、困难各占多少比例。输出格式我一般要求它输出 JSON,每条包含问题、预期答案要点、难度标签、类型标签。
这里有个实操技巧:先让 Claude 生成 20 条,人工过一遍,把好的留下、差的删掉,然后把留下的作为示例,再让它生成更多。这叫 few-shot 生成,出来的质量比一次性生成 100 条高得多。我试过直接生成 100 条,最后能用的不到 40 条;用 few-shot 的方式,能用率能到 70% 以上。
还有一个细节:生成完之后一定要人工抽查。Claude 偶尔会生成一些看起来合理但实际有问题的用例,比如问题本身有歧义、预期答案和文档不符。抽查比例我一般控制在 20% 左右,发现问题的批次就整批重做。
3.2 评分 prompt 怎么写才稳定
评分 prompt 是整个 eval 体系里最需要打磨的部分。我踩过的坑是:一开始写得太简单,Claude 打分忽高忽低,同一份回答跑两次能差 1 分。后来我把评分 prompt 拆成了四个部分,稳定性明显提升。
第一部分是角色设定,告诉它“你是一个严格的技术文档评审员”。第二部分是评分维度及标准,把每个维度的 1 到 5 分具体条件列清楚。第三部分是待评内容,包括原始问题、参考文档片段、待评回答。第四部分是输出格式,要求它输出每个维度的分数、理由,以及一个总分。
关键点在于理由必须写在分数前面。如果让 Claude 先给分数再写理由,它往往会先定一个分数然后硬凑理由;反过来先写理由再给分数,分数会更贴合实际分析。这个顺序上的小改动,是我试了十几版 prompt 之后才发现的,效果立竿见影。
另外,评分标准里要明确写出“扣分项”和“加分项”。比如准确性维度,出现编造信息直接扣到 1 分,这是扣分项;完整性维度,主动补充了相关背景知识可以加 0.5 分,这是加分项。有了明确的加减分规则,Claude 的判断会更有依据。
3.3 控制打分漂移的三个手段
打分漂移是指同一个回答在不同时间被打出不同分数。这个问题在长周期迭代里很致命,因为你会分不清分数变化是来自你的修改还是来自 Claude 的随机性。我用了三个手段来控制它。
第一个手段是固定评分 prompt 版本。每次改评分 prompt 都要记录版本号,对比分数时确保用的是同一版本。如果中途改了评分标准,那前后的分数就不可比了,需要重新跑基线。
第二个手段是设置温度参数为 0。如果通过 API 调用,把 temperature 设成 0,让输出尽可能确定。如果是在对话界面里用,就尽量在同一会话里连续打分,减少上下文差异带来的波动。
第三个手段是锚定样本。在 eval 集里固定放几条“锚点”用例,它们的分数应该是稳定的。每轮跑完 eval,先看这几条锚点的分数有没有异常波动。如果锚点分数都飘了,说明评分系统本身出了问题,这轮的分数就不可信。
注意:如果发现锚点分数连续两轮都在飘,不要急着改 prompt,先检查是不是 Claude 的版本更新了。模型更新会带来打分习惯的变化,这时候需要重新校准评分标准。
4. 实操过程:从零到跑通第一轮 eval
4.1 环境准备与调用方式选择
动手之前先确定你用什么方式调用 Claude。三种常见方式:网页对话界面、API、以及各类集成开发环境里的插件。我的建议是,如果 eval 集在 30 条以内,用网页界面手动跑也能接受;超过 30 条,强烈建议走 API,因为手动复制粘贴太容易出错,而且没法批量处理。
走 API 的话,你需要准备一个 API key,然后写一个简单的脚本。脚本的逻辑不复杂:读取 eval 集(JSON 格式),逐条调用 Claude,把回答和评分结果写回文件。我用 Python 写的,核心就是几十行代码,主要时间花在处理异常和重试上。
如果你不熟悉编程,也有折中方案:用表格软件把 eval 集整理好,然后一条条粘贴到对话界面里,把结果粘贴回表格。这种方式慢,但胜在零门槛。我早期就是这么干的,跑 50 条大概要一个多小时,后来才转成脚本。
4.2 第一轮基线 eval 的完整流程
第一轮的目标不是拿高分,而是建立一个可信的基线。具体步骤是这样的:
- 准备好 eval 集文件,确认每条用例都有问题、参考要点、难度标签。
- 准备好评分 prompt,确认维度、标准、输出格式都写清楚了。
- 先拿 5 条用例试跑,检查评分结果是否符合预期。如果这 5 条的打分明显不合理,说明评分 prompt 有问题,先改 prompt 再继续。
- 试跑通过后,跑完整 eval 集,记录每条的总分和各维度分数。
- 计算平均分、各维度平均分、以及分数分布(有多少条是低分、多少条是高分)。
我第一次跑基线时,平均分只有 2.8 分(满分 5 分),低分用例占了将近一半。当时有点沮丧,但后来发现这是好事——基线低说明提升空间大,而且低分用例正好指出了最需要改的地方。
4.3 分析低分案例,找到第一个改进点
跑完基线后,不要急着改 prompt。先花时间看低分案例,找出出现频率最高的失败模式。我的做法是把所有低于 3 分的用例挑出来,逐条看 Claude 给的理由,然后归类。
比如我当时发现,低分案例里有六成是“完整性问题”——回答漏掉了文档里的关键步骤。进一步看,这些漏步骤的问题又集中在一个类型上:当文档里的步骤超过五步时,助手倾向于只回答前三步。这就是一个非常具体的失败模式,比笼统的“完整性不好”有用得多。
找到失败模式后,改进方向就清晰了:针对“长步骤漏答”这个问题,我可以在 prompt 里加一条指令,要求助手在回答步骤类问题时,先列出所有步骤的标题,再逐条展开。这就是第一轮要改的唯一变量。
4.4 跑第二轮 eval 并对比分数
改完 prompt 后,重新跑一遍完整的 eval 集。这里有个细节:要用同一套评分 prompt 和同一个温度参数,否则分数不可比。跑完后,把第二轮的总分和第一轮对比,同时看各维度的变化。
我第二轮跑完,平均分从 2.8 涨到了 3.2,完整性维度从 2.5 涨到了 3.1,其他维度基本没变。这说明我的修改方向是对的,而且没有引入副作用。如果发现准确性维度反而跌了,那就要警惕——可能是新加的指令让助手为了凑步骤而编造内容。
对比分数时,不要只看平均分。平均分涨了 0.4,但如果有几条用例的分数暴跌,那也是有问题的。我一般会看三个指标:平均分、最低分、以及分数标准差。标准差变大说明回答质量变得不稳定,这往往比平均分低更麻烦。
5. 常见问题与排查技巧实录
5.1 分数卡住不动怎么办
迭代到一定轮次后,分数往往会进入平台期,怎么改都不涨。我遇到过两次这种情况,后来总结出三个排查方向。
第一个方向是检查 eval 集本身。有时候不是模型不行,而是 eval 集里有几条用例本身就有问题——问题有歧义、参考要点不准确、或者难度远超当前能力。把这几条挑出来修正或剔除,分数可能立刻就上去了。
第二个方向是换维度看问题。总分卡住,但某个维度可能还有提升空间。比如总分卡在 3.5,但可读性维度只有 3.0,那就可以专门针对可读性做优化,把这一维提上去,总分自然跟着涨。
第三个方向是跳出 prompt 层面。如果 prompt 已经改了很多轮都没效果,可能是模型能力到顶了,或者需要引入外部知识(比如检索增强)。这时候继续在 prompt 上抠字眼是浪费时间,应该考虑换方案。
5.2 Claude 打分和人工判断不一致怎么处理
这种情况很常见,尤其是边界案例。我的处理原则是:以人工判断为准,但要把人工判断的标准反哺到评分 prompt 里。
具体做法是,当发现某条用例 Claude 打了 4 分但你觉得只有 2 分时,不要直接改分数,而是去分析为什么 Claude 会打高分。通常是因为评分标准里没有覆盖到这个问题。比如 Claude 觉得回答“结构清晰”所以给了高分,但你觉得内容本身是错的,结构再清晰也没用。这时候就要在评分标准里加一条:内容准确性是前置条件,准确性低于 3 分时,其他维度最高只能给 3 分。
这种“一票否决”规则在评分 prompt 里非常有用,能有效防止 Claude 被表面质量迷惑。
5.3 常见问题速查表
| 问题现象 | 可能原因 | 排查动作 |
|---|---|---|
| 同一回答两次打分差 1 分以上 | 温度参数不为 0,或评分 prompt 有歧义 | 检查 temperature 设置,细化评分标准 |
| 平均分涨了但用户反馈变差 | eval 集不能代表真实场景 | 补充真实用户问题到 eval 集 |
| 某条用例反复低分,怎么改都不行 | 用例本身有问题,或超出模型能力 | 人工复核用例,必要时剔除 |
| 分数突然整体下跌 | 模型版本更新或评分 prompt 被误改 | 检查版本记录,重跑锚点用例 |
| 低分案例集中在某一类型 | 该类型是当前系统的薄弱环节 | 针对该类型做专项优化 |
5.4 几个我踩过的坑
第一个坑是eval 集泄露。我早期图省事,把 eval 集里的问题直接写进了 prompt 的示例里。结果分数虚高,因为模型相当于提前看过答案。后来我把示例和 eval 集严格分开,示例用另外生成的问题,分数才回归真实。
第二个坑是过度优化单一维度。有一轮我死磕准确性,把 prompt 改得非常保守,结果准确性上去了,但可读性暴跌,回答变得像机器翻译。这提醒我,优化时要盯着所有维度,不能顾此失彼。
第三个坑是忽略成本。跑一轮 eval 如果走 API,100 条用例大概要花几块钱。迭代几十轮下来,成本不算小。后来我学会了先用 20 条的小集快速验证方向,方向确认了再用全量集跑,省了不少钱。
6. 把 eval 迭代变成长期习惯
6.1 建立版本管理和记录习惯
迭代到后面,你会发现最大的敌人不是技术问题,而是“记不清”。记不清上一版 prompt 长什么样、记不清哪轮改了什么、记不清哪个方向试过了。所以从第一轮开始就要建立记录习惯。
我的记录分三块:prompt 版本表(版本号、修改内容、修改日期)、eval 分数表(轮次、平均分、各维度分、备注)、失败模式库(失败类型、出现频率、已尝试的解决方案、效果)。这三块记录用最简单的表格工具就行,关键是坚持记。
有了这些记录,你随时可以回到任何一个历史版本,也可以清楚地看到自己的优化轨迹。我后来做新项目时,直接翻旧项目的失败模式库,很多坑就不用再踩一遍了。
6.2 eval 集的持续扩充
eval 集不是建一次就完事了。随着系统能力提升,原来的难题会变成简单题,eval 集的区分度会下降。所以要定期往里面加新用例,尤其是真实用户提出的、当前系统答不好的问题。
我一般每迭代五轮就做一次 eval 集扩充,从真实使用记录里挑 10 到 20 条有代表性的问题加进去。加完之后重新跑基线,看看新用例的分数分布。如果新用例普遍低分,说明系统还有明显的短板;如果新用例分数和旧用例差不多,说明系统泛化能力还不错。
扩充 eval 集时要注意保持难度分布。如果新加的全是难题,平均分会掉,但这不代表系统变差了,只是 eval 集变难了。所以每次扩充后要重新校准基线,不能拿新旧分数直接比。
6.3 什么时候该停止迭代
这个问题没有标准答案,但有几个信号可以参考。一是边际收益递减:连续三轮修改,分数涨幅都小于 0.1,说明当前方案已经接近上限。二是成本超过收益:继续优化的投入已经大于它能带来的实际价值。三是用户反馈稳定:真实用户不再抱怨明显问题,说明系统已经达到可用水平。
我自己的习惯是,当平均分达到 4.2 以上、且最低分不低于 3 分时,就基本停止大规模迭代,转入维护状态。后续只在发现新的失败模式时才做针对性优化。毕竟 eval 分数只是手段,让真实用户满意才是目的。
最后分享一个我一直在用的小技巧:每次迭代开始时,先花五分钟重读上一轮的失败模式库。这个动作看起来多余,但它能帮你快速回到上下文,避免重复劳动。我试过跳过这一步,结果有一轮改了半天,最后发现这个方向两轮前就试过且无效。从那以后,我再也没跳过这五分钟。