EvalHarness/tests/error.md
sora 370953729b Fix perf stats (wrong import path), per-repeat checkpoints, README
- perf_stats aggregator lives in eval/, not model/: the import failed
  silently and EVERY perf column was empty (not just ttft). Now warns
  on stderr instead of swallowing.
- repeats > 1 get their own checkpoint key (:rep2, :rep3, ...): repeat 2
  previously restored repeat 1's predictions and finished instantly with
  identical scores. rep1 keeps the legacy key (existing checkpoints still
  resume).
- repeats summary: report the MEAN score and aggregate time/tokens over
  ALL runs (was: last run only).
- README: six-benchmark command as the primary example.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-11 13:38:04 +00:00

13 KiB
Raw Blame History

EvalHarness 对标 evalscope 全程踩坑记录

28 bench 双框架对比过程中发现的所有问题(我方 bug / es 方 bug / 口径差),按层归类。 每条含:现象 → 根因 → 修复 → 验证结果。


一.5、fix2 轮新增修复2026-09-02 晚prompt 逐字对齐 + 基建)

16.5. es bfcl 单轮全 0 = 依赖版本崩溃(已帮修,evalscope/.../bfcl/v3/utils.py - 现象es bfcl simple/multiple/parallel 等 10 个单轮类全部 0 分irrelevance 类却 0.9+ - 根因utils.py convert_format_language() import bfcl_eval.constants.enumsBFCL v4 新版枚举),环境装的是 bfcl_eval 2025.8.6.2旧版ast_checker 直接比较字符串 "Java"/"JavaScript"/"Python")→ ModuleNotFoundError → except 吞掉 → 全部判 ast_decoder:decoder_failed - 修复utils.py 两个 convert 函数改为版本兼容try 新版枚举fallback 旧版字符串,注意 JavaScript 大写 S - 验证es bfcl 20/类 0.1736 → 0.3563simple 0.55、live_simple 0.7、parallel 0.45-0.5 全部起来) - 遗留:我方 0.266 vs es 修复版 0.356 仍差 0.09——我方 bfcl_mock 的官方后端转换细节underscore_to_dot 等)待对齐

  1. 多段 pool spec range 替换 bugmodel/runner.py::_make_adapter
    • 现象多段逗号池105+138+140+143 共 20 口)全军覆没 ConnectError单段池正常curl 同口 200
    • 根因:re.sub(r'\{..\}', port, u, count=1) 每次只替换最前的 range → 20 个成员 URL 全带字面量 {8200..8203}httpx 连畸形 host 必败
    • 修复:按逗号拆段,每段独立 search+替换自己的 range
    • 验证20 成员展开正确4/4 请求成功;停滞的 mmlu_pro 恢复 1 samples/s
  2. 网络抖动三层自愈集群路由分钟级断通交替17:07-18:15 反复)
    • adapterhttpx.Timeout(connect=15, read=300, write=30, pool=15)——半开 TCP 快速失败
    • pool实例级 failover已有
    • runner.run_one6 次退避重试10/20/40/60/90s跨过断网窗口——gather 不再被单点异常炸掉
  3. prompt 逐字对齐 10 处(双侧渲染 diff 器验证,全部 IDENTICAL
    • mmlu 域匹配失效subject/category 键名不一致 → 全局前 5es 是每科目 5 范例)
    • mmlu_pro 三处header 应在范例前 / cot_content 变换单 ANSWER / 测试选项 A) x
    • bbh 测试题缺 Q:/A: Let's think 包装
    • aime 缺尾部 Remember to put your answer inside \boxed{}. + 前导 \n
    • gsm8k \boxed{}. 句号math fewshot 单换行分隔imo/hmmt/cmmlu/trivia 尾换行
    • lcb 缺 ### Format: 前缀 + starter_code 进代码块 + expert 头移到 system role
    • hle judge prompt 换 es 逐字版 + 三态契约移 system role
    • trivia list(str) 拆字符隐患
  4. es limit 是 per-subset 语义es mmlu limit=200 = 每科目 200 = 全量 14042同题跑法必须 per-subset kmmlu 4/科目=228、cmmlu 3、hle 25、imo 25、lb2 66/长度)
  5. gfc ckpt 版本漂移:数据镜像重物化后 metadata 变化 → key_for 失配 restored 0同口径 f1 直接从本次 report.samples 算更稳

一、我方框架 bug16 个,全部已修)

