harness-eval:評估 AI 開發環境設計品質的框架
Back to Projects
ai-workflowevaluationclaude-codeharnessdeveloper-tools

harness-eval:評估 AI 開發環境設計品質的框架

分不清失敗是模型的極限還是環境的問題?這個工具評估 AI 開發環境的設計本身,而不是單次結果。

harness-eval:評估 AI 開發環境設計品質的框架

用 AI 寫程式的人,會不知不覺為它搭起一整套工作環境:規則文件、自動檢查、任務流程、狀態檔案。每個元件加進來的當下都有理由,都在堵一個「AI 自己做不到」的缺口。但這套環境只進不出。模型隔一陣子就升級,缺口悄悄消失,補丁卻留在原地繼續收稅。直到某天你覺得 AI 變笨了,卻分不清那是模型的極限,還是你親手搭的環境在拖累它。


單次成敗回答不了設計問題

為什麼分不清?因為你手上唯一的訊號,就是單次任務的成敗,而 AI 的輸出本來就有隨機性:跑成功一次不代表環境設計得好,失敗一次也不代表設計得爛。拿單次結果去調環境,跟擲一次硬幣就判斷硬幣公不公平,是同一回事。

最直覺的解法,就是把規則越寫越詳細。我試過。結果環境更肥,常駐載入的東西更多,AI 反而更常忽略規則。更麻煩的是,寫 code 至少有 lint 和 test 把關;為 AI 搭的環境什麼都沒有,好壞全憑體感。而體感這東西沒有參照系,你說自己的環境「還行」,是相對什麼的還行?


定位:評設計品質而非單次結果

缺的那個工具,我把它做成了 harness-eval。這套圍繞 AI 搭起來的工作環境,行業裡叫 harness;harness-eval 對它做的事像健康檢查:不看你今天有沒有生病,看你的生活習慣撐不撐得起長期的健康。換成工程語言,它評的是「這個設計有沒有能力持續跑好」。至於「這次任務跑通了嗎」,上一節說過,那是擲硬幣。

它是用 Claude Code 的擴充形式發佈的,這種擴充叫 skill,你可以把它理解成一份 AI 讀了就照做的作業程序書。用起來也簡單,在專案裡下一個指令,它讀完你的環境,吐一張附改善建議的成績單給你。


評估引擎:為什麼沒有一行程式碼

要讓一份作業程序書變成評估工具,第一個要回答的問題是引擎,也就是判斷誰來執行。這種評估躲不開語義:規則文件裡宣告的事,和自動檢查腳本 (hook) 實際攔下的事,是不是同一件?字串比對和語法分析都答不了這種問題,只有讀得懂自然語言的 LLM 答得了。所以整個工具就是一份評估框架說明書,評估引擎就是執行它的那個 LLM。我只維護框架,不維護程式碼。

這個選擇丟掉的東西不少。最明顯的是確定性,同一個環境評兩次,分數可能不同;框架自身也沒辦法拿單元測試驗證,想在 CI 自動跑分更是免談。我的對策是把每條判準寫成「出現 X 給 A,出現 Y 給 C,出現 Z 給 F」這種顯式映射句,用判準的密度去壓縮引擎自由發揮的空間。壓不壓得住?收尾會誠實交代。


評估流程:從指令到成績單

引擎定了,再看一個指令進來,到成績單出去,中間經過哪幾站:

 使用者指令 (指定要評估的路徑)
      |
      v
 [界定範圍] ---- 只掃目標系統, 預設不掃全域設定
      |
      v
 [盤點元件] ---- 找出規則檔 / hook / 狀態檔, 記錄載入時機與大小
      |
      +---------------------------+
      v                           v
 [流程模擬]                 [假設壓力測試]
  沿開發生命週期走一遍         逐元件檢驗前提是否過期
      |                           |
      | 發現直接倒灌進評分        | 產出 ✓/⚠/✗ 清單
      +---------------------------+
      |
      v
 [六維度評分] ---- 每個維度一張準則表, 給 A 到 F
      |
      v
 [成績單與建議] ---- 加權總分 + 逐維度明細 + 有上限的建議清單

