拿到 WorkBuddy Bench 的结果,如果页面上只呈现一个总分,基本无法判断该修什么。更稳妥的流程是回到结果文件:先用任务ID和通过状态把未通过的任务筛出来,再按任务ID找到对应补丁和运行日志,用版本控制查看补丁差异,把每条扣分原因和具体改动对齐,最后用同一任务复跑一次,确认失败可复现。字段名和目录结构各家实现不同,下面的命令和表格是骨架,键名、路径需要按你拿到的结果文件替换;在没确认报告格式前,不要假设某个字段一定存在。
总分只回答“这批任务整体过没过”,不回答“哪个任务失败、失败和补丁哪一行有关”。适用场景是本地或 CI 已经产出 Bench 结果文件、需要定位修复点;操作动作是先解析结果文件筛出未通过任务ID,再按ID取补丁与日志、查看差异、逐条对齐扣分原因,最后同任务复跑;验证方式是复跑前后任务ID、通过状态、错误信息是否一致;风险边界是字段名、目录命名、评分细则均以实际结果和配置为准,无法对应的扣分项只能标为待复现,不要凭印象归因到某段代码。
在结果文件里筛出未通过的任务ID
结果文件通常是一份 JSON 或 JSONL,里面按任务记录保存任务ID、通过状态、分数、错误信息,有些实现还会把 stdout、耗时、评分细则一起塞进同一条记录。先做一次结构打印,确认实际键名,再动手筛选;直接凭经验写 status == 'failed' 很容易筛出空列表。
import json, pathlib
p = pathlib.Path('results/report.json') # 替换为实际结果文件
slow = json.loads(p.read_text(encoding='utf-8'))
def walk(o, path=''):
if isinstance(o, dict):
for k, v in o.items():
print(path + '/' + k, type(v).__name__)
walk(v, path + '/' + k)
elif isinstance(o, list) and o:
walk(o[0], path + '/[0]')
walk(slow)
结构确认后,再按字段筛出未通过任务,把任务ID、状态、错误信息首行导出成一张清单,作为后续定位的主索引:
import json
data = json.load(open('results/report.json', encoding='utf-8'))
for t in data['tasks']: # 键名按上一步打印结果替换
if t.get('status') != 'passed':
print(t.get('task_id'), t.get('status'), str(t.get('error', ''))[:200])
如果结果文件是 JSONL,按行读、逐行判断即可;如果错误信息只给了摘要,先看同一条记录里有没有完整日志路径字段,没有就去输出目录找。这一步只做一件事:得到一份确定的未通过任务ID清单,不在这一步猜原因。
按任务ID找到对应补丁和运行日志
有了任务ID,下一步是建立“任务ID—补丁文件—日志片段”的对应关系。建议直接落成三列表,缺哪一列就说明产物没落盘或命名规则没对上:
| 任务ID | 补丁文件 | 日志片段 |
|---|---|---|
| task-014 | patches/task-014.diff | error: expected ..., got ...(日志第 N 行) |
| task-027 | 未找到 | 超时退出,无断言输出 |
找不到补丁时,先查输出目录和命名规则,而不是先怀疑补丁没生成:
ls -1 out/ | grep -i 'task-014'
find out/ -maxdepth 3 -newer results/report.json -name '*task-014*'
head -n 40 out/task-014/run.log
常见情况是补丁按批次或按哈希命名,任务ID只出现在日志和结果文件里;这时用日志中的路径字段反查,或者按修改时间窗口缩小范围。确实没有补丁产物,就把它记为“产物缺失”,不要用同一批次其他任务的补丁替代比对。
查看补丁差异,标出与任务输入相关的改动
整个补丁动辄几百行,逐行读效率很低。用版本控制把差异缩到与任务输入、期望行为相关的那几处,其余改动只记录不展开:
git diff `--stat` <base_commit> -- patches/task-014/
git diff -U3 <base_commit> -- patches/task-014/
# 补丁是独立文件时
diff -u original/task-014/ fixed/task-014/
记录时只写三类内容:改动了哪个函数或分支、是否触及任务输入涉及的字段或参数、是否触及期望输出对应的判定逻辑。没出现在 diff 里的代码不要推断,日志里没打印的中间值不要补写。如果 diff 里根本没有和任务输入相关的行,这本身就是一条结论:可能是漏改,也可能是补丁打到了错误路径。
把扣分原因和补丁差异逐条对齐
这一步把“扣分点”和“补丁行为”一一对起来,判定通常落在三种情况:缺改动、改错位置、判定条件不满足。建议做成下面这种对照表,一次只处理一条扣分原因:
| 扣分原因(来自评分记录) | 补丁对应改动或缺失项 | 判定 |
|---|---|---|
| 返回字段缺少 unit | 补丁新增了 unit 字段但未写入序列化分支 | 改错位置 |
| 边界输入报错退出 | diff 中无该分支的空值处理 | 缺改动 |
| 输出格式与期望不一致 | 补丁修改了格式,但任务期望未在配置中确认 | 待复现 |
无法与任何一条补丁改动对应的扣分原因,一律标为待复现,并附上日志行号或评分记录位置。不要为了凑齐表格把原因硬挂到相邻改动上,那类结论在复跑时通常站不住。
用同一任务复跑一次,确认失败可复现
在动补丁之前先复跑同一任务,把偶发的环境问题排除掉。复跑要和原次用同样的参数、同样的输入,只改输出目录:
# 以实际 CLI 和参数为准
run-bench `--task` task-014 `--out` runs/rerun-01
复跑前后各记一行,三条信息对齐再看结论:
| 批次 | 任务ID | 通过状态 | 错误信息 |
|---|---|---|---|
| 原次 | task-014 | failed | expected unit field, got null |
| 复跑 | task-014 | failed | expected unit field, got null |
状态和错误信息一致,说明失败可复现,可以进入补丁修复和针对性回归;不一致则先查运行环境,包括依赖版本、工作目录、超时设置、随机种子、缓存和外部服务可用性,把这些变量稳定下来再谈补丁。两种情况下都不要只用总分判断修没修好,仍以同一任务ID的状态变化为准。