判分 / 聚合层

  1. few_shot_hook 从未挂载data/registry.py

    • 现象bbh 全程 0-shot无官方 3-shot CoT15 个 MCQ 子集接近 0 分
    • 根因:register_dataset 装饰器从不把模块级 <name>_few_shot 函数挂到 provider 上runner getattr(prov, 'few_shot_hook') 永远 None
    • 修复:装饰器里 factory.__globals__.get(f'{spec.name}_few_shot') 自动拾取(注意 __globals__ 是 dict 要用 .get 不是 getattr
    • 验证bbh 27子集×10 = 0.819 vs es 0.8185
  2. MCQ 抽取格式不匹配eval/recipes/qa.py

    • 现象bbh 全部 MCQ 子集判分全 miss
    • 根因:mcq_letter 返回裸字母 'A'target 是 '(A)'
    • 修复bbh recipe 按 target 形态格式化为 f'({val})'
  3. llm_judge 标签子串扫描eval/scorer.py

    • 现象hle 虚高 1.0、simple_qa 解析错乱
    • 根因:label in upper 全文子串匹配——judge 解释文本里 "CONSISTS" 命中 'C'、"ANSWER" 命中 'A'
    • 修复:三级解析——label_pattern 正则(如 GRADE:\s*([CI]))→ 尾行词边界匹配 → 全文词边界兜底
    • 验证hle 1.0→0.031es 0.050 同族、simple_qa 见下条
  4. dict 聚合器主指标被派生值均值覆盖eval/runner.py

    • 现象simple_qa 真值 0.035 被报成 0.403
    • 根因:simpleqa_official 返回 5 个派生指标 dict代码取 mean(全部值) = mean(0.035, 0.945, 0.02, 0.98, 0.036) = 0.403
    • 修复dict 展开时主指标取同名键 out[metric],无同名键才退化均值
    • 验证simple_qa 同题 0.050 vs es 0.0503
  5. judge adapter 拿不到 API key

    • 现象judge 全 401
    • 根因launcher 没 export OPENAI_API_KEYspec URL 里不含 key
    • 修复:启动脚本统一带 key

配对 / 选样层

  1. 双重 _apply_limits 依赖原地 shuffle 别名model/runner.py

    • 现象per-task 截断时判分配对错位mmlu 一度 0.275
    • 根因run_eval 和 generate_predictions 各调一次 _apply_limits旧实现靠「in-place shuffle 使两处列表别名同步」侥幸正确per-group 重写返回新列表后别名断裂 → samples 顺序 ≠ preds 顺序
    • 修复run_eval 用确定性重算得到与 generate_predictions 完全一致的 work 列表再 zip 判分
    • 验证mmlu 恢复 0.730+
  2. checkpoint key 不含 subset

    • 现象lb2 三个长度互相污染缓存
    • 修复ckpt 名加 :{subset} 后缀
  3. checkpoint key 不含 prompt / 生成参数

    • 现象:改 prompt 模板后重跑复用旧模板的预测hswag 渲染实验多次被坑humaneval 指令头实验同)
    • 教训:改任何影响 prompt 的东西必须删 ckpt(此后每次模板修改都显式 rm ckpt
  4. no_shuffle 没管到 per_task 分支

    • 现象:以为在跑「同题前 N」实际 per-group 内仍 Random(42).shuffle 取前 Nhswag 同题实验一度假对齐)
    • 修复per_task 分支尊重 shuffle=False(组内不洗直接前 N
  5. 选样语义与 es 不同model/runner.py

    • es每个 subset 独立 Random(42).shuffle 后取前 N
    • 我方旧实现:全局 shuffle 后按组截断 → 同池不同题
    • 修复per_task 时按组分组、组内独立 Random(42)、组序内取前 N

生成 / prompt 层

  1. /no_think 裸拼污染题面

    • 现象prompt 尾部最后一个选项后面跟 /no_think 字样
    • 根因Qwen3 软开关实现把标记 append 到最后一条 user 消息
    • 修复:普通请求改 chat_template_kwargs: {enable_thinking: false}服务端验证支持tools 请求保留软开关(模板 400 规避)
    • 验证gpqa 0.263 → 0.460es 0.480
  2. MCQ 选项渲染字符级差异strict/cot_letter 分支)

    • 现象hswag 同题下 A. 渲染 = 0.7825、A) 渲染 = 0.565——两个字符差 22 分no-think Qwen3 对格式极端敏感)
    • 修复:所有 MCQ 分支逐字对齐 esA) 选项 + one of A,B,C,Dmmlu_pro 例外es 用 A 空格分隔)
    • 验证wino 0.655 = es 0.655hswag 对齐中
  3. prompt 模板逐 bench 缺失/走样(最大一类,累计 12+ 处)

    • mmlu/cmmlu/mmlu_pro我方 strict「整个回复只能是 ANSWER」 vs es「Think step by step + last line ANSWER」→ 全部对齐mmlu 0.730→0.795es 0.800
    • few-shot 渲染es 范例=裸题+A)+ANSWER:,我方=Question:/A./Answer: → 对齐 + 按科目域匹配范例es biology 题配 biology 范例)
    • mmlu_proes 专属模板(Question:/Options:/A x + CoT 范例 + 按域 header→ 0.471→0.579es 0.629
    • gsm8kes 范例=题+Reasoning:全文+ANSWER: \boxed{} → runner 加 reasoning 元数据渲染分支
    • mathes 范例=Problem:/Solution: 裸答案 → 同上
    • aime×3es=「Solve the following math problem step by step. Put your answer inside \boxed{}.」指令前置,我方是题后 suffix → 加 aime_es
    • imo/hmmt26es=Problem:\n{题}\n\nPlease reason boxedProblem: 前缀),我方裸题 → 套 imo_esimo 0.138→0.19hmmt 验证中)
    • simple_qaes=Answer the question:\n\n{q}无 Answer 行契约,我方自加契约 → simple_qa_es
    • triviaes 开放卷(Content: {wiki证据列表} + es 模板),我方闭卷(镜像键名读错 wiki_contentwiki_context)→ 修键名+开模板0.555→0.700es 0.660
    • lb2es=<text> 包装 + CoT 契约,我方裸文档+strict → lb2_es
    • humanevales 指令头("Read the following function signature...")→ 加了头后 harness 仍用 input 拼程序导致指令进 main.py 全 0 → metadata 存原始 promptharness 用 metadata 版
    • LCB我方无代码契约模型输出 LaTeX 数学推导!)→ 官方 system+### Question:/### Answer:+```python 格式 → lcb_es
    • dropes=Think step by step + "Answer: [ANSWER]" → prompt_suffix范例=完整 Passage 式
  4. tau2 env 内部调用不传生成参数agent/envs/tau2_official.py

    • 现象agent 调用走 adapter 默认 4096 tokens/无温度
    • 修复:run_task(gen_kwargs=) 透传temp 0/16k16k+长对话会超 131072 上下文 → 8192
  5. tau2 reward 读不存在的字段

    • 根因:读 environment_reward/communication_rewardtau2 官方 reward_info 字段是 reward/db_check/... → 恒 0
    • 修复:取 rewards['reward']es 同款官方综合分)
  6. HF 下载同步阻塞事件循环

    • 现象18 任务并发时全卡死py-spy 见主线程 _hf_download
    • 修复:asyncio.to_thread 物化