圖上第一站「界定範圍」,藏了一個很容易被忽略的決定:預設不掃使用者的全域設定 (~/.claude/)。因為一掃下去,個人的全域規則會和專案的 harness 混成一鍋,常駐 token 統計被灌水,兩套系統攪在一起評。代價是沒辦法一次評完完整環境,換到的是單一系統評分的乾淨度。


流程模擬:不跑 code 走一遍開發生命週期

沿著圖往下走,盤點完元件,框架不急著打分,先做兩道前置分析。第一道是流程模擬:不執行任何 code,但沿著一次開發的完整生命週期(啟動、開發、收尾、驗證、壓縮 context)走一遍。每個階段觸發了什麼,context 變成什麼狀態,大約吃掉多少 token,全部填成一條可審計的狀態轉移鏈。這一步的用意,是逼評估的人把「這系統好不好用」這種印象分,拆成一段一段指得出來的事實;走的過程中發現什麼問題,有明確的倒灌規則,直接對應到後面哪個維度該降級。


假設壓力測試:逐元件檢驗存在理由

第二道前置分析處理的是時間。

harness 裡的每個元件,都編碼了一個「模型自己做不到」的假設。假設過期,元件就從輔助變成純消耗。

所以框架要求你把每個元件的存在理由,改寫成一句可證偽的假設「假設 AI 做不到 X」,再對照當前模型,看看還成不成立。我叫它假設壓力測試,輸出長這樣:

假設壓力測試:
  ✓ {完成度守門 hook}: 假設 AI 會跳過驗證直接標記完成。
    成立: 沒有硬性關卡時, 它真的會跳過
  ⚠ {技術棧偵測 hook}: 假設 AI 不會主動掃描依賴清單。
    部分成立: 會讀, 但不一定主動掃
  ✗ {元件 X}: 假設寫在這裡。已不成立: 模型現在自己做得到。
    建議移除

三態符號的用意,是把「這個 hook 感覺還有用」這種無法反駁的話,強制改寫成能被推翻的形式。整個框架裡,正面處理「模型會升級,今天成立的假設明天可能不成立」的設計就這一個,所以它被拉出來獨立成一道前置步驟,而且產出清單,不是分數。分數容易被理解成評一次就永久有效;清單配上「模型升級後重跑」的觸發條件,才扛得住「這是持續成本」的語意。代價也很明顯,它跟後面六維度分數之間只有敘述性的銜接,不像流程模擬有結構化的倒灌路徑。兩道前置步驟的完整度不對稱,這塊我到現在還不太滿意。


評分模型:50 條準則與一套偏心的權重

評分本體吃的,就是這兩道前置分析餵進來的材料。框架把「好的 harness」拆成六個維度:穩健度、持久力、遵守度、context 效率、系統消耗、協作品質,合計 50 條準則。50 條聽起來很多,真正要緊的是粒度:每條準則的判準都寫成顯式映射句,這是零程式碼設計壓制非確定性的主要手段。整份文件的寫法也很統一,表格給分級規則,散文給評估方法;難判斷的準則才展開方法小節,簡單的就不佔篇幅。

準則裡我自己最滿意的一段,是 context 效率維度對「多餘的 context」給出的可操作定義。「這個 harness 話太多」是最常見也最模糊的抱怨,框架把它變成一條追蹤鏈加四條分類規則:

誰產生這個資訊? -> 誰修改它? -> 誰需要它? -> 誰負責遞送?

1. 產生者 = 消費者       -> 中間的遞送者是多餘的
2. 已經在 context 裡     -> 重複注入
3. A 的存在必然推得出 B  -> 再告知 B 是多餘的
4. AI 自己無從得知       -> 才有價值

第一條規則附了一個反例,值得單獨拿出來講:AI 自己改了規劃文件,hook 再把文件摘要注回給 AI。你看,AI 既是這份資訊的產生者又是消費者,中間那個 hook 就是純粹的多餘遞送者。這種好心幫倒忙的元件在真實 harness 裡非常常見,有了分類規則才抓得出來。

遵守度維度玩的是同一招。先承認純文字規則永遠不會被完全遵守,再給出各種強制機制的期望遵守率,權限黑名單和硬性攔截接近全遵守,純說明文字只有四到七成。有了這張落差表,「加權遵守率」的計算才有可代入的係數,而不是憑「我有寫規則」自我感覺良好。

評完六個維度,總分不是等權平均:

總分 = 加權平均:
  穩健度        x 2     系統壞了, 其他都不重要
  持久力        x 1.5   決定一個 session 能有效工作多久
  遵守度        x 1.5   決定產出的工作品質
  context 效率  x 1
  系統消耗      x 1
  協作品質      x 1

為什麼不等權?因為等權會讓「規則寫得漂亮但系統會整組壞掉」的 harness,拿到和穩健系統差不多的總分。所以偏心是刻意的,權重本身就是價值判斷。當然它也有暗面,高權重維度會系統性蓋掉低權重維度的短板:一個 context 效率墊底但穩健度和遵守度都拿 A 的系統,總分仍可能相當好看。所以成績單硬性規定要附逐維度明細,只看總分等於誤讀。

分數還需要參照系。框架內建一張典型系統對照表,從什麼都不設定的裸跑,到規則堆好堆滿的過度工程,每一型跨六個維度都有預期分數,你的 B 才知道是相對什麼的 B。有意思的是,這張表的形狀本身藏著一個非線性結論:元件堆最滿的 harness,穩健度反而比只掛幾個 hook 的系統差,原因很直觀,元件越多,單點故障面越大。順著這個結論還能撿到一條經驗法則:系統消耗的分數比遵守度還差,通常就是過度工程了。

成績單最後的建議清單上限 5 條,按固定優先序排。上限存在的理由很簡單:修不完的清單等於沒有清單。


已知限制:抓文件漂移的工具,自己也在漂移

成績單設計得再周全,有一關我自己沒過。寫這篇解讀前重新盤點 repo,發現兩件事。第一件,README 後來補寫的準則描述,有 5 條從來沒進到實際被安裝執行的主檔 SKILL.md,等於對外宣稱的準則清單,和真正會跑的評估邏輯已經對不上。第二件,repo 裡還躺著一份舊版英文 skill 檔,任何安裝指令都不再指向它,內容也明顯落後主檔。諷刺的是,框架自己就有準則專門檢查「文件宣稱的和實際執行的是不是同一件事」,也有準則檢查「被引用的元件還活不活著」。一個以抓文件漂移為賣點的工具,自己的文件在漂移。

而且漂移根本不需要時間。這個 repo 的十幾次開發提交,全部發生在同一天,之後四個月只有一次無關的維護提交;漂移就發生在那一天之內,同一份事實改了 README 忘了改主檔,一次就夠。還有一個更根本的洞:框架文件裡誠實列了四條自身限制,但沒有一條點名最要命的那個,評分依賴執行當下的 LLM 判斷,同一個系統評兩次可能給出不同的字母分,而 repo 裡目前沒有任何跨系統或跨次數的評分穩定性驗證記錄。

這兩個洞給我的教訓,其實超出這個專案。我原本把漂移當紀律問題,覺得多用心就防得住;這次盤點完才確定,它是架構問題。同一份事實只要存在於兩個地方,分岔遲早發生,跟你用不用心無關。修法也只有一條,讓事實只存在一份。至於這個評估框架,我現在最推薦的用法,是先拿它照自己。我照出來的東西,就寫在上面。

Joey Chen

Joey Chen

Build things that are interesting. All made by AI.

AIWeb3