用Claude设计eval:从62分到91分的hillclimb实战

发布时间:2026/10/5 5:23:41
用Claude设计eval:从62分到91分的hillclimb实战 1. 为什么我放弃了手写测试用例转而让 Claude 来设计 eval第一次认真考虑用 Claude 来设计 eval是因为一个很具体的场景我手上有一个基于 Claude API 的文本处理工具功能是把用户零散的需求描述整理成结构化的任务清单。上线第一版之后用户反馈时好时坏——同一个输入有时候输出格式完美有时候字段缺一半有时候干脆把优先级理解成了截止时间。我一开始的做法很原始手动写了二十来条测试用例跑一遍看输出对不对。但很快问题就来了这二十条用例根本覆盖不住真实用户的输入分布而且每次改 prompt我都得重新人工核对一遍效率低到让人想砸键盘。后来我换了个思路既然 Claude 本身就能理解任务、能生成文本那为什么不让它来帮我设计 eval具体来说就是让 Claude 根据我的任务描述自动生成一批有代表性的测试输入再让它对输出做初步评判我只需要审核和修正评判标准。这个思路听起来有点用魔法打败魔法的意思但实测下来它确实把我从重复劳动里解放出来了而且覆盖度比我手写的高得多。这篇文章就是把我这套用 Claude 设计 eval再一轮轮把分数提上去的完整流程拆开讲。核心关键词是Claude、eval、claude-api、hillclimb、Claude Code——我会讲到怎么用 Claude API 批量生成测试用例怎么设计一个能自动打分的 eval 框架怎么通过一轮轮的 hillclimb爬坡式迭代把分数从 60 分推到 90 分以上以及在这个过程中 Claude Code 能帮你省掉哪些体力活。适合已经在用 Claude API 做应用、但还没建立起系统化评测流程的开发者也适合任何想给自己的 AI 应用做量化评估的人。先说结论这套方法不是银弹它有自己的边界。Claude 生成的测试用例会有盲区自动打分也会有偏差你需要人工介入校准。但相比纯手工它的效率提升是数量级的而且一旦跑通你就能像看仪表盘一样看着自己的应用分数一点点往上爬那种感觉比盲改 prompt 踏实太多了。2. 让 Claude 生成 eval 用例从任务描述到测试集的完整链路2.1 为什么不能让 Claude 随便生成用例很多人第一次尝试让 Claude 生成测试用例会直接甩一句帮我生成 50 条测试用例然后拿到一堆看起来很像但实际没用的东西。问题出在哪儿出在你没有给 Claude 足够的约束。Claude 不知道你的任务边界在哪里不知道哪些输入是合法的、哪些是边缘情况、哪些是故意刁难的对抗样本。它只能根据你给的只言片语去猜猜出来的东西自然泛泛。我的做法是把生成测试用例这件事本身也当成一个结构化任务来处理。具体来说我会给 Claude 一份详细的任务规格说明书里面包含几个关键部分任务的目标是什么、输入的数据格式和取值范围、输出的期望格式、已知的失败模式、以及我希望覆盖的用例类型分布。这份说明书不需要写得很长但每一条都得具体。举个例子还是那个需求整理工具。我会这样写任务规格任务目标把用户口语化的需求描述转换成包含任务名称、优先级、预计工时、依赖项四个字段的结构化清单。输入格式一段 50 到 500 字的中文自然语言可能包含多个需求可能包含模糊的时间表达如尽快这周内可能包含矛盾信息。输出格式JSON 数组每个元素包含上述四个字段优先级只能是高/中/低工时是整数小时。已知失败模式字段缺失、优先级判断错误、把非需求内容当成需求、JSON 格式错误。用例类型分布正常用例 40%、边缘用例 30%、对抗用例 30%。有了这份规格Claude 生成出来的用例质量会完全不一样。它会知道要覆盖模糊时间表达这种边缘情况也会知道要故意构造一些包含矛盾信息的对抗样本。这一步的投入大概半小时但能省掉后面几小时的返工。2.2 用 claude-api 批量生成用例的实操细节接下来是技术实现。我用的是 Claude API 的 messages 接口模型选的是 claude-sonnet 系列因为生成用例这个任务对创造力要求高但对推理深度要求没那么极致sonnet 的性价比最合适。如果你预算充足opus 系列生成出来的用例会更刁钻一些但差距没有价格差距那么大。调用的时候有几个细节值得注意。第一temperature 要调高一点我一般设 0.8 到 1.0因为你要的是多样性不是稳定性。如果 temperature 太低Claude 会反复生成相似的用例覆盖度上不去。第二用 system prompt 来固定角色和约束把任务规格放在 system 里把具体的生成指令放在 user message 里。第三分批生成一次让它生成 10 到 15 条而不是一次性要 100 条。因为上下文太长的时候Claude 对后面用例的质量会下降而且一旦生成到一半出错你前面的也白费了。下面是我实际用的调用代码骨架用 Python 写的import anthropic import json client anthropic.Anthropic(api_key你的key) SYSTEM_PROMPT 你是一个专业的测试用例设计师。你的任务是根据给定的任务规格生成高质量的测试用例。 任务规格如下 [这里粘贴你的任务规格说明书] 生成要求 1. 每条用例包含 input输入文本和 category用例类型正常/边缘/对抗 2. 正常用例要覆盖典型场景边缘用例要触及边界条件对抗用例要故意制造困难 3. 输入文本要像真实用户会写的那样不要过于书面化 4. 输出严格的 JSON 数组格式不要有任何额外说明文字 def generate_cases(batch_size12, category_focus混合): user_msg f请生成 {batch_size} 条测试用例类型分布为{category_focus}。直接输出 JSON 数组。 response client.messages.create( modelclaude-sonnet-4-20250514, max_tokens4000, temperature0.9, systemSYSTEM_PROMPT, messages[{role: user, content: user_msg}] ) text response.content[0].text # 清理可能的 markdown 代码块标记 text text.strip().removeprefix(json).removeprefix().removesuffix().strip() return json.loads(text) # 分批生成凑够 60 条 all_cases [] for i in range(5): cases generate_cases(batch_size12) all_cases.extend(cases) print(f第 {i1} 批生成 {len(cases)} 条累计 {len(all_cases)} 条) # 去重按 input 文本 seen set() unique_cases [] for c in all_cases: if c[input] not in seen: seen.add(c[input]) unique_cases.append(c) with open(eval_cases.json, w, encodingutf-8) as f: json.dump(unique_cases, f, ensure_asciiFalse, indent2)这段代码跑下来大概能拿到 50 到 55 条去重后的用例。你会发现 Claude 生成的用例里有一部分质量很高有一部分明显是凑数的。这很正常下一步就是人工筛选。2.3 人工筛选这一步为什么不能省我试过完全跳过人工筛选直接用 Claude 生成的用例去跑 eval结果分数虚高得离谱。原因是 Claude 生成的用例里有相当一部分是它自己觉得难但其实不难的还有一些是重复表达同一个意思的。如果不筛你的 eval 分数就没有参考价值。筛选的标准我总结成三条第一输入是否真实。如果一条用例的输入读起来像教科书例句不像真人会说的话删掉。第二是否覆盖了新场景。如果和已有用例表达的是同一个意思只是换了几个词删掉。第三期望输出是否明确。如果一条用例的输入本身就有歧义导致你没法判断什么输出算对那这条用例就不适合放进 eval因为你自己都说不清标准。筛选完之后我一般会保留 30 到 40 条。这个数量不算多但足够覆盖主要场景了。而且用例少有个好处每次跑 eval 的成本低、速度快你可以频繁地跑快速验证改动效果。等应用成熟了再考虑扩充到上百条。提示筛选的时候建议用表格记录每条用例的保留/删除决定和理由这样后面如果对 eval 结果有疑问可以回溯是哪条用例导致的。3. 设计一个能自动打分的 eval 框架评分逻辑比用例本身更关键3.1 三种评分方式的选择与组合用例有了接下来要解决怎么判断输出好不好的问题。这一步是整个 eval 框架里最考验设计功力的地方。我实践下来评分方式无非三种精确匹配、规则校验、模型评判。每种都有适用场景关键是组合使用。精确匹配适合输出格式完全固定的场景比如你要求输出必须是某个枚举值。规则校验适合有明确结构约束的场景比如 JSON 字段是否齐全、数值是否在合理范围内。模型评判适合主观性强的场景比如这段总结是否抓住了重点这种没法用规则描述的东西。我的需求整理工具评分逻辑是这样组合的先用规则校验检查 JSON 格式和字段完整性这部分占 40 分再用规则校验检查优先级判断是否合理对照我预先标注的期望优先级占 30 分最后用 Claude 评判任务名称是否准确概括了用户意图占 30 分。三项加起来是 100 分。这里有个坑要提醒不要让模型评判承担太多权重。模型评判虽然灵活但它的稳定性不如规则校验同样的输出跑两次可能给出不同的分数。我一般把模型评判的权重控制在 30% 到 40% 之间剩下的交给确定性规则。3.2 用 Claude 做评判时的 prompt 设计要点用 Claude 做评判prompt 的设计直接决定评分的可靠性。我踩过的坑是一开始只给 Claude 一句请判断这个输出好不好打 0 到 10 分结果它给分非常随意同样的输出有时候 7 分有时候 9 分完全没有参考价值。后来我改成结构化评判效果好很多。核心改动是三点第一给出明确的评分维度不要让它笼统地打分而是分维度打分再汇总。第二给出每个维度的评分标准比如9 到 10 分表示完全准确7 到 8 分表示基本准确但有轻微偏差5 到 6 分表示有明显偏差。第三要求它先给出理由再给分数这样你能看出它的判断逻辑是否合理。下面是我实际用的评判 prompt 模板JUDGE_PROMPT 你是一个严格的输出质量评判员。请根据以下标准对给定的输出进行评分。 评分维度任务名称准确性 - 9-10分任务名称精准概括了用户的核心意图没有遗漏也没有添加 - 7-8分基本准确但措辞略有偏差或遗漏了次要信息 - 5-6分抓住了部分意图但偏离了核心 - 3-4分明显误解了用户意图 - 0-2分完全无关或输出为空 请先分析输出与用户输入的匹配程度给出理由然后在最后一行输出格式为SCORE: X的分数。 用户输入 {input} 模型输出 {output} def judge_with_claude(input_text, output_text): response client.messages.create( modelclaude-sonnet-4-20250514, max_tokens1000, temperature0.0, # 评判要稳定temperature 设 0 messages[{role: user, content: JUDGE_PROMPT.format( inputinput_text, outputoutput_text)}] ) text response.content[0].text # 提取最后一行的 SCORE for line in reversed(text.strip().split(\n)): if line.startswith(SCORE:): return float(line.replace(SCORE:, ).strip()) return 0.0注意 temperature 设成 0评判任务要的是稳定不是多样。另外我建议对同一批输出跑两次评判如果两次分数差异超过 1 分说明这条用例的评判标准可能不够清晰需要回头调整 prompt。3.3 把评分逻辑串成一个可复用的 eval 脚本有了用例和评分逻辑接下来就是把它们串起来。我写了一个 eval 脚本流程是读入用例文件对每条用例调用被测应用拿到输出然后依次跑规则校验和模型评判最后汇总成分数报告。import json def run_eval(cases_file, app_func): with open(cases_file, r, encodingutf-8) as f: cases json.load(f) results [] for i, case in enumerate(cases): input_text case[input] try: output app_func(input_text) except Exception as e: results.append({case_id: i, score: 0, error: str(e)}) continue # 规则校验部分 format_score check_format(output) # 0-40 priority_score check_priority(output, case.get(expected_priority)) # 0-30 # 模型评判部分 name_score judge_with_claude(input_text, output) * 3 # 0-30 total format_score priority_score name_score results.append({ case_id: i, input: input_text, output: output, format_score: format_score, priority_score: priority_score, name_score: name_score, total: total }) avg_score sum(r[total] for r in results) / len(results) print(f平均分{avg_score:.1f}) # 按分数排序方便看哪些用例最差 results.sort(keylambda x: x[total]) with open(eval_report.json, w, encodingutf-8) as f: json.dump(results, f, ensure_asciiFalse, indent2) return avg_score, results这个脚本跑一次大概几分钟取决于用例数量和 API 调用速度。跑完之后你会拿到一个按分数排序的报告最差的用例排在最前面。这些最差的用例就是你下一轮优化的重点。注意eval 脚本本身也要做版本管理。每次改动评分逻辑都要记录改了什么、为什么改否则过一段时间你自己都忘了当初为什么这么设计。4. Hillclimb 实战一轮轮把分数从 62 推到 91 的完整记录4.1 第一轮基线分数 62问题出在格式和优先级第一次跑完 eval平均分 62.3。我把报告拉出来看发现分数低的用例集中在两类一类是输出 JSON 格式错误的另一类是优先级判断错误的。格式错误的表现是 Claude 有时候会在 JSON 外面包一层解释文字导致解析失败优先级错误的表现是它把尽快一律判成高但实际上有些尽快只是客套话真实优先级是中。针对格式问题我在 prompt 里加了一条硬约束只输出 JSON 数组不要有任何解释文字、不要用 markdown 代码块包裹。同时在代码层面加了一个容错解析如果直接解析失败就尝试用正则提取 JSON 部分。这一轮改完格式分从平均 28 提到了 37满分 40。针对优先级问题我在 prompt 里补充了优先级判断的规则只有当用户明确表达紧迫性如今天必须马上或涉及阻塞其他任务时才判为高优先级尽快这周内等模糊表达默认判为中优先级除非上下文有更强的紧迫信号。这一轮改完优先级分从平均 18 提到了 24满分 30。第一轮优化后平均分从 62.3 提到了 74.1。这个提升幅度说明大部分分数损失其实来自明确的、可修复的问题而不是什么玄学。你只要认真看报告把最差的用例挑出来分析就能找到优化方向。4.2 第二轮模型评判分数上不去原来是评判标准太模糊第二轮我重点看模型评判那 30 分。发现平均只有 19 分左右而且波动很大。我抽了几条用例看评判理由发现 Claude 评判员经常说任务名称基本准确但不够精炼这种模糊的话然后给个 7 分。问题是不够精炼到底扣多少分没有明确标准。于是我回头改了评判 prompt把任务名称准确性这个维度拆成了两个子维度信息完整性有没有遗漏关键信息和表达精炼度有没有冗余表达。每个子维度给出更具体的评分锚点。改完之后评判分数的波动明显变小了平均分也提到了 23 分。这一轮还发现一个有意思的现象有些用例的输入本身就有歧义导致模型输出无论怎么做都只能拿一半分。这种用例其实是坏用例不应该算进平均分。我把这类用例标记为参考用例不计入总分只用于观察。这个调整让平均分又涨了 2 分左右但更重要的是它让分数更能反映真实水平。4.3 第三轮对抗用例暴露的深层问题第三轮我把注意力放在对抗用例上。这些用例是我故意构造的刁难输入比如包含矛盾信息、包含无关内容、包含超长文本。跑下来发现对抗用例的平均分只有 55 左右远低于正常用例的 85。深入看发现主要问题是对抗输入里的噪声干扰了模型判断。比如一条输入里既有真实需求又有一大段抱怨模型有时候会把抱怨也当成需求提取出来。针对这个问题我在 prompt 里加了一条输入中可能包含与任务无关的内容请只提取真正的需求忽略抱怨、闲聊和背景描述。同时我在 few-shot 示例里加了一个含噪声输入的例子让模型有样学样。这一轮改完对抗用例的平均分从 55 提到了 72整体平均分从 74.1 提到了 83.6。这个提升让我意识到对抗用例虽然难但它们是提升应用鲁棒性的关键。正常用例只能验证能不能用对抗用例才能验证靠不靠谱。4.4 第四轮从 83 到 91靠的是细节打磨到了 83 分这个阶段大的优化空间已经不多了剩下的都是细节。我做了几件事第一把 few-shot 示例从 2 个增加到 4 个覆盖更多边缘场景。第二在 prompt 里加入输出格式的示例让模型更清楚期望的 JSON 结构。第三对模型评判的 prompt 做了微调把评分锚点写得更具体。这几件事单独看都不起眼但叠加起来平均分从 83.6 提到了 91.2。到这个分数剩下的 8 分多损失主要来自少数几条特别难的对抗用例以及模型评判本身的噪声。我判断继续优化的边际收益已经很低了就停在了这个水平。下面这张表是我四轮迭代的分数变化记录供你参考轮次主要改动格式分(40)优先级分(30)名称分(30)平均总分基线无28181662.3第一轮格式硬约束优先级规则37241774.1第二轮评判维度拆分37242383.6第三轮噪声处理对抗示例38262483.6第四轮few-shot扩充锚点细化39272591.2提示每一轮只改一个变量这样你才能知道分数变化到底是哪个改动带来的。如果一轮改了好几个地方分数涨了你也不知道该保留哪个。5. 用 Claude Code 把 eval 流程自动化省掉那些重复的体力活5.1 Claude Code 在这个流程里能干什么前面讲的流程如果全手工操作最烦的部分是每次改完 prompt要手动跑 eval 脚本、手动看报告、手动对比上一轮的结果。这些操作本身不难但重复次数多了很消耗精力。Claude Code 在这里能帮上大忙因为它可以直接在你的项目目录里执行命令、读写文件、甚至帮你分析报告。我现在的做法是把 eval 脚本、用例文件、报告文件都放在同一个项目目录下然后用 Claude Code 来驱动整个流程。比如我会直接跟它说跑一下 eval 脚本然后把这次报告和上一轮报告对比告诉我哪些用例的分数下降了可能是什么原因。Claude Code 会自己去执行脚本、读取两个报告文件、做对比分析然后给我一份结论。这个过程如果手工做大概要十分钟交给它之后我只需要看结论。5.2 让 Claude Code 帮你分析分数下降的原因分数下降是最让人头疼的情况因为你改了一个地方本来以为会涨分结果反而掉了。这时候 Claude Code 的分析能力就很有用。我会把两轮的报告都给它让它找出分数下降的用例并对比这些用例在两轮里的输出差异。有一次我改 prompt 之后整体分数从 83 掉到了 79。Claude Code 分析后发现下降集中在含多个需求的用例上。原因是我的新 prompt 里加了一句优先处理最紧急的需求导致模型有时候只输出了一个需求把其他的漏掉了。这个发现如果靠我自己看报告可能要花半小时才能定位到Claude Code 几分钟就给出了结论。5.3 用 Claude Code 做批量 prompt 变体测试还有一个我觉得特别有用的场景当你拿不准哪个 prompt 写法更好的时候可以让 Claude Code 帮你批量测试。具体做法是准备几个 prompt 变体让 Claude Code 依次替换、跑 eval、记录分数最后给你一张对比表。这个操作手工做的话每个变体都要改代码、跑脚本、记分数很容易出错。交给 Claude Code 之后它会自动完成整个流程你只需要最后看结果。我一般会准备 3 到 5 个变体跑一轮下来大概二十分钟但能帮你省掉好几天的试错时间。注意Claude Code 执行命令的时候建议在项目目录里操作并且提前把重要的文件做好备份。虽然它一般不会乱改文件但涉及批量替换的时候谨慎一点总没错。6. 这套方法踩过的坑和几条实在的经验6.1 不要用 eval 分数去反向拟合这是我踩过的最大的坑。有一段时间我为了让分数好看不断调整 prompt 去迎合 eval 用例结果分数是上去了但真实用户体验反而变差了。原因是 eval 用例再多也只是真实分布的一个采样你过度拟合 eval就会在 eval 没覆盖到的地方翻车。正确的做法是把 eval 分数当成一个参考指标而不是唯一目标。每次优化之后除了看分数还要抽几条真实用户输入跑一下看看实际效果。如果分数涨了但真实效果没涨那这个优化就是无效的。6.2 模型评判的偏差要定期校准模型评判虽然方便但它有自己的偏好。比如 Claude 评判员倾向于给表达流畅的输出更高分哪怕内容上略有偏差。这种偏差如果不校准会系统性地误导你的优化方向。我的做法是每隔一段时间人工抽 10 条用例自己打分然后和模型评判的分数对比。如果发现系统性偏差比如模型评判普遍比人工高 1 分就调整评判 prompt 里的锚点。这个校准不需要很频繁一个月一次就够了。6.3 用例集要定期更新应用在迭代用户输入分布也在变化。三个月前生成的用例集可能已经覆盖不了现在的真实场景了。我一般每季度会重新生成一批用例和旧用例合并去重保持用例集的时效性。更新用例集的时候有个技巧保留那些经典难题用例它们虽然老但能持续暴露应用的薄弱环节。同时加入一批新的真实用户输入脱敏后让用例集更贴近实际。6.4 分数不是越高越好够用就行最后一条经验可能有点反直觉不要追求满分。我见过有人为了把分数从 95 推到 98花了好几周时间但实际用户体验的提升微乎其微。eval 的目的是帮你发现明显的问题不是让你刷分。当分数到了 85 以上且最差的用例也在可接受范围内就可以把精力放到其他事情上了。我在实际操作中的体会是eval 最大的价值不在于那个分数本身而在于它逼着你去系统性地思考什么算好、什么算坏。这个思考过程比分数更能提升你对应用的理解。等你把 eval 跑顺了你会发现改 prompt 不再是盲人摸象而是有方向、有反馈的迭代。这种踏实感是任何感觉好像好了一点的模糊判断都给不了的。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询