1. 为什么我要用 Claude 来设计 eval
第一次认真做 eval 是两年前,当时手头有个分类任务,模型离线指标看着挺漂亮,上线之后用户投诉却一堆。回头一查,发现我那个测试集是从训练数据里随手切出来的,分布跟真实流量差了十万八千里。那次教训让我彻底明白一件事:模型能力是一回事,你能不能量出来它是另一回事。eval 做不好,后面所有的调优、迭代、上线决策全是拍脑袋。
后来我把 eval 当成一个独立项目来做,而不是训练脚本里的一个附属函数。这个转变带来的收益远超预期。而真正让效率起飞的关键,是我开始用 Claude 来帮我设计 eval、生成测试用例、分析失败样本,然后一轮一轮把分数往上爬。
这套方法的核心逻辑其实很朴素:eval 本身也是一个需要迭代的系统。你不可能一次写出完美的测试集和评分标准,就像你不可能一次训出完美的模型。既然要迭代,那就需要一个能快速产出、快速反馈、快速修正的循环。Claude 在这个循环里扮演的角色,是一个不知疲倦的、有一定判断力的协作者——它能帮你把脑子里模糊的“好”和“坏”变成可执行的评分规则,能批量生成边界用例,能帮你分析为什么这一轮分数掉了。
这篇文章适合谁看?如果你正在做 LLM 应用、Agent 系统、或者任何需要量化评估模型输出质量的场景,并且你已经厌倦了“感觉还行”这种评价方式,那这篇内容应该能帮到你。我会从 eval 的整体设计思路讲起,然后拆解用 Claude 设计 eval 的具体操作,再讲怎么通过一轮轮迭代把分数提上去,最后分享一些我踩过的坑和排查技巧。
需要说明的是,下面提到的所有操作步骤和参数配置,都是基于我自己的实践经验总结的,不同场景下你需要根据实际情况调整。Claude 的 API 调用方式、模型版本这些细节,请以官方文档为准。
2. eval 整体设计与思路拆解
2.1 先想清楚你要量什么
很多人做 eval 的第一步是打开编辑器开始写测试用例,这是错的。第一步应该是坐下来想清楚:你到底要量什么。
我见过太多 eval 项目失败在起点上——测试集里塞了一堆“看起来相关”的问题,但这些问题跟实际业务目标没有直接关系。比如你做一个客服问答系统,测试集里全是通用知识问答,那这个 eval 分数再高也没意义。
我的做法是先定义清楚三个东西:
- 任务边界:模型在这个场景下要做什么、不做什么。比如客服问答,模型只需要回答产品相关问题,对于竞品对比、价格谈判这类问题应该拒答或转人工。
- 成功标准:什么样的输出算“好”。这个标准要具体到可以写成评分规则的程度。比如“回答准确”太模糊,“回答中提到的产品参数与知识库一致”才可操作。
- 失败模式:你最怕模型犯什么错。是胡编乱造?是答非所问?是语气不当?把这些失败模式列出来,它们就是你 eval 的重点关注对象。
这三个东西想清楚之后,你才知道 eval 应该覆盖哪些维度、每个维度的权重怎么分配。
2.2 为什么选择用 Claude 来辅助设计
市面上能用的模型不少,我选 Claude 做 eval 辅助有几个实际原因。
第一是长上下文能力。设计 eval 的时候经常需要把大量参考资料、历史对话、评分标准一起塞进 prompt 里,Claude 在这方面的表现比较稳定,不容易因为上下文长了就丢信息。
第二是指令遵循的细腻度。eval 的评分规则往往有很多边界条件,比如“如果回答中包含了正确信息但语气过于生硬,扣 0.5 分而不是 1 分”。这种细粒度的规则,Claude 执行起来比很多模型要靠谱。
第三是生成多样性。让 Claude 批量生成测试用例的时候,它给出的边界案例质量明显更高,不会翻来覆去就是那几种套路。
当然,这不是说其他模型不能用。核心思路是一样的:找一个指令遵循好、上下文窗口大、生成质量稳定的模型来当你的 eval 协作者。Claude 只是我目前用下来最顺手的。
2.3 eval 系统的三层结构
我把 eval 系统分成三层,这个结构在后面迭代的时候会反复用到:
第一层是测试用例集。这是 eval 的原材料,包含输入和期望输出(或者期望的输出特征)。测试用例的质量直接决定了 eval 的上限。
第二层是评分器。评分器负责把模型输出和期望输出做对比,给出分数。评分器可以是基于规则的(比如关键词匹配、正则表达式),也可以是基于模型的(让另一个模型来打分),还可以是混合的。
第三层是聚合与报告。把单个用例的分数聚合成整体指标,并且能按维度拆解,让你知道模型在哪个方面强、哪个方面弱。
这三层里,第一层和第二层是 Claude 能帮上大忙的地方。第三层更多是工程实现,Claude 的参与度相对低一些。
2.4 迭代循环的设计
整个迭代循环长这样:
- 用 Claude 生成初始测试用例集和评分规则
- 跑一遍 eval,拿到基线分数
- 分析失败样本,找出分数低的原因
- 判断是测试用例的问题、评分规则的问题、还是模型本身的问题
- 针对性地修正,然后回到第 2 步
这个循环听起来简单,但实际操作中有很多细节。比如第 4 步的判断就很容易出错——很多人一看到分数低就想着去调模型,但实际上很多时候是评分规则太严或者测试用例本身有问题。
我的一般原则是:先怀疑 eval,再怀疑模型。因为 eval 是你自己设计的,出错的概率远高于一个已经训练好的模型。
3. 用 Claude 设计 eval 的核心细节与实操要点
3.1 怎么让 Claude 理解你的评估需求
跟 Claude 协作设计 eval,最关键的一步是把你脑子里的评估需求准确地传达给它。我试过很多种方式,最后总结出一个比较有效的 prompt 结构:
你是一个 eval 设计专家。我需要你帮我设计一套评估方案。 ## 任务背景 [描述你的任务是什么,模型需要做什么] ## 成功标准 [描述什么样的输出算好,越具体越好] ## 失败模式 [列出你最怕模型犯的错误] ## 输出要求 请帮我生成: 1. 评估维度列表,每个维度附上权重建议 2. 每个维度的具体评分规则 3. 每个维度的示例测试用例(至少 5 个)这个结构的关键在于成功标准和失败模式要写得足够具体。我一开始写得很笼统,Claude 生成的评分规则也很笼统。后来我把成功标准细化到“回答中必须包含知识库中对应的产品参数,且参数值完全一致”,Claude 生成的评分规则就变得非常可操作了。
还有一个技巧是给 Claude 提供反面例子。比如你告诉它“下面这些是我不希望看到的输出”,然后给几个具体的 bad case。Claude 对反面例子的理解往往比正面描述更准确,生成的评分规则也更能抓住你真正在意的点。
3.2 生成测试用例的批量操作
初始测试用例集不需要很多,20 到 50 条就够了。重要的是覆盖面,而不是数量。我一般会让 Claude 按下面的维度来生成:
- 典型场景:最常见的用户输入,占 40% 左右
- 边界场景:输入很短、很长、有歧义、包含多个意图的情况,占 30% 左右
- 对抗场景:故意诱导模型犯错的输入,占 20% 左右
- 拒答场景:模型应该拒绝回答的情况,占 10% 左右
让 Claude 生成的时候,我会给它一个具体的格式要求:
请按以下 JSON 格式输出测试用例: { "id": "case_001", "category": "typical", "input": "用户输入内容", "expected_output": "期望的输出内容或输出特征", "scoring_notes": "这个用例的评分要点" }用 JSON 格式的好处是后面可以直接程序化处理,不用手动整理。Claude 生成 JSON 的稳定性还不错,偶尔会有格式问题,加一句“请确保输出是合法的 JSON,不要包含注释”就能解决大部分情况。
生成完之后,一定要人工过一遍。Claude 生成的用例大部分是合理的,但总有一些跟你的实际场景不符。我一般会删掉 10% 到 20% 的用例,然后手动补充一些 Claude 没想到的场景。
3.3 评分规则的设计要点
评分规则是 eval 系统里最容易出问题的地方。我踩过的坑包括:规则太模糊导致评分不稳定、规则太严格导致所有输出都低分、规则之间有冲突导致无法同时满足。
用 Claude 设计评分规则的时候,我会要求它遵循几个原则:
可操作性:每条规则都能对应到一个具体的判断动作。比如“回答准确”不可操作,“回答中的产品价格与知识库一致”可操作。
独立性:不同维度的规则之间尽量不重叠。如果两个维度都在衡量“准确性”,那它们应该合并。
可区分性:规则要能区分出“好”和“一般”和“差”。如果一条规则只有 0 分和 1 分两个档位,那它很难反映输出的细微质量差异。我一般会用 0 到 5 分的五档评分,或者 0、0.5、1 的三档评分。
权重合理:不同维度的权重应该反映它们在实际场景中的重要程度。比如客服场景里,“准确性”的权重应该远高于“语气友好度”。
下面是一个评分规则的示例,展示一下我实际用的格式:
| 维度 | 权重 | 评分标准 |
|---|---|---|
| 信息准确性 | 40% | 5分:所有信息与知识库一致;3分:主要信息正确但有细节偏差;1分:关键信息错误;0分:完全错误 |
| 完整性 | 25% | 5分:覆盖用户问题的所有方面;3分:覆盖主要方面但遗漏次要信息;1分:只覆盖部分;0分:答非所问 |
| 语气适当性 | 20% | 5分:专业且友好;3分:专业但生硬;1分:语气不当;0分:冒犯性内容 |
| 格式规范性 | 15% | 5分:格式完全符合要求;3分:基本符合但有 minor 问题;1分:格式混乱;0分:完全不符合 |
这个表格是 Claude 生成的初版,我调整了权重和部分评分描述。权重调整是最需要人工介入的地方,因为只有你知道在实际业务里哪个维度更重要。
3.4 用 Claude 做评分器的注意事项
除了设计 eval,Claude 本身也可以当评分器用。让 Claude 根据评分规则给模型输出打分,这在很多场景下比基于规则的评分器更灵活。
但用 Claude 做评分器有几个坑要注意:
评分一致性:同一个输出,Claude 两次打分可能不一样。我实测下来,温度设为 0 的时候一致性最好,但也不是 100% 稳定。对于关键评估,我会让 Claude 对同一个输出打三次分,取平均值。
评分偏差:Claude 倾向于给“看起来合理”的输出打高分,即使这个输出实际上有事实错误。解决办法是在 prompt 里明确要求它“先检查事实准确性,再评估其他维度”,并且给它提供事实核查的参考资料。
成本控制:如果测试集很大,用 Claude 逐条打分成本不低。我的做法是先用基于规则的评分器做初筛,只对规则评分器不确定的样本调用 Claude 评分。
prompt 设计:评分 prompt 里一定要包含评分规则、评分示例(few-shot)、以及输出格式要求。我一般会给每个分数档位配一个示例输出,这样 Claude 打分更稳定。
4. 一轮轮把分数提上去的实操过程
4.1 建立基线:第一轮 eval 怎么跑
第一轮 eval 的目标不是拿高分,而是建立一个可比较的基线。所以第一轮不要做任何调优,就用最原始的模型和 prompt 跑一遍,看看分数是多少。
我第一轮跑的时候,整体分数只有 2.8 分(满分 5 分)。这个分数本身不重要,重要的是分维度的分数。我当时的分布是这样的:
- 信息准确性:3.2 分
- 完整性:2.1 分
- 语气适当性:3.8 分
- 格式规范性:2.5 分
一眼就能看出来,完整性和格式规范性是短板。这就给后面的迭代指明了方向。
第一轮跑完之后,我会做一件事:把每个维度的最低分样本挑出来,人工看一遍。这一步非常关键,因为分数只告诉你“哪里差”,不告诉你“为什么差”。人工看样本才能发现真正的问题。
4.2 分析失败样本:找到分数低的真正原因
我挑出完整性维度最低的 10 个样本,逐个分析。发现的问题主要有三类:
第一类是模型确实漏掉了信息。比如用户问了三个问题,模型只回答了前两个。这是模型能力问题。
第二类是评分规则太严。比如用户问“这个产品支持哪些支付方式”,模型回答了“支持微信和支付宝”,但评分规则要求“必须列出所有支付方式包括银行卡”,而知识库里其实只写了微信和支付宝。这是评分规则的问题。
第三类是测试用例本身有问题。比如有个用例的期望输出写错了,导致模型回答正确却被判低分。
这三类问题的处理方式完全不同。第一类需要调模型或改 prompt,第二类需要改评分规则,第三类需要修测试用例。如果不做这个分析,直接去调模型,那第二类和第三类问题永远解决不了,分数也永远提不上去。
4.3 修正 eval 本身:先让尺子准起来
分析完失败样本之后,我的第一轮修正全部集中在 eval 本身,而不是模型。
具体做了这几件事:
修正测试用例:把期望输出写错的用例改对,把跟实际场景不符的用例删掉,补充了一些遗漏的场景。这一轮改了大概 15% 的用例。
调整评分规则:把过于严格的规则放宽,把模糊的规则改具体。比如完整性维度,原来要求“覆盖所有方面”,改成了“覆盖主要方面即可得 4 分,覆盖所有方面得 5 分”。这一轮改了大概 30% 的评分规则。
统一评分尺度:让 Claude 对一批样本重新打分,然后人工核对,确保评分尺度一致。这一步花了不少时间,但非常值得,因为评分尺度不一致的话,后面的分数变化就没有意义了。
修正完 eval 之后,重新跑一遍。分数从 2.8 变成了 3.1。这个提升完全来自 eval 本身的修正,模型没有任何变化。
这里有一个很重要的心态:不要害怕花时间修 eval。很多人觉得修 eval 不是“正经工作”,不如去调模型来得有成就感。但实际上,eval 不准的话,你调模型就是盲调,今天分数涨了明天可能又跌了,你根本不知道发生了什么。
4.4 优化模型输出:prompt 调整与迭代
eval 修正到比较可靠之后,才开始动模型。我优化模型输出的手段主要有三个:改 prompt、加 few-shot 示例、调生成参数。
改 prompt是最直接的。针对完整性维度低的问题,我在 prompt 里加了一句“请确保回答覆盖用户问题的所有方面,如果有多个问题请逐一回答”。这一句话让完整性分数从 2.1 提到了 3.0。
加 few-shot 示例对格式规范性特别有效。我在 prompt 里加了两个格式完美的回答示例,格式规范性分数从 2.5 提到了 4.2。
调生成参数主要是调温度和最大长度。温度从 0.7 降到 0.3 之后,输出的稳定性明显提升,信息准确性分数从 3.2 提到了 3.6。最大长度从 500 提到 800 之后,完整性分数又涨了一点,因为模型不再因为长度限制而截断回答了。
这一轮下来,整体分数从 3.1 提到了 3.9。每一轮改动之后我都会重新跑 eval,记录分数变化。下面是我记录的迭代日志:
| 轮次 | 改动内容 | 整体分数 | 准确性 | 完整性 | 语气 | 格式 |
|---|---|---|---|---|---|---|
| 基线 | 无 | 2.8 | 3.2 | 2.1 | 3.8 | 2.5 |
| 第1轮 | 修正 eval | 3.1 | 3.3 | 2.5 | 3.8 | 2.8 |
| 第2轮 | 改 prompt | 3.5 | 3.4 | 3.0 | 3.9 | 3.5 |
| 第3轮 | 加 few-shot | 3.8 | 3.5 | 3.2 | 4.0 | 4.2 |
| 第4轮 | 调参数 | 3.9 | 3.6 | 3.4 | 4.0 | 4.2 |
这个日志看起来简单,但每一轮背后都有大量的分析和尝试。而且不是每一轮都涨分,我有好几次改完之后分数反而掉了,然后回滚重新想。
4.5 用 Claude 做 hillclimb:自动化迭代
手动迭代到 3.9 之后,提升速度明显变慢了。这时候我开始尝试用 Claude 做半自动化的 hillclimb。
具体做法是:让 Claude 分析失败样本,提出 prompt 修改建议,然后我批量测试这些建议,保留有效的,丢弃无效的。
流程大概是这样:
- 把当前分数最低的 20 个样本和对应的模型输出、评分结果整理成一份报告
- 让 Claude 分析这些失败样本,找出共同模式,提出 3 到 5 个 prompt 修改建议
- 对每个建议,生成一个修改后的 prompt 版本
- 用每个版本跑一遍 eval,记录分数
- 保留分数最高的版本,如果都不如当前版本,就保留当前版本
这个流程跑一轮大概需要 30 分钟到 1 小时,取决于测试集大小和 API 响应速度。我跑了大概 10 轮,分数从 3.9 提到了 4.3。
Claude 提出的建议里,有些是我自己想不到的。比如它发现模型在回答包含数字的问题时容易出错,建议在 prompt 里加一句“涉及数字时请仔细核对,必要时在回答中标注数据来源”。这个建议让准确性分数又涨了 0.2。
但也有很多建议是无效的,甚至有害的。比如它建议“在回答末尾添加总结段落”,这导致格式规范性分数下降,因为总结段落经常跟正文重复。所以人工筛选是必须的,不能完全放手让 Claude 自动改。
4.6 分数卡住了怎么办:进阶排查思路
分数提到 4.3 之后,又卡住了。这时候常规的 prompt 调整已经没什么效果了。我用了几个进阶的排查思路:
分维度交叉分析:把准确性和完整性做交叉,看看是不是存在“准确但不完整”或者“完整但不准确”的样本群。果然发现有一批样本,模型为了追求完整性而牺牲了准确性,回答里塞了很多不相关的信息。
错误类型聚类:把失败样本按错误类型聚类,发现有一类错误是“模型正确理解了问题但选择了错误的回答策略”。比如用户问“这个功能怎么用”,模型给了一个很长的功能说明,但用户其实想要的是操作步骤。这类问题不是 prompt 能解决的,需要在系统层面做意图识别和路由。
测试集难度分层:把测试集按难度分成简单、中等、困难三层,分别看分数。发现简单和中等样本的分数已经很高了,但困难样本的分数一直上不去。这说明模型的瓶颈在复杂场景的处理能力上,需要更根本的改进。
对比不同模型:用同样的 eval 跑了一下其他模型,发现有些模型在特定维度上表现更好。这不一定意味着要换模型,但可以借鉴那些模型的处理方式,比如它们的输出格式、回答结构等。
这些排查思路帮我找到了新的优化方向,分数又从 4.3 提到了 4.5。但越往上提越难,从 4.5 到 4.6 花的时间比从 2.8 到 4.3 还多。
5. 常见问题与排查技巧实录
5.1 评分不一致怎么办
这是最常见的问题。同一个输出,两次评分结果不一样,或者不同评分器给出的分数差异很大。
排查思路:
- 先检查评分规则是否足够具体。模糊的规则必然导致不一致。
- 检查评分 prompt 里是否有足够的示例。few-shot 示例能显著提升一致性。
- 把温度设为 0,减少随机性。
- 如果还是不一致,考虑用多个评分器取平均,或者用规则评分器做初筛。
我实测下来,规则评分器的一致性最好,但灵活性最差。模型评分器灵活性好,但一致性差。混合方案是比较好的折中:规则评分器处理明确的对错判断,模型评分器处理需要理解语义的判断。
5.2 测试集过拟合了怎么办
当你发现模型在测试集上分数很高,但实际使用中效果不好,很可能就是测试集过拟合了。
原因通常是测试集太小、太单一,或者你在迭代过程中不自觉地针对测试集做了优化。
解决办法:
- 定期用新数据替换一部分测试集。我一般每个月会替换 20% 的测试用例。
- 保留一个“从未用于迭代”的 hold-out 测试集,只在最终评估时使用。
- 让 Claude 生成一些跟现有测试集风格差异较大的用例,专门用来检测过拟合。
5.3 分数上不去但不知道问题在哪
这是最让人头疼的情况。我的排查清单是这样的:
| 排查项 | 检查方法 | 常见问题 |
|---|---|---|
| 测试用例质量 | 人工抽查 20 个用例 | 期望输出写错、场景不匹配 |
| 评分规则合理性 | 看分数分布是否过于集中 | 规则太严或太松 |
| 评分器一致性 | 同一输出多次评分 | 分数波动大 |
| 模型输出质量 | 人工看失败样本 | 确实存在能力不足 |
| prompt 有效性 | A/B 测试不同 prompt | prompt 有歧义或冲突 |
| 参数配置 | 对比不同参数下的分数 | 温度、长度等不合适 |
按这个清单逐项排查,基本能定位到问题所在。最怕的是跳过排查直接调模型,那样很可能白忙一场。
5.4 用 Claude 做 eval 的成本控制
用 Claude 做 eval 确实有成本,尤其是测试集大的时候。我的控制策略是:
- 分层评估:先用便宜的规则评分器跑全量,只对规则评分器不确定的样本调用 Claude。
- 采样评估:如果测试集超过 500 条,每次迭代只随机采样 200 条跑 eval,全量评估只在关键节点做。
- 缓存结果:相同的输入和评分规则,评分结果可以缓存,不用重复调用。
- 批量处理:把多个评分请求合并成一个请求,减少 API 调用次数。
这些策略综合下来,我的 eval 成本控制在了可接受的范围内。具体数字因场景而异,但核心思路是不要对所有样本都用最贵的评分方式。
5.5 几个我踩过的坑
坑一:评分规则太多。我一开始设计了 10 个评分维度,结果每个维度的分数都很低,因为模型不可能同时满足所有维度。后来精简到 4 个核心维度,分数反而更合理了。
坑二:测试用例太“干净”。我最初的测试用例都是精心构造的,输入很规范。但实际用户的输入往往有错别字、语法混乱、意图模糊。后来我让 Claude 专门生成了一批“脏”输入,eval 结果跟实际表现的差距小了很多。
坑三:忽略评分成本。有一次我设计了一个需要调用 Claude 三次才能完成评分的规则,测试集有 1000 条,跑一次 eval 的成本高得吓人。后来改成了规则评分器初筛加 Claude 复核的方案,成本降了 80%。
坑四:迭代太快。有一段时间我每天改好几版 prompt,分数确实在涨,但后来发现涨的全是测试集分数,实际效果没变。原因是改得太快,没有足够的时间做人工验证。后来我把迭代节奏放慢到每周一到两轮,每轮都做人工抽查,效果反而更好。
坑五:忘了记录。我有一段时间没有记录每轮改动的细节,结果后来想回滚到某个版本的时候,发现已经记不清当时改了什么。从那以后我养成了写迭代日志的习惯,每轮改动、分数变化、人工观察都记下来。这个日志后来成了我最宝贵的参考资料。
5.6 一个实用的排查技巧:分数分解
当整体分数卡住的时候,我会做一个分数分解:把整体分数按维度、按难度、按场景类型分别拆开看。
比如整体分数是 4.3,但拆开之后发现:
- 简单场景:4.8 分
- 中等场景:4.4 分
- 困难场景:3.2 分
这说明瓶颈在困难场景上。然后再看困难场景里哪个维度分数最低,假设是完整性只有 2.5 分,那就集中精力解决困难场景下的完整性问题。
这个技巧看起来简单,但非常有效。它能把“分数上不去”这个模糊的问题,变成“困难场景下完整性不足”这个具体的问题,然后你就能针对性地去解决了。
6. 一些个人体会
这套方法我用了大半年,最大的感受是:eval 不是一次性的工作,而是一个持续迭代的系统。你不可能一次写出完美的 eval,就像你不可能一次写出完美的代码。重要的是建立起“设计-评估-分析-修正”的循环,然后一轮一轮地跑下去。
Claude 在这个循环里帮了我很多,但它不是万能的。它生成的测试用例需要人工筛选,它提出的修改建议需要人工验证,它打的分数需要人工抽查。把 Claude 当成一个高效的协作者,而不是一个自动化的解决方案,这个定位很重要。
另外,分数不是越高越好。4.5 分和 4.6 分的差距,在实际业务中可能根本感知不到。与其花大量时间把分数从 4.5 提到 4.6,不如把精力放在扩大测试集覆盖面上,或者优化那些分数虽然高但实际体验不好的场景。
最后分享一个我最近在用的技巧:让 Claude 扮演“挑剔的用户”来评估输出。具体做法是在评分 prompt 里加一句“你是一个对产品质量要求极高的用户,请找出这个回答中所有可能让用户不满的地方”。这样 Claude 会更容易发现那些“看起来没问题但实际上有隐患”的输出,评分也更有区分度。这个技巧让我的 eval 在高质量样本上的区分能力提升了不少。