基础设施

  • 根盘写满Errno 28两次HF 缓存迁移 /data2、清 modelscope 196G、truncate docker 巨型日志
  • pkill -f <pattern> 会误杀自己所在 shellcmdline 含 pattern→ 用 launcher 文件 + 短命令
  • bash 工具 timeout 会杀未及 detach 的后台任务 → nohup ... < /dev/null & disown + 立即返回
  • checkpoint 恢复打印 restored N (M to generate)N≠M 命中时警惕 key 失配(多次救场信号)

二、esevalscope侧问题代码级证据

  1. tau2 崩溃tau2_bench/generation.py:118 openai_chat_choices(include_reasoning=False) 丢弃 Qwen3 思考通道 → 空 content → 官方引擎 message.py:116 校验 raisetemp=0 确定性复现)
  2. gfc 误判(已帮修):general_fc_adapter.py is_call_tool = finish_reason=='tool_calls'vLLM/Qwen3 输出 tool_calls 时 finish_reason 常为 'stop' → FN 虚高。patchor bool(tool_calls)
  3. BCB 执行器空跑(已帮修):bigcodebench_adapter.py passed = status=='success'——沙箱命令完成≠测试通过198/200 空输出判对0.99 虚高。patchunittest 显式 runner + __BCB_RESULT__ PASS 标记 → 0.365(与我们 0.375、交叉判分三方一致)
  4. LCB 本地执行全体 -2use_sandbox=false 本机跑 codegen_metrics 全失败环境缺依赖docker sandbox 修复后 0.413 有效
  5. gfc 0.0 失败运行残骸:断连+空回复产物;重跑 0.456
  6. swe 无评测断点198/200 评完后报告步骤遇断连作废,重跑=整段 4h我们用日志聚合出真值 0.0

三、口径差(非 bug须同口径才可比

类别 内容
选样 双方 shuffle42 的 base 行序不同 → 不同题集。统一方案:双侧 shuffle=False 取原始前 N数据源行序一致已验证 400/400 同题)
金标集合 dropes=answer+validated_answers 合并(任一算对),我们镜像无该字段 → 严 ~0.065
指标定义 gfces 报 tool_call_f1我们 acc已重算同口径imojudge vs math_equal已统一 judge0.188 vs 0.198
数据构成 math 全量:我们随机 200易题占比高vs es 5 Level 均衡——对齐档 L×N 才可比
执行环境 bfcl/gfc/tau2es+Qwen3 的 agent 栈兼容性差LCB判定器不同官方 codegen_metrics vs 自写 runner
截断 lb2 文档中位 41.7 万字符天然超 131072——head+tail 截断双方同构(非 bug

四、方法论教训

  1. 分数不一致时先做同题实验(同 prompt 双跑 / 同题双侧——hswag 0.2 之谜三小时才定位到两个字符
  2. 交叉判分A 的输出 × B 的判分器)是分离「判分层差 vs 生成层差」的唯一利器
  3. 隔离变量实验:同题×同 prompt×只换渲染 → 定位 A. vs A)
  4. no-think 模型对 prompt 字符级格式极端敏感22 分级别的摆动)
  5. ckpt key 必须覆盖 prompt 语义,否则改模板=白改