先釐清「6/8」從哪裡來
README 裡有一行數字:純 embedding、k=10 的成績是 6/8。今天跑完重現,凍結語料
sha 09649c24、參數全同,結果是 4/8——而且與既有的凍結基準
frozen_full_emb_k10.json 逐題逐位元組一致,是完全確定性的重現。
6/8 幾乎確定是在語料凍結之前跑的。評測語料每次重建,改寫題的 gold chunk
排名就會漂移——這正是 README G 段標記的「活語料陷阱」。commit 12df03a
的訊息本身也標記這臂 REJECTED。已在表格後加 † 更正註,標清凍結真值 4/8。
八題拆開看,三道改寫題各自卡在哪一關
長上下文管線分三關:先檢索(embedding 取 top-10)、再切分成多段餵給模型、 最後抽取答案。三道改寫題失敗的關卡不同:
l2_06、l2_07:檢索失明。 06 的 gold chunk 索引是 9,top-10 回傳 137、20、21、8、7、48、11、52、39、13—— 9 不在裡面。07 的 gold 是 82,top-10 是 5、33、16、31、42、1、21、2、37、45—— 82 也不在。gold 根本沒進 context,後面的抽取步驟沒有機會。這是 embedding 對語意改寫的結構性限制:問題換個說法,向量空間的距離就變了。
l2_08:抽取失敗,不是檢索。
08 的 gold chunk 136 被 embedding 排在第 1 位,covered_all=True,
context 裡確實有答案。但模型對改寫問法擅自婉拒,沒有抽出 owner。
這和 l2_04 是同一種病:map_one_chunk 的 prompt 對改寫問法脆弱。
k 再大、換再好的 retriever,都治不了 08 這類失敗。
為什麼這個區分重要
「三道改寫題全滅、BM25 與 embedding 都救不了」這個描述會讓人去研究換 retriever。 但 08 的 retriever 已經把 gold 排第 1,問題在 prompt 層,不在檢索層。 如果把修法集中在換 retriever,08 不會動;如果只修 prompt,06/07 也不會動。 兩個問題需要兩支不同的修法,混為一談就是浪費。
真正純檢索無解的只剩 06、07,對應的方向是提高 k 預算或換 retriever(BM25 hybrid、
rerank)。08 與 l2_04 共用同一個抽取脆弱根因,對應的方向是修 map_one_chunk
的 prompt 或換小模型。
順帶踩到的兩個環境坑
第一個:系統 python3 沒有 transformers,直接 python3 run_l2.py
秒掛 ModuleNotFoundError。必須用 repo 下的 .venv/bin/python
(transformers 5.12.1 裝在那裡)。PyTorch not found 是無害警告,可以忽略。
第二個:用 nohup … & 包長跑 job,harness 會收到 launcher 的 exit 0
誤判為「任務完成」,實際 python 在追蹤外獨立跑,跑完不通知。
正確做法是直接把 .venv/bin/python … 交給 harness 的 run_in_background,
跑完才會通知。
關鍵教訓
「全滅」不等於「同一種病」:相同的表面結果可能有不同的失敗層。先把管線每一關的實際輸出記錄下來,再診斷,別憑分數猜根因。
活語料跑出的基準不能當凍結真值:改寫題的 gold chunk 排名在語料重建時會漂移,README 裡的數字要標清楚是活語料還是凍結語料跑的。
抽取失敗比檢索失敗更隱蔽:retriever 已把答案排第 1,但模型拒絕抽——這類失敗光看最終分數完全看不出來,要記錄 covered_all 與每步中間結果。
環境坑要寫進 reference:venv 路徑、nohup 的誤判行為,這類坑每次換環境都會再踩,寫進 memory reference 才算解決。
重現是校正文件的最快路:23 分鐘重跑,比反覆推論哪個數字對更快確認真值,順便更新了 README 的錯誤標記。