← 隨筆

Fable 5、Opus 4.8 與 Sonnet 4.6:如何在自己的程式碼上誠實比較 LLM

受控實驗:Fable 5、Opus 4.8 與 Sonnet 4.6 以同一提示審核真實程式碼庫。在自己的專案上誠實比較 LLM 的方法論。

7 分鐘閱讀
Telegram原文
Fable 5、Opus 4.8 與 Sonnet 4.6:如何在自己的程式碼上誠實比較 LLM

每當有新模型推出,發表公告回答的是「它在基準測試上好了多少」——卻不回答我唯一關心的問題:它會改變我工作中的什麼。我做了一個受控實驗:三個 Claude 模型—— Fable 5、 Opus 4.8 與 Sonnet 4.6 ——拿到逐字相同的任務,審核這個部落格的程式碼庫,各自在隔離的儲存庫副本中進行,並採用事先議定的評分標準。文章內容包括這套可在任何專案上重現的方法論、結果,以及另外單獨說明實驗如何兩度失敗、從中學到了什麼。

為什麼基準測試回答不了我的問題

公開基準測試有兩個問題,而且兩者都是根本性的。第一是資料污染:測試樣本滲入訓練集,模型部分「記得」答案,而不是真正解題。這不是邊緣的懷疑,而是一整個研究領域的主題: Xu 與共同作者(2024)的綜述 系統整理了基準測試污染的研究,而 EMNLP 2025 的綜述 記錄了產業界的回應——從靜態測試轉向動態生成的測試。

第二個問題更簡單:基準測試測的不是我的任務。我不需要一個最會解奧林匹亞題目的模型。我需要一個能在我的 Laravel 部落格裡找到真實 bug、不憑空捏造不存在的問題,並證明它的修復有效的模型。

由此得出一個簡單的想法:比較模型的最佳測試平台就是自己的專案。它的程式碼以這樣的組合不會出現在訓練集中,上面的任務正是我付錢要解決的,而結果我可以親手驗證,因為我熟悉這段程式碼。

實驗設計:一個提示,三個隔離世界

三個模型的任務逐字相同——只有分支名稱和結果資料夾不同。共四個階段:審核部落格的雙語文章系統,每項發現都要有證據,形式為 файл:строка 並附上程式碼引用;為三項主要發現選擇解決方案並描述取捨;實作一項修復並自我驗證;以俄文和英文撰寫結果筆記。這是完整的工程工作循環,而不是孤立的「問答」——這種做法也正是 Anthropic 所建議的:在真實產品的任務上評估代理,並採用啟動前議定的評分標準。

三條規則讓比較變得誠實:

隔離。 每個模型都在獨立的 git worktree 中工作——擁有自己的工作目錄副本和自己的分支。模型在物理上不可能看到彼此的結果,也不可能互相干擾。

在提示本身中防範幻覺。 任務的關鍵一句:「捏造的發現(不存在的程式碼、錯誤的行號)比沒有發現更糟」。沒有這個誘因,被要求找問題的模型傾向於無論如何都要「找到」問題。有了它——每項發現都必須通過人工檢查。

將提示中的線索排除在計分之外。 儲存庫裡有一個 CLAUDE.md,描述了專案已知的陷阱——例如在帶語言前綴的 URL 上會失效的資源相對路徑。三個模型都會讀這個檔案,所以這類發現是「免費的」:它們計入細心程度,但不計入深度。

評分標準:只評估能親手驗證的東西

啟動前我固定了六個維度、每項五分:審核準確度(依 файл:строка人工抽查發現)、深度(提示中沒有、但經確認的發現)、關於取捨的推理品質、程式碼與自我驗證的真實性、俄文與英文文本的品質、紀律(零次向人提問、零次違反限制)。原則和好的程式碼審查一樣:一個維度越少依賴品味、越多依賴可驗證的事實,就越值得信任。

第一次是如何全盤失敗的

第一次執行我做錯了——而這竟成了實驗中最可移植的部分。我在同一個儲存庫資料夾裡同時開了三個人互動工作階段。幾分鐘後,工作樹裡躺著無法歸屬的未提交修改:共用 checkout 意味著當一個工作階段執行 git checkout -b,三個工作階段的分支都會切換,它們的修改和提交也混在一起。其中一個工作階段還執行了 git stash ,把一切掃了進去——包括我自己與實驗無關的檔案。

「同一個資料夾裡的平行 AI 代理不是平行實驗。這是一場有三個作者的大衝突。」

– 讓我付出重跑代價的結論

