ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

用Claude设计Eval:从单次评测到持续爬坡的工程循环

用Claude设计Eval:从单次评测到持续爬坡的工程循环 评估这件事很多人第一反应是跑个测试集看准确率然后就没有然后了。分数低就换个更大的模型分数高就发个朋友圈中间发生了什么、为什么涨、还能不能继续涨一概不知。我做了几轮下来最大的感受是eval 不是一次性的验收动作而是一个可以持续爬坡的工程循环。这篇就聊聊我怎么用 Claude 来设计 eval再一轮一轮把分数往上推的完整过程——包括怎么让 Claude 帮你写评测集、怎么定位失分点、怎么设计爬坡的迭代节奏以及那些只有真跑过几轮才会遇到的坑。适合已经在用 Claude API 或 Claude Code 做应用、但评测还停留在手动看几条 case阶段的同学。1. 为什么跑一次 eval几乎必然失败1.1 单次评测的三种典型死法我见过也踩过最多的三种情况几乎覆盖了 90% 的我做了 eval 但没用。第一种是评测集和真实场景脱节。你手写 20 条 case全是自己脑子里想出来的理想输入格式工整、意图明确。结果上线后用户输入的是错别字、中英混杂、带一堆无关上下文的长文本模型直接懵。评测集不真实分数再高也是自嗨。第二种是指标太粗。只统计一个整体准确率 78%你根本不知道那 22% 错在哪。是格式没对齐是漏了关键字段还是推理链断在中间一个笼统的数字没法指导任何优化动作。第三种是没有基线对比。你改了 prompt分数从 78% 涨到 81%你很高兴。但你没测过如果什么都不改只是把 temperature 从 0.7 调到 0分数会不会也涨到 81%没有对照你根本不知道涨分是来自你的改动还是随机波动。评测的核心不是得到一个分数而是得到一个能指导下一步动作的信号。分数本身没有价值分数背后的失分结构才有价值。1.2 把 eval 当成爬坡而不是考试这是我思路转变的关键。考试思维是准备 → 考一次 → 看结果 → 结束。爬坡思维是建立可复现的评测基线 → 定位当前最大的失分点 → 针对性改一处 → 重跑 → 确认涨分且没引入回归 → 进入下一轮。这个循环里每一轮只动一个变量这样你才能确定涨分归因。听起来很慢但实际比一次改五个地方然后不知道哪个起作用快得多。而且爬坡有个好处你会积累一份什么改动有效的经验清单下一轮直接复用。Claude 在这个循环里的角色很特别——它既是被评测的对象又是帮你设计评测、分析失分、生成新 case 的工具。这种自己评自己的用法是这篇要讲的核心。2. 让 Claude 帮你从零搭出第一版评测集2.1 先定义什么算对再谈怎么测很多人上来就让 Claude 生成 50 条测试用例这是本末倒置。你得先回答对于我的任务一条输出满足什么条件才算正确以我做过的一个从客服对话里抽取工单结构化字段的任务为例正确性至少包含三层字段完整性该抽的字段一个不少比如问题类型、紧急程度、涉及产品、用户诉求。字段准确性抽出来的值要和对话内容一致不能编造。格式合规性输出必须是合法 JSON枚举值必须在预定义集合内。这三层的重要性不一样。格式错了整个下游都崩属于硬性失败字段值偶尔偏差属于软性失败。在评测里给不同失败类型不同权重比一个笼统的准确率有用得多。我一般会先让 Claude 帮我把正确性定义结构化我有一个任务从客服对话中抽取结构化字段。 请帮我列出评估这个任务输出质量的所有维度 按硬性失败和软性失败分类并说明每个维度如何判定。Claude 给出的维度清单通常比我拍脑袋想的全尤其是它会提醒我一些边界情况比如对话中用户中途改变了诉求应该以哪个为准。2.2 用 Claude 生成有梯度的测试用例拿到维度后再让 Claude 生成用例。这里有个关键技巧不要让用例难度均匀分布要刻意制造梯度。我通常要求 Claude 按难度分三档生成简单档约 30%意图明确、格式规整、单轮对话。这档用来验证基础能力如果这档都错说明 prompt 或模型选型有根本问题。中等档约 50%有干扰信息、多轮对话、字段需要推理。这档是主战场大部分优化空间在这里。困难档约 20%信息缺失需要合理兜底、矛盾信息需要判断、超长上下文。这档用来探边界不指望全对但要知道错在哪。生成时的 prompt 我会写得很具体基于以下字段定义 [粘贴字段定义] 生成 30 条客服对话测试用例要求 1. 10 条简单单轮、意图明确、字段齐全 2. 15 条中等多轮对话含 1-2 个干扰信息 3. 5 条困难信息缺失或存在矛盾需要模型做判断 每条用例请同时给出标准答案和这条主要考察什么维度。让 Claude 标注考察维度这一步很重要它让后面的失分分析能直接对应到维度上。2.3 人工过一遍别全信生成结果Claude 生成的用例质量整体不错但标准答案必须人工核对。我遇到过好几次 Claude 自己把标准答案写错的情况——它生成的对话里用户说的是 A标准答案却填了 B。如果直接拿这种数据当 ground truth你的评测从第一天就是歪的。我的做法是生成 30 条人工快速过一遍删掉明显有问题的 3-5 条修正几条标准答案最后留下 25 条左右。这个投入大概 20 分钟但换来的是一个可信的基线。一个经验值第一版评测集 20-30 条就够启动了。不要一开始就追求 200 条因为你后面一定会根据失分情况补充新 case第一版太大反而拖慢迭代。3. 把评测跑起来从手动到半自动3.1 最小可用的评测脚本长什么样第一版不需要什么框架一个脚本就够。核心逻辑就三步读用例 → 调模型 → 比对打分。import json from anthropic import Anthropic client Anthropic() def run_case(case): resp client.messages.create( modelclaude-sonnet-4-5, max_tokens1024, messages[{role: user, content: case[input]}] ) return resp.content[0].text def score(case, output): # 先判格式 try: parsed json.loads(output) except json.JSONDecodeError: return {format: 0, fields: 0, reason: 非法JSON} # 再逐字段比对 gold case[gold] hit sum(1 for k, v in gold.items() if parsed.get(k) v) return {format: 1, fields: hit / len(gold)}跑完把每条的结果存下来包括输入、输出、标准答案、得分、失败原因。这份明细比总分重要一百倍后面所有分析都基于它。3.2 用 Claude 当裁判处理开放式输出有些任务的输出不是结构化字段没法简单字符串比对比如生成一段回复或总结这段对话。这时候可以用 Claude 当裁判LLM-as-judge。但直接让 Claude 打个分很不靠谱分数飘忽。我的做法是让裁判做二元判断而不是打分你是评测裁判。给定用户输入、模型输出、评分标准 请判断模型输出是否满足以下每一条标准逐条回答是或否 并给出判断依据。不要给总分。 标准 1. 是否准确反映了用户的核心诉求 2. 是否包含编造的信息 3. 语气是否专业且礼貌二元判断比打分稳定得多而且逐条 依据的结构让你能看清是哪条标准没过。多个标准最后自己加权汇总权重你说了算。裁判模型最好和被测模型不是同一个或者至少用不同的 prompt。同模型自评会有明显的自我偏好实测下来分数普遍偏高 5-10 个百分点。3.3 固定随机性让分数可复现这一步不做后面所有对比都是假的。要点temperature 设 0或尽可能低减少输出波动。固定模型版本别用会漂移的别名。固定评测集每轮跑的是同一批 case。记录完整环境模型名、参数、prompt 版本、评测集版本。我习惯给每轮评测打个 tag比如v1-baseline、v2-prompt-tweak结果文件按 tag 存。这样任何时候都能回溯这一分是怎么涨上来的。4. 定位失分点把 78% 拆成能动手的清单4.1 先做失败分类别急着改拿到第一版结果最忌讳的就是立刻去改 prompt。正确动作是先把所有失败 case 分类。我会把失败明细丢给 Claude让它帮我归类以下是 25 条评测中失败的 8 条包含输入、模型输出、标准答案。 请把它们按失败原因归类每类给出失败模式描述、 涉及的 case 编号、可能的根因假设。Claude 通常能归出几类比如枚举值越界多轮对话中丢失早期信息信息缺失时编造而非留空。每一类对应一个可操作的优化方向这比准确率低有用太多。4.2 按影响面 × 修复成本排优先级分类完不是每类都值得马上修。我用一个简单的二维判断失败类型影响 case 数修复成本优先级枚举值越界4低prompt 里明确枚举高多轮信息丢失2中改输入组织方式中信息缺失时编造2高需要改推理逻辑低先修影响面大 成本低的。上面这个例子里枚举值越界 4 条、改 prompt 就能解决这是第一轮该动的。信息缺失编造虽然严重但难修放后面。这个排序逻辑很朴素但能避免你一头扎进最难的问题里半天不见分数动。4.3 一个反直觉的发现格式问题往往被低估我前几轮踩的最大的坑是低估了格式失败的连带影响。有一次模型输出 JSON 里多了一句解释性文字导致json.loads直接失败这一条的所有字段分全丢。表面看是格式问题实际它吃掉了好几条的字段分。后来我在评测里把格式单独拎出来统计才发现格式失败率高达 20%。修起来也简单——在 prompt 里加一句只输出 JSON不要任何额外文字格式失败率直接降到 2%总分跟着涨了一截。教训评测明细里一定要能区分格式失败和内容失败。很多看起来是内容不行的情况根子是格式没对齐。5. 一轮一轮爬坡每轮只动一个变量5.1 爬坡的节奏怎么定我的节奏是一轮一个改动跑完看总分 看失败分类变化。一轮大概 15-30 分钟取决于评测集大小和 API 速度。一个下午能跑 5-8 轮。每轮记录三样东西改了什么、总分变化、失败分类的变化。攒几轮之后你会有一张改动-效果对照表这张表就是你的经验资产。举个我实际跑出来的对照数字是示意轮次改动总分主要变化v1基线72%格式失败 20%v2prompt 加只输出JSON81%格式失败降到 2%v3枚举值写进 prompt86%枚举越界清零v4加 few-shot 示例88%中等档提升明显v5多轮信息用摘要前置91%多轮丢失问题缓解可以看到前几轮涨分最快越往后越难。这是正常的别指望一直线性涨。5.2 什么时候该停边际收益判断跑到后面每轮涨 1-2 个点成本却越来越高。这时候要判断继续爬坡的收益值不值得投入。我的判断标准是看剩余失分是不是可接受的业务风险。如果剩下的失败都是困难档里的边界 case而线上真实场景很少遇到那就可以停。如果剩下的失败集中在某个高频场景那还得继续。不要为了刷分而刷分。评测分数是手段不是目的。5.3 警惕过拟合评测集这是爬坡到后期最容易犯的错。你盯着这 25 条 case 反复调 prompt分数是涨了但模型可能只是背下了这些 case 的特征换个新输入就露馅。防过拟合的两个办法留一个 holdout 集从生成的总量里留 20% 不参与调优只在每几轮后跑一次看它和主评测集的分数是否同步上涨。如果主集涨、holdout 不涨说明你在过拟合。定期补充新 case每跑几轮让 Claude 生成几条新的、风格不同的 case 加进去保持评测集的新鲜度。我一般每 3-4 轮补一次新 case同时用 holdout 集做交叉验证。6. 那些只有真跑过才会遇到的坑6.1 API 调用失败被当成模型答错早期我没处理 API 报错结果偶尔的网络超时或限流被脚本当成模型输出为空直接判失败。这会让分数莫名其妙地波动你还以为是模型不稳定。修法很简单调用失败要重试重试仍失败要标记为无效而不是失败从分母里剔除。别让基础设施问题污染你的评测信号。6.2 裁判模型的位置偏见用 LLM 当裁判时如果你让它对比两个输出它往往偏向第一个或第二个取决于模型。解决办法是交换顺序跑两次只有两次判断一致才算数。这个细节不做对比类评测基本不可信。6.3 评测集里的脏数据会一直拖后腿前面说过要人工核对标准答案但实际跑起来还会发现新的脏数据——比如某条 case 的输入本身就有歧义标准答案只是其中一种合理解读。这种 case 会让模型冤枉失分。我的处理是发现一条歧义 case就修正或删除一条并在评测集版本里记录。别留着它会一直干扰你对真实水平的判断。6.4 别忽略成本这个维度爬坡到后面你可能会想换个更强的模型是不是分数更高。会但成本也上去了。我在评测明细里会同时记录每条 case 的 token 消耗最后算一个每分成本。有时候一个便宜模型 精心调的 prompt性价比远高于贵模型 随便的 prompt。7. 把整套流程沉淀成可复用的模板跑了几轮之后我把流程固化成了几个可复用的部分下次做新任务直接套评测集生成 prompt 模板包含维度定义、难度分档、标准答案格式要求。评测脚本骨架读用例、调模型、打分、存明细格式失败和内容失败分开统计。失败分类 prompt 模板输入失败明细输出分类 根因假设。爬坡记录表轮次、改动、总分、失败分类变化、每分成本。这套东西的价值在于它把评测从一次性动作变成了一个可重复的工程流程。新任务来了半天就能搭起第一版基线然后进入爬坡循环。Claude 在其中的角色与其说是被测对象不如说是评测工程师的副手——帮你生成用例、分析失分、归类问题。但判断和决策始终在人这边什么算对、先修哪个、什么时候停这些是 Claude 替不了的。最后分享一个我自己的习惯每轮评测完我会用一句话记下这轮学到的最重要的一件事攒在一个文档里。跑十几轮下来这个文档比任何教程都值钱因为它是针对你自己任务的、踩过坑验证过的经验。下次遇到类似任务翻出来直接复用省下的时间远超当初记录的成本。
返回列表