用Claude设计Eval并实现分数爬坡:从43%到91%的实战经验

发布时间:2026/10/7 12:27:11
用Claude设计Eval并实现分数爬坡:从43%到91%的实战经验 评估这件事很多人第一反应是跑个测试集看准确率但真正做过模型迭代的人都知道最难的从来不是跑分而是设计出一套能真实反映问题、又能指导下一步优化的评估体系。我最近用 Claude 做了一轮完整的 eval 设计和分数爬坡从最初 40% 多的通过率一路推到 90% 以上中间踩了不少坑也总结出一些可复用的方法。这篇文章就把整个过程拆开讲清楚——怎么让 Claude 帮你设计 eval、怎么定位失分点、怎么一轮轮把分数提上去。适合正在做模型评估、Agent 调优、或者想用 Claude 辅助工程迭代的同行参考。1. 为什么让 Claude 设计 eval这件事本身值得认真做1.1 手工写 eval 的三个死穴先说清楚为什么要绕这一圈。大部分人做评估习惯自己拍脑袋写测试用例或者从线上日志里捞一批样本直接跑。这两种做法我都试过问题非常明显。第一个死穴是覆盖盲区。你脑子里能想到的边界情况永远只是真实分布的一小部分。我做过一个信息抽取的任务自己写了 50 条用例感觉已经覆盖了各种格式结果上线后遇到带嵌套括号的输入直接崩了——这种 case 我压根没想到要测。第二个死穴是评分标准模糊。什么叫回答正确是关键词命中就行还是语义等价才算手工写 eval 的时候这些标准往往散落在脑子里不同人跑出来的结论对不上。更麻烦的是当你迭代了几轮之后自己都忘了当初为什么这么判。第三个死穴是维护成本高。任务一变eval 就得跟着改改着改着就变成一坨谁也不敢动的祖传代码。让 Claude 来设计 eval本质上是把穷举边界情况和统一评分口径这两件苦力活外包出去。它的价值不在于比你聪明而在于它不会累、不会漏、而且能一次性给你生成结构化的评分维度。1.2 Claude 设计 eval 的独特优势Claude 在这件事上有几个别的模型不太具备的特点。一是长上下文下的指令遵循稳定性你可以一次性把任务描述、输入格式、期望输出、评分维度全塞进去它不容易跑偏。二是对评分标准这类元指令的理解比较到位你让它设计一个 rubric它给出的维度通常比你自己想的更细。我实测下来让 Claude 设计 eval 最有效的姿势不是帮我写测试用例而是给它一个角色 任务 输出格式的三段式指令。比如你是一名严格的评估工程师。下面是一个信息抽取任务的定义 [任务描述] 请设计一套评估方案要求 1. 列出至少 8 个评估维度每个维度说明判定标准 2. 针对每个维度给出 3 个典型测试用例含输入和期望输出 3. 标注哪些维度是硬性通过项哪些是加分项 4. 输出为结构化 JSON这样出来的东西直接就能转成可执行的 eval 脚本。关键在于硬性通过项 vs 加分项这个区分——它逼着 Claude 去思考哪些是底线、哪些是锦上添花这个思考过程本身就是 eval 设计的核心。1.3 一个容易被忽略的前提先把任务定义写清楚这里有个坑我必须提前说。如果你自己的任务定义都是模糊的Claude 设计出来的 eval 一定是垃圾。我第一轮就栽在这上面——任务描述只写了从文本中抽取关键信息结果 Claude 给我设计了一堆模棱两可的维度跑出来的分数完全没有参考价值。后来我改成这样描述任务输入是什么格式、输出必须包含哪些字段、每个字段的类型和取值范围、什么情况算失败。改完之后eval 的质量立刻上了一个台阶。eval 的质量上限取决于你对任务定义清晰度的下限。这句话我建议你贴在显示器上。2. 从零搭一套可执行的 eval 框架2.1 评估维度的拆解逻辑Claude 给出的维度通常可以归成三类格式合规性、内容正确性、鲁棒性。这三类的权重分配很讲究。格式合规性是硬门槛通常占通过与否的一票否决权。比如要求输出 JSON结果模型吐了一段自然语言那这条直接判失败不用看内容。内容正确性是核心一般拆成字段级准确率和整体语义一致性两层。鲁棒性则是看模型在边界输入、噪声输入、超长输入下的表现。我一般会用一个加权公式来算总分总分 格式合规(0/1) × (0.6 × 内容准确率 0.3 × 鲁棒性得分 0.1 × 效率得分)这个公式的好处是格式不过直接归零逼着你先解决最基础的问题。效率得分我放得很低因为早期迭代阶段跑得慢一点无所谓准才是第一位的。2.2 用 Claude 生成测试用例的正确姿势生成测试用例的时候最忌讳的是让 Claude 随便生成一些。它确实会生成但生成的都是平均情况对评估毫无价值。正确的做法是按维度定向生成。我会给 Claude 这样的指令针对嵌套结构处理这个维度生成 5 个测试用例 - 2 个正常嵌套2 层 - 2 个深层嵌套4 层以上 - 1 个畸形嵌套括号不匹配 每个用例给出输入文本和期望的抽取结果。定向生成的好处是你能精确控制测试集的分布。我一般会让正常 case 占 60%、边界 case 占 30%、畸形 case 占 10%。这个比例不是拍脑袋来的——它大致对应了真实线上流量的分布畸形输入虽然少但一旦出现就是灾难性的。2.3 评分脚本的落地细节Claude 设计的 eval 方案再漂亮最终都要落成能跑的脚本。这里有几个实操细节值得说。第一评分函数要幂等。同一个输入跑两次结果必须一致。我见过有人用随机采样做评分导致同一份输出两次跑出不同分数这种 eval 完全没法用来做迭代对比。第二失败要能定位到具体维度。不要只输出一个总分要输出每个维度的得分和失败原因。我一般会要求评分脚本返回这样的结构{ case_id: nested_003, passed: false, dimension_scores: { format: 1, content_accuracy: 0.5, robustness: 0 }, failure_reason: 深层嵌套时丢失了最内层字段 }有了 failure_reason你才能知道下一轮该改什么。没有这个你只能看着分数干瞪眼。第三保留原始输出。每次跑 eval 都把模型的原始输出存下来方便事后复盘。我吃过这个亏——某轮分数突然掉了但没存原始输出只能重跑浪费了大半天。3. 分数爬坡一轮轮把通过率推上去的实战记录3.1 第一轮基线 43%问题出在哪第一轮跑完通过率 43%。这个数字不算意外但拆开看维度得分就很有意思了格式合规率 91%内容准确率 52%鲁棒性 18%。格式基本没问题说明 prompt 里的输出格式约束是有效的。内容准确率刚过一半说明模型理解了任务但做得不够精细。鲁棒性只有 18%这是重灾区。我把失败 case 拉出来看发现三个高频问题一是深层嵌套时字段丢失二是同义表述没归一化比如北京和北京市被当成两个值三是超长输入时截断位置不对。这三个问题每一个都对应着明确的优化方向。3.2 第二轮针对性修补冲到 67%第二轮我没有大改 prompt而是针对三个高频问题逐个击破。嵌套丢失的问题我在 prompt 里加了一段显式的处理指令要求模型从最内层开始逐层向外解析每解析完一层就记录当前层级的所有字段。这个思路来自编译原理里的递归下降让模型模拟一个栈式的解析过程。同义归一化的问题我加了一个后处理步骤抽取完成后对每个字段值做一次标准化映射。这个映射表是我从失败 case 里人工整理出来的大概 30 多条。别小看这个后处理它把内容准确率从 52% 拉到了 71%。超长输入的问题我改成了分段处理 结果合并。分段边界选在语义完整的句子之间避免把一个实体切两半。这一轮跑完通过率 67%。格式合规 95%内容准确率 71%鲁棒性 41%。进步明显但离目标还差得远。3.3 第三轮引入 few-shot 和自洽性检查第三轮我做了两件事。一是加了 few-shot 示例每个维度挑 2 个典型 case 放进 prompt。二是引入了自洽性检查——同一个输入让模型跑 3 次如果 3 次结果不一致就标记为低置信度走人工复核或者降级处理。few-shot 的效果立竿见影内容准确率直接到了 84%。自洽性检查则主要提升了鲁棒性因为不一致的 case 被单独拎出来了不再拉低整体分数。这一轮通过率 82%。但这时候出现了一个新问题过拟合。我发现模型在 few-shot 示例覆盖的 case 类型上表现极好但稍微变个形式就掉链子。这说明 few-shot 的示例选择需要更有代表性不能只挑好看的。3.4 第四轮对抗性测试与最终 91%第四轮我引入了对抗性测试。具体做法是让 Claude 生成一批看起来像正常输入但实际有陷阱的 case比如字段名和值混淆、标点符号异常、中英文混排等。这批 case 一跑通过率立刻掉到 76%。但这次掉分是好事——它暴露了模型在真实场景下的脆弱点。我针对这些陷阱 case 又做了一轮 prompt 优化主要是加了先判断输入类型再决定解析策略的分支逻辑。最终通过率稳定在 91%。从 43% 到 91%一共四轮每轮都有明确的优化目标和验证方法。轮次通过率格式合规内容准确率鲁棒性主要动作第一轮43%91%52%18%建立基线第二轮67%95%71%41%针对性修补三个高频问题第三轮82%97%84%63%few-shot 自洽性检查第四轮91%98%92%78%对抗性测试 分支逻辑4. 爬坡过程中踩过的坑和反直觉发现4.1 分数不是越高越好警惕 eval 过拟合这是我最想强调的一点。当你反复用同一套 eval 调优时模型会逐渐记住这套 eval 的偏好分数涨得飞快但真实能力可能没怎么变。我第三轮就遇到了这个情况——eval 分数 82%但拿一批全新的线上样本一测实际通过率只有 68%。判断是否过拟合有个简单方法留出一批从不参与调优的 holdout 集。每次调优只看训练集的分数holdout 集只在关键节点跑一次。如果两者差距超过 10 个百分点基本可以确定过拟合了。4.2 有些失分是假失分别急着改爬坡过程中你会发现有些 case 的失分其实是 eval 本身的问题不是模型的问题。比如我遇到过一个 case模型输出2024年3月eval 期望2024-03判定失败。但这两个表述在语义上完全等价是 eval 的评分标准太死板。这种假失分如果不去甄别你会花大量精力去优化一个根本不需要优化的方向。我的做法是每轮跑完人工抽查 20 个失败 case判断是模型问题还是 eval 问题。如果是 eval 问题就修 eval而不是改模型。4.3 提升鲁棒性的性价比远高于提升准确率从数据上看内容准确率从 52% 提到 92% 花了三轮鲁棒性从 18% 提到 78% 也花了三轮。但实际体验上鲁棒性的提升带来的收益更大——因为鲁棒性差的模型在真实场景下会频繁崩溃而准确率差一点只是偶尔出错。如果你的 eval 显示鲁棒性得分很低我建议优先解决它。具体做法就是前面说的对抗性测试专门找那些看起来正常但实际有坑的输入。4.4 自洽性检查是个被低估的工具让模型对同一输入跑多次、比较结果一致性这个技巧我用下来觉得性价比极高。它不需要改 prompt不需要额外训练只是多跑几次就能识别出模型不确定的 case。这些低置信度的 case 有两种处理方式一是走人工复核二是降级到更保守的处理逻辑。我一般会把自洽性低于阈值的 case 单独统计如果占比超过 15%说明模型在这个任务上还不够稳定需要继续优化。5. 把 eval 爬坡变成可复用的工作流5.1 每轮迭代的标准动作经过这几轮我总结出一套标准动作每轮迭代都按这个流程走跑全量 eval记录各维度得分和失败 case人工抽查 20 个失败 case区分模型问题和 eval 问题确定本轮优化目标只聚焦 1-2 个维度不要贪多实施优化改 prompt、加后处理、调参数重跑 eval对比分数变化跑 holdout 集验证是否过拟合这套流程看起来简单但坚持下来不容易。最大的诱惑是一次改很多地方觉得这样效率高。实际上一次改多个变量你根本不知道是哪个改动起了作用。单变量迭代是爬坡的铁律。5.2 用 Claude 做 eval 的边界在哪里说了这么多 Claude 的好处也得说说它的边界。Claude 擅长的是生成结构化的评估方案和测试用例但它不擅长判断这个 case 在业务上是否重要。业务权重的分配必须由人来定。另外Claude 生成的测试用例会有一定的同质化倾向——它倾向于生成它自己容易理解的 case而不是真实分布中最难的 case。所以真实线上样本的引入是必不可少的不能完全依赖 Claude 生成。我的做法是Claude 生成 70% 的测试用例剩下 30% 从真实日志里采样。这个比例兼顾了覆盖度和真实性。5.3 一些可以直接抄的 prompt 模板最后分享几个我常用的 prompt 模板都是实测有效的。设计评估维度你是一名评估工程师。任务定义如下[任务描述] 请设计评估方案输出 JSON 格式包含 - dimensions: 评估维度列表每个维度含 name、description、weight、is_hard_requirement - test_cases: 每个维度至少 3 个测试用例含 input、expected_output、case_type 要求覆盖正常、边界、畸形三类情况。生成对抗性测试用例针对以下任务[任务描述] 生成 10 个对抗性测试用例要求 - 输入看起来正常但包含容易导致解析错误的陷阱 - 每个用例说明陷阱类型和期望的正确处理方式 - 输出 JSON 格式分析失败原因以下是模型输出和期望输出的对比 输入[input] 模型输出[actual] 期望输出[expected] 请分析失败原因归类到以下维度之一格式问题、内容缺失、内容错误、鲁棒性问题。 并给出具体的修复建议。这几个模板我用了很多轮基本能覆盖 eval 设计和分析的主要场景。你可以根据自己的任务特点调整但核心结构——角色、任务、输出格式、约束条件——建议保留。整套流程跑下来我最大的体会是eval 不是一次性的工作而是一个持续迭代的系统。用 Claude 帮你设计 eval本质上是把这个系统的搭建成本降下来让你能把精力集中在真正的优化上。分数从 43% 爬到 91% 的过程与其说是模型变强了不如说是你对任务的理解变深了——每一轮失败 case 的分析都是在逼你把模糊的直觉变成明确的规则。这个过程没有捷径但有了 Claude 辅助至少能少走一些弯路。