ARTICLE DETAIL

资讯详情

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

用Claude设计Eval与Hillclimb优化Prompt实战指南

用Claude设计Eval与Hillclimb优化Prompt实战指南 1. 为什么我要用 Claude 来设计 eval1.1 从“凭感觉调 prompt”到“用数据说话”做 AI 应用的人都有一个共同的痛点改了一版 prompt感觉效果好像好了但到底好了多少、有没有在别的场景上变差心里完全没底。我以前也是这么干的改完 prompt 随手试几个 case觉得“嗯不错”就上线了。结果上线之后用户反馈一堆问题回头一查原来是我改的那版 prompt 在某个边缘场景上直接崩了。后来我开始认真做 eval也就是评估集。简单说eval 就是一组“输入 期望输出”的测试用例每次改完 prompt 或者换模型都跑一遍 eval看分数是涨了还是跌了。这个思路跟软件工程里的单元测试一模一样只不过测的不是代码逻辑而是模型的输出质量。那为什么标题里强调“用 Claude 设计 eval”因为设计 eval 这件事本身就很费脑子。你得想清楚哪些场景要覆盖每个场景的期望输出长什么样评分标准怎么定这些问题如果全靠自己拍脑袋很容易漏掉关键 case或者评分标准定得太模糊导致分数忽高忽低没有参考价值。而 Claude 在这件事上特别好用——它能帮你快速生成大量候选测试用例还能帮你把模糊的评分标准拆成可执行的打分维度。1.2 什么是 hillclimb为什么它比“一步到位”更靠谱Hillclimb中文叫“爬山法”核心思想特别朴素你不需要一次性找到最优解你只需要每一步都比上一步好一点点。就像爬山一样你不需要知道山顶在哪你只需要每次往更高的方向走一步。放到 eval 优化里流程是这样的先有一个 baseline也就是当前版本的 prompt 和对应的 eval 分数。分析 eval 结果找出得分最低的那几个 case。针对这些 case 改 prompt只改一个点不要一次改一堆。重新跑 eval看分数有没有提升。如果提升了保留这版改动如果没提升或者下降了回滚。重复步骤 2 到 5直到分数不再明显提升。这个方法听起来很笨但它比“一次性重写 prompt”靠谱得多。因为每次只改一个点你能清楚地知道是哪个改动带来了提升哪个改动导致了下降。而且它天然避免了“改了一堆东西结果有的变好有的变坏最后总分没变但你已经不知道发生了什么”这种灾难。1.3 这套方法适合谁不适合谁这套方法最适合两类人一是正在做 AI 应用但还没建立 eval 体系的开发者二是已经有 eval 但分数卡住了不知道怎么继续提升的人。不太适合的情况也有如果你的任务非常简单比如就是一个固定格式的抽取任务那可能不需要这么复杂的 eval 体系写几个 case 手动测一下就够了。另外如果你的任务没有明确的“好”和“坏”的标准比如开放式创意写作那 eval 的设计会非常困难hillclimb 的效果也会打折扣。2. 用 Claude 设计 eval 的完整流程2.1 第一步让 Claude 帮你生成候选测试用例设计 eval 最耗时的部分就是“想 case”。你得覆盖正常场景、边缘场景、异常输入、多语言、长文本、短文本……全靠自己想很容易漏。我的做法是先把任务描述和几个典型输入丢给 Claude让它帮我生成 50 到 100 个候选测试用例。Prompt 大概长这样我有一个任务{任务描述} 下面是几个典型输入示例 {示例1} {示例2} {示例3} 请帮我生成 50 个测试用例要求 1. 覆盖正常场景、边缘场景、异常输入 2. 每个用例包含输入和期望输出 3. 期望输出要具体不要写“合理的回答”这种模糊描述 4. 标注每个用例的难度等级简单/中等/困难Claude 生成完之后不要直接全用。我一般会人工过一遍删掉重复的、不合理的、期望输出写得太模糊的。通常 50 个里面能留下 30 个左右就不错了。注意Claude 生成的期望输出有时候会过于“理想化”比如要求模型输出一段完美格式的 JSON但实际场景中模型可能会多输出一句话。这种时候你要根据实际需求调整期望输出不要盲目追求完美。2.2 第二步设计评分标准把“好”拆成可打分的维度有了测试用例之后下一步是设计评分标准。最粗糙的做法是“对/错”二值判断但这样太粗了很多 case 其实是“部分正确”。更好的做法是把评分拆成多个维度每个维度单独打分。比如我最近做的一个信息抽取任务评分维度是这样的维度说明分值字段完整性是否抽取了所有要求的字段0-3字段准确性抽取的值是否与原文一致0-3格式正确性输出格式是否符合要求0-2无冗余信息是否输出了不要求的内容0-2每个 case 的总分是 10 分最后把所有 case 的分数加起来除以总分得到一个百分比分数。这个评分标准也是让 Claude 帮我细化出来的。我一开始只写了“准确性”和“完整性”两个维度Claude 提醒我说“格式正确性”和“无冗余信息”也很重要因为实际使用中格式错误会导致下游解析失败冗余信息会干扰用户阅读。2.3 第三步用 Claude API 批量跑 eval有了测试用例和评分标准接下来就是批量跑 eval。这一步可以用 Claude API 来做核心逻辑是遍历每个测试用例把输入发给 Claude。拿到输出后用评分标准打分。汇总所有 case 的分数得到总分。打分这一步可以人工做也可以让 Claude 来做。如果 case 不多比如 30 个以内人工打分更准确。如果 case 很多100 个以上可以让 Claude 来打分但需要给它非常明确的打分指令。import anthropic client anthropic.Anthropic(api_keyyour-api-key) def run_eval(prompt_template, test_cases): results [] for case in test_cases: # 构造输入 input_text prompt_template.format(inputcase[input]) # 调用 Claude API response client.messages.create( modelclaude-sonnet-4-20250514, max_tokens1024, messages[{role: user, content: input_text}] ) output response.content[0].text # 打分这里简化为人工打分实际可以接自动打分逻辑 score manual_score(output, case[expected]) results.append({case: case, output: output, score: score}) total_score sum(r[score] for r in results) / len(results) return total_score, results提示跑 eval 的时候一定要固定模型版本和参数temperature、max_tokens 等否则分数波动你会分不清是 prompt 改了还是模型变了。2.4 第四步分析失败 case找出改进方向跑完 eval 之后不要只看总分。总分只是一个数字真正有价值的是失败 case 的分布。我一般会把所有得分低于 60% 的 case 单独拉出来按失败原因分类格式错误输出格式不符合要求字段缺失漏抽了某些字段字段错误抽出来的值不对冗余输出多说了不该说的话分类完之后你会发现失败 case 往往集中在某几个类型上。比如我最近一次 eval80% 的失败 case 都是“格式错误”具体表现是模型在 JSON 外面多包了一层 markdown 代码块。这个问题很好解决在 prompt 里加一句“直接输出 JSON不要用 markdown 代码块包裹”就行了。3. Hillclimb 实战一轮轮把分数提上去3.1 第一轮建立 baseline别急着优化第一轮的目标不是提升分数而是建立一个可靠的 baseline。你需要确认三件事eval 本身是稳定的同样的 prompt 跑两次分数差异不超过 5%。评分标准是合理的人工抽查几个 case确认打分符合预期。失败 case 的分布是清晰的你知道主要问题出在哪里。如果这三件事有任何一件没做到先别急着优化 prompt先把 eval 本身修好。我见过太多人 baseline 还没建好就开始改 prompt结果分数忽高忽低完全不知道自己在优化什么。3.2 第二轮针对最大失败类型做最小改动Baseline 建好之后看失败 case 的分布找到占比最大的那个失败类型针对它做最小改动。比如我的情况是“格式错误”占比最高那我就在 prompt 末尾加一句输出要求直接输出 JSON 对象不要用 markdown 代码块包裹不要添加任何解释性文字。只改这一句其他什么都不动。然后重新跑 eval看分数变化。这里的关键是“最小改动”。如果你同时改了格式要求、字段定义、示例那分数提升了你也不知道是哪个改动起了作用。Hillclimb 的核心就是每次只动一个变量。3.3 第三轮处理边缘 case但别过度拟合第二轮改完之后格式错误应该大幅减少。这时候失败 case 的分布会变化可能变成“字段缺失”占比最高。那就针对字段缺失做改动比如在 prompt 里补充字段定义或者加一个 few-shot 示例。但这里有一个坑不要针对单个 case 做过度拟合。比如你发现某个 case 失败了就在 prompt 里加一句专门针对这个 case 的规则。这样做的结果是这个 case 的分数上去了但其他类似 case 的分数可能反而下降了。正确的做法是看失败 case 的共性针对共性做改动。比如你发现多个 case 都漏抽了“日期”字段那就在 prompt 里强调“日期字段必须抽取如果原文没有明确日期输出 null”。而不是针对某一个具体 case 写一条特殊规则。3.4 第四轮及以后分数卡住了怎么办通常跑到第四轮或第五轮分数会进入一个平台期怎么改都提升不明显。这时候有几个策略策略一换模型。如果当前用的是小模型换大模型跑一遍 eval看分数上限在哪里。如果大模型分数明显更高说明当前 prompt 已经接近小模型的能力上限了。策略二加 few-shot 示例。如果 prompt 里还没有示例加 2 到 3 个高质量示例通常能带来明显提升。示例要覆盖不同的场景不要只放简单 case。策略三拆任务。如果一个 prompt 要模型同时做多件事比如先抽取再分类再格式化考虑拆成多个 prompt 串行执行。每个 prompt 只做一件事成功率会高很多。策略四检查 eval 本身。有时候分数卡住不是因为 prompt 不够好而是因为 eval 里有几个 case 的期望输出本身就有问题。重新审查一遍 eval把不合理的 case 修掉或删掉。4. 常见问题与排查技巧实录4.1 分数波动太大怎么办分数波动大通常有三个原因模型参数不固定。temperature 设得太高每次输出都不一样。建议 eval 时把 temperature 设为 0 或接近 0。eval case 太少。如果只有 10 个 case一个 case 的分数变化就会导致总分波动 10%。建议至少 30 个 case最好 50 个以上。评分标准太模糊。如果打分靠人工感觉不同时间打的分数可能不一致。建议把评分标准写成明确的规则最好能让两个人独立打分看一致性有多高。4.2 Claude 生成的测试用例质量不高怎么提升Claude 生成的测试用例质量取决于你给的输入。如果你只给一个任务描述它生成的用例会很泛。如果你给几个具体示例它生成的用例会贴近你的实际场景。我的做法是先手动写 5 个高质量示例覆盖不同场景然后把任务描述和这 5 个示例一起给 Claude让它基于这些示例生成更多用例。这样生成的用例质量会高很多。另外生成完之后一定要人工过一遍。我一般会删掉 30% 到 40% 的用例留下的都是真正有价值的。4.3 自动打分和人工打分差距很大怎么校准自动打分让 Claude 打分和人工打分有差距是正常的但如果差距超过 20%说明自动打分的指令需要调整。校准方法是先人工打 20 个 case 的分数然后让 Claude 也打一遍对比两者的差异。如果 Claude 打分普遍偏高就在指令里加一句“请严格打分不要因为输出看起来合理就给高分”。如果 Claude 打分普遍偏低就加一句“只要输出包含了期望的关键信息即使格式略有不同也给满分”。4.4 常见问题速查表问题可能原因解决方法分数波动大temperature 太高 / case 太少固定 temperature0 / 增加 case 数量分数卡住不涨prompt 接近模型上限换大模型 / 加 few-shot / 拆任务自动打分不准打分指令模糊校准打分指令 / 人工抽查某个 case 反复失败过度拟合其他 case检查是否有冲突规则 / 单独处理eval 跑得太慢case 太多 / API 限流分批跑 / 加缓存 / 用更快的模型4.5 几个我踩过的坑坑一eval 里混入了“不可能完成”的 case。有些 case 的期望输出本身就不合理比如要求模型从一段没有日期的文本里抽出日期。这种 case 永远不可能得满分会拉低整体分数。定期审查 eval把不合理的 case 删掉。坑二prompt 越改越长最后变成一坨。Hillclimb 的过程中每次改一点prompt 会越来越长。跑到十几轮之后prompt 可能已经几千字了里面有很多重复和矛盾的规则。这时候需要做一次“重构”把 prompt 重新整理一遍删掉冗余规则合并相似规则。坑三只看总分不看分布。总分从 70% 涨到 75% 看起来是好事但如果涨的那 5% 全来自简单 case而困难 case 的分数反而下降了那这个改动其实是有问题的。每次看分数变化时都要同时看不同难度等级的分数变化。坑四忘了记录每次改动。Hillclimb 会跑很多轮如果不记录每轮改了什么、分数变化是多少跑到后面你会完全忘记哪版 prompt 是最好的。建议用一个简单的表格记录轮次改动内容总分简单 case 均分困难 case 均分0baseline68%85%45%1加格式要求74%88%52%2加日期字段说明77%89%58%3加 few-shot 示例82%92%65%这个表格不仅能帮你追踪进展还能在回滚时快速找到最好的那一版。5. 把 eval 和 hillclimb 变成日常习惯5.1 每次改 prompt 之前先跑一遍 eval这个习惯听起来很简单但坚持下来不容易。我一开始也经常忘记改完 prompt 直接上线结果出了问题才想起来没跑 eval。后来我把 eval 脚本做成了一个命令行工具改完 prompt 之后顺手跑一下几秒钟就能看到分数变化。python run_eval.py --prompt prompts/v3.txt --output results/v3.json跑完之后脚本会自动对比上一版的结果输出分数变化和失败 case 的变化。这样你就能立刻知道这次改动是正向的还是负向的。5.2 把 eval case 当成代码来维护Eval case 不是写完就扔的一次性东西它需要像代码一样维护。我的做法是把 eval case 存在一个 JSON 或 YAML 文件里用 git 管理。每次发现新的失败场景就把它加进 eval。定期审查 eval删掉过时的 case补充新的 case。给每个 case 打标签难度、场景类型方便分析。这样做的结果是eval 会越来越贴近实际使用场景分数也越来越有参考价值。5.3 用 Claude 做 eval 的自动化分析每次跑完 eval手动分析失败 case 很费时间。我后来写了一个脚本把失败 case 自动发给 Claude让它帮我分类和总结def analyze_failures(failed_cases): prompt f 下面是一批失败的测试用例请帮我分析 1. 这些失败 case 可以分成哪几类 2. 每类失败的主要原因是什么 3. 针对每类失败给出具体的 prompt 改进建议。 失败 case {failed_cases} response client.messages.create( modelclaude-sonnet-4-20250514, max_tokens2048, messages[{role: user, content: prompt}] ) return response.content[0].text这个脚本帮我省了很多时间而且 Claude 的分析往往能发现我忽略的模式。5.4 关于 skill 和 agent 的一点想法最近“skill”这个词很火各种 agent skill、claude skill 的讨论很多。我的理解是skill 本质上就是把一套固定的操作流程封装起来让 agent 可以复用。Eval 和 hillclimb 其实也可以封装成一个 skill输入是 prompt 和 eval 集输出是优化后的 prompt 和分数报告。但我不建议一上来就搞这么复杂。先把 eval 跑起来把 hillclimb 的手动流程跑通等你跑了几十轮之后自然就知道哪些环节可以自动化了。过早追求自动化往往会在还没搞清楚问题的情况下就搭了一堆没用的基础设施。我在实际使用中发现eval 和 hillclimb 最大的价值不是把分数从 70% 提到 90%而是让你对 prompt 的每一次改动都有信心。你知道这次改动是正向的你知道失败 case 在哪里你知道下一步该往哪个方向走。这种确定性比分数本身重要得多。
返回列表