两次会话的结果只能判定为不可用:即使它们运行到底,我也无法诚实地说我评估的是谁的修改。第二次运行——已经在隔离的 worktree 中——撞上了套餐限额:两个 agent 在启动时死亡,第三个卡住,却仍在界面上看起来「在工作」。诊断是由文件系统给出的,而不是状态指示器:二十分钟内它的工作副本里没有出现任何一个文件。这是第二个可迁移的教训:agent 的存活要按磁盘上的变化来检查。重启之后,三个模型在同等条件下都跑完了完整周期。

结果:模型在哪里相同,在哪里不同

最重要的结果是那件没有发生的事: 三个模型都没有出现幻觉。我手动检查了每个模型至少三项发现——所有引文和行号都精确到字符。对于审计类任务,这是信任的主要门槛,而三个模型都通过了。

接下来才是差异:

Fable 5 Opus 4.8 Sonnet 4.6
已确认的发现 11 5 9
非平凡的唯一发现 3 1 2
修复的自检 在临时数据库上的集成渲染、xmllint、对他人失败测试的归因 linter + 渲染;抓到了自己的 bug 只有 linter 和路由列表
Token / 时间 164k / 21 分钟 101k / 12 分钟 131k / 12 分钟
评分表总分(满分 30) 30 24 25,5

质性差异比分数更有信息量。 Opus 4.8 ——唯一一个没有注意到 sitemap 中损坏的标题 Content-Type 的模型(另外两个发现了它),并把它留在了自己的修复里;而且它的俄语文本里渗进了一个英文词——「и even 图片路径」。 Sonnet 4.6 做出了正确的修复,但它的自检是声明式的:用 linter 代替了实际运行。 Fable 5 恰恰在自检上脱颖而出:它发现 php 在我机器上是一个挂载到主目录的 docker 容器的包装器,于是把所有检查都重建为一次性容器,并在临时数据库上对自己的修复做了集成测试。「我做了」和「我证明了我做了」之间的差别,正是 agent 任务最具区分度的轴。

另一个有用的信号是收敛:三个模型都独立地把同一个 sitemap 问题列为最重要的发现。当独立的审计者在首要发现上趋于一致时,这是专家间一致性的一种廉价替代:这个问题几乎肯定是真实的。

由参与者担任裁判

评分表的评分由 Fable 5 执行——正是参与比较的同一个模型。这是一个方法论漏洞,必须直说:LLM 裁判会系统性地给自己的文本打高分,而且模型越能识别出自己的文本,这种倾向就越强——这一点在 Panickssery 等人发表于 NeurIPS 2024 的论文中已有展示。缓解这种偏差有两种方式,而我两种都用了:第一,尽可能把评分表从口味轴转向可验证的事实——行号准确性、修复完整性、渗入的外语词都不取决于裁判的偏好;第二,明确声明利益冲突,把有争议的轴交给另一个模型或人做交叉评估。我结论中的主观轴——文本质量、推理质量——应当带着这一修正来读。

诚实性限制

每个模型只跑一次,也就是 n=1:一两个分数的差异毫无意义,只有质性差距才值得信任——漏掉的 bug、自检的深度。实验测量的是三个模型在一个领域的一项任务上的表现;「Fable 5 整体上更好」并不能从中推出。还要记住成本:顶级模型消耗的 token 是最经济参与者的 1.6 倍,时间几乎翻倍,而 它的 token 单价 本身也更贵——对于常规任务,这是支持更简单模型的有力论据。

我为自己留下的东西

方法论归结为一份简短的检查清单,适用于任何项目和任何模型:

  • 测试任务是真实工作的完整周期,在自己的代码上,而不是合成的小题。
  • 所有人用同一个 prompt,通过独立的 worktree 隔离,结果放在独立分支。
  • 在 prompt 中明确写出幻觉的代价:编造的发现比没有发现更糟。
  • 所有人都能拿到的提示(文档、仓库中的笔记)不计入深度得分。
  • 评分表在运行前固定,并依据可验证的事实,而不是印象。
  • 发现的样本要手动检查;独立模型在首要发现上的一致是它们真实存在的信号。
  • 参与者担任裁判——已声明的利益冲突:有争议的轴交给交叉评估。
  • agent 的存活要按磁盘检查,而不是按界面上的指示器。

计划之外的额外收获:实验自己回本了。三次独立审计在博客中发现了真实问题——从缺少英文页面的 sitemap 到控制器中的死查询——两个现成的修复已经躺在分支里,等待合并到生产环境。在自己的代码上比较模型,与阅读基准测试不同,留下的不只是观点。

来源